Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3826 lines
1.1 MiB
Plaintext
3826 lines
1.1 MiB
Plaintext
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ9N8Y2SEVH0CMFNK0', 'task', '06FB0TNSRWW7NX8R77SZ7QHTZG', 'import_economics.py: import_system_specialization() function + source stamp tracking', 'Implement import_system_specialization() in import_economics.py and wire it into the main import flow.
|
||
|
||
Function steps:
|
||
1. Read wiki/economics/specialization_vocabulary.toml -> validate FK against commodities table -> clear + repopulate specialization_vocabulary table.
|
||
2. Read wiki/economics/system_specialization.toml -> for each authored system:
|
||
- UPSERT system_economy.economic_specialization and system_economy.cultural_specialization
|
||
- UPSERT system_factions.dominant_faction ONLY when the field is present in the TOML stanza (systems without an entry are unaffected; the system_factions row must already exist)
|
||
3. Run hard validations (see CI ticket) — abort transaction on failure.
|
||
4. Print coverage report and soft warnings.
|
||
5. Call within the main import transaction (same pattern as other import steps).
|
||
|
||
Source stamp tracking:
|
||
- Add wiki/economics/system_specialization.toml and wiki/economics/specialization_vocabulary.toml to IMPORT_ECONOMICS_SOURCES list.
|
||
- Mirror both additions in tooling/check-systems-db-stamp GENERATOR_SOURCES[''import_economics''] dict (keep in sync or the pre-push hook will reject the DB).
|
||
|
||
Note: dominant_faction column already exists on system_factions. The import step populates it for named systems; it does NOT add a new column or migrate the schema.', 'done', 'high', NULL, 'server', 'D-237', '2026-05-31 16:13:12', '2026-06-01 07:09:18', NULL, '4150edf5a9ca8bb1ee3e811cc362693a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZAPRWZRXSTVHTCXX0', 'task', '06FB0TNSRWW7NX8R77SZ7QHTZG', 'CI guardrails: specialization vocabulary validation + cross-field checks + coverage report', 'Implement in import_economics.py (called from import_system_specialization()).
|
||
|
||
HARD ERRORS (build aborts):
|
||
V-SES-01: economic_specialization must be in specialization_vocabulary.specialization_id when present.
|
||
V-SES-02: inhabited systems (population > 0) must resolve to a non-null economic value (authored or fallback) — fail build if derivation returns null.
|
||
V-SES-03: production_ubiquity_override in specialization_vocabulary must be >= catalog default concentration (ubiquitous < common/regional < concentrated < monopolistic).
|
||
V-SES-04: cultural_specialization must be in the combined activity+heritage vocabulary list when present.
|
||
V-SES-05: dominant_faction must be in the 8-value vocabulary (concord_assembly|compact|compact_sympathetic|syndic_dominant|veil_institute|independent|disputed|mixed) when present.
|
||
V-FAC-01: every inhabited NAMED system (has a GTTR entry or wiki page) MUST have an authored dominant_faction value — hard error.
|
||
V-SES-06: specialization_vocabulary.commodity_id must exist in commodities(commodity_id) — FK integrity.
|
||
|
||
SOFT WARNINGS (build succeeds, prints):
|
||
W-SES-01: MonopolySource systems list for human review (D-177 constraints apply).
|
||
W-SES-02: >25% of inhabited systems resolve to same vocabulary value.
|
||
W-SES-03: economic_base_primary prose does not mention commodity/sector from vocabulary description.
|
||
W-SES-08: estate_farming + population > 5_000_000 (probably breadbasket).
|
||
W-FAC-01: compact + tractus_primary currency zone (D-172 violation).
|
||
W-FAC-02: compact + MonopolySource extraction excluding marble_monopoly/terroir_* (Compact self-sufficiency doctrine).
|
||
W-FAC-03: syndic_dominant + no Tier-1 corp HQ in corp_presence (ungrounded pin).
|
||
W-FAC-04: compact_sympathetic + mark_primary currency (may be full Compact member).
|
||
W-FAC-05: independent + sole Tier-1 monopolist corp HQ (Calloway Reach pattern — flag for confirm).
|
||
W-FAC-06: compact + cultural_specialization missing compact_cooperative reference.
|
||
W-FAC-07: syndic_dominant inner-corridor + cultural_specialization = corridor default (institutional culture expected).
|
||
|
||
COVERAGE REPORT (always printed):
|
||
economic: NNN/MMM inhabited systems authored (NN%); NNN on fallback
|
||
cultural: NNN/MMM named systems authored (NN%); NNN on corridor default
|
||
faction: NNN/MMM named systems authored (NN%); NNN on derivation
|
||
BulkClass distribution: BulkSolid=NN|BulkLiquid=NN|Perishable=NN|PrecisionDense=NN|NonPhysical=NN
|
||
ProductionUbiquity distribution: Ubiquitous=NN|Common=NN|Specialist=NN|MonopolySource=NN
|
||
MonopolySource systems [D-177 REVIEW REQUIRED]: [list]
|
||
D-172 faction/currency mismatches [REVIEW]: [list]
|
||
Compact monoeconomy flags [REVIEW]: [list]', 'done', 'medium', NULL, 'server', 'D-237', '2026-05-31 16:13:49', '2026-06-01 10:44:58', NULL, 'a9f6b5f93a9155e496d417df90a2d810', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXS53J55C78CPDR6H4', 'story', '06FB0TNSRWW7NX8R77SZ7QHTZG', 'Heritage rebalancing — convert overrepresented southern-African systems to Arab/Persian/Turkic (DLC/content)', 'The #1016 heritage taxonomy (docs/workshops/system-economic-specialization/heritage-taxonomy-draft.md) surfaced a real worldbuilding imbalance: ~25 of ~300 named systems read southern-African, with afrikaans alone on 15 systems — more than french+italian+russian+arab combined. arab=2, persian=0, turkic=0. Artifact of the original name-balancing overcorrecting in one direction.
|
||
|
||
FIX (out of scope for #1016): rewrite a subset of afrikaans/zulu systems into arab/persian/turkic heritage. This is a FULL per-system content rewrite — index.md (name, infobox-adjacent prose) AND gttr.md (founding story, naming, narrative) — not a TOML value flip. The canonical taxonomy already reserves arab/persian/turkic values as write targets.
|
||
|
||
Scope when picked up: pick N southern-African systems (candidates: the thinner afrikaans deep-frontier pocket), rewrite name+index+gttr for each into the target heritage, update system_specialization.toml cultural_specialization, regen. Likely DLC-tier content work. Tracked low-priority.', 'backlog', 'low', NULL, 'server', 'D-237', '2026-06-01 14:48:41', '2026-06-01 14:48:41', NULL, '25228b2888ab8815f49090f1ddda96c4', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYYR0QJC12EMA0SV1W', 'task', NULL, 'Add East-African-interior heritage token to cultural_specialization taxonomy', 'The #1016 cultural pass found two systems founded by East-African-INTERIOR peoples that the canonical 47-value heritage taxonomy has no token for, so they currently borrow ''swahili'' (a coastal value) as the nearest fit (documented inline in wiki/economics/system_specialization.toml):
|
||
|
||
- GJ 667B Kampala Gate — Baganda/Ugandan (Great Lakes interior)
|
||
- GJ 1292 Moyale — Kenyan/Ethiopian (Borana/Oromo, Horn)
|
||
|
||
(Mwangaza GJ 693 is genuinely coastal Swahili — correct, leave it.)
|
||
|
||
SCOPE: add an appropriate heritage value (or values) to the canonical taxonomy at the nationality/people granularity the taxonomy uses — candidates: a Great Lakes / interior East African token and/or a Horn-of-Africa token. Update:
|
||
1. docs/workshops/system-economic-specialization/heritage-taxonomy-draft.md (canon list + count)
|
||
2. _CULTURAL_HERITAGE in tooling/economy-db/import_economics.py
|
||
3. repin GJ 667B and GJ 1292 in system_specialization.toml to the new value(s)
|
||
4. regen-db + verify (V-SES-04) + commit
|
||
|
||
Surfaced by the PR #147 (#1016) review (Paula HIGH / Miri). Low priority — current ''swahili'' approximation is documented, not silently wrong.', 'backlog', 'low', NULL, 'server', 'D-237', '2026-06-03 08:27:09', '2026-06-03 08:27:09', NULL, 'f7f3f9d3cae5022a856a7dfa2e0b064e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWP79J2MJWEPGR4188', 'story', '06FB0TNSRWW7NX8R77SZ7QHTZG', 'Content pass: ~300-system economic + cultural_specialization + faction authored pins', 'Author the three specialization fields for all GTTR-named systems (~300 total). Hero seeds are in wiki/economics/system_specialization.toml (T3); this pass extends to the full set.
|
||
|
||
AUTHORING SCOPE:
|
||
economic_specialization: ~80-100 GTTR-named systems. All inhabited systems fall back to heuristic if unauthed.
|
||
cultural_specialization: ~60-100 divergent-heritage systems. Criterion: GTTR names a founding community AND that community''s heritage diverges from the corridor baseline. Unnamed systems fall to corridor default.
|
||
dominant_faction: ALL inhabited named systems (GTTR entry or wiki page) MUST have an authored value (V-FAC-01 hard error). ~40-60 entries; remainder on hop/currency heuristic.
|
||
|
||
VOCABULARY GROUND TRUTH: wiki/economics/specialization_vocabulary.toml (27 values). Miri''s Round 3 table has pre-merge labels for some entries:
|
||
marine_farming -> terroir_organics
|
||
military_station -> military_industrial
|
||
specialist_manufacturing -> precision_tech
|
||
Use TOML labels, not the pre-merge Round 3 table labels.
|
||
|
||
AUTHORING METHOD (Miri):
|
||
Heritage triage (4-step): (1) system name language — does it diverge from corridor? (2) institution names in non-corridor language family? (3) GTTR founding community mention? (4) if none apply, corridor handles it (no pin).
|
||
Heritage values take precedence over activity values when both apply.
|
||
|
||
CULTURAL_SPECIALIZATION vocabulary (single field, combined):
|
||
Activity/character: scholarly, artistic, institutional, commercial, agrarian, industrial_heritage, medical_elite, ecological, military, financial_technocratic, cosmopolitan, compact_cooperative (12 values).
|
||
Heritage: scottish, french_provencal, vietnamese, afrikaans_cape, zulu, chinese, italian_northern, tagalog, norse_compact + more discovered during pass (expandable).
|
||
|
||
ASSIGNMENTS:
|
||
Miri: economic_specialization pins + cultural_specialization pins (GTTR-truth lens; 4-step heritage triage).
|
||
Paula: dominant_faction pins + cultural_register input via three mechanisms: institutional erasure (Sirius, Groombridge, Bastion, Renaissance, Prometheus), deepened corridor (Ostmark, Nyrheim, Calloway Reach, Braemar), heritage preservation (Confluent, Dai Lo, Dagat). Faction list: paula-round3.md §1.
|
||
Burnelli: economic credibility review; fallback algorithm validation; distribution balance check (W-SES-02). Flag vocabulary values unclaimed after pass (candidates for retirement: rare_mineral_extraction, precision_tech, legal_archive).
|
||
|
||
CONFLICT: Vuurkloof dominant_faction — Miri=independent, Paula=concord_assembly. Resolve against workshop-outcomes.md before committing.', 'done', 'medium', NULL, 'server', 'D-237', '2026-05-31 16:14:10', '2026-06-03 08:27:51', NULL, '8a529ed1b0783ce6c55d765f84518276', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRX74TSW78W28XX6FA0', 'task', '06FB0TNSRWW7NX8R77SZ7QHTZG', 'atlas_body_trait_bias hero-pin sub-pass (~30-40 bodies) + Groombridge GSH landmark', 'Author per-body atlas_body_trait_bias entries for ~30-40 GTTR-named hero bodies per D-232 design.
|
||
|
||
Pin types:
|
||
pin: mandatory template; counts toward K; body WILL use this template.
|
||
boost: up to 3x weight increase (non-mandatory).
|
||
suppress: >= 0.33x (never 0 — preserves second-playthrough surprise).
|
||
|
||
RELATIONSHIP TO T7: system-level cultural_specialization (T7) sets the baseline for ALL bodies in a system. Per-body atlas_body_trait_bias pins override for specific bodies. Both are needed — without the system baseline, hero-pinned bodies are surrounded by wrong-character context. T7 must be underway before this pass is useful.
|
||
|
||
GROOMBRIDGE GSH LANDMARK (folded in from D-222/D-232 design):
|
||
The Groombridge Settling House is the Reach''s singular clearing house — a MonopolySource-class institution within a Specialist financial district.
|
||
Mechanism: (1) D-222 multi-block reservation — a reserved block in the financial district for a single named institution, placed at generation time; (2) D-232 atlas_body_trait_bias pin — forces the clearing_house_landmark template onto that reserved block.
|
||
Implementation check REQUIRED before authoring: confirm whether the D-222 multi-block reservation mechanism supports named landmark reservations in the Phase 4 generator. If not yet implemented, raise a sub-task for the reservation slot mechanism before authoring the content pin.
|
||
Content: add Groombridge body entry with clearing_house_landmark pin.
|
||
|
||
BEFORE STARTING: confirm atlas_body_trait_bias import mechanism with Burnelli (wiki TOML -> import vs. direct entry in an existing TOML). The D-232 record (decisions/architecture.md §D-232) specifies storage as a sparse atlas_body_trait_bias table; confirm the authoring pipeline for that table.
|
||
|
||
Authoring: Miri (lore truth) + Araminta (template catalog knowledge).
|
||
|
||
--- Refinement 2026-06-03 (feasibility gates checked, #1016 done): BLOCKED. Both BEFORE-STARTING gates fail — the infra does not exist yet. (1) atlas_body_trait_bias table + trait_templates catalog: absent from systems-schema.sql, systems.db, and all importer/server code → blocked on #993 (tables+import) and #1005 (catalog content). (2) D-232 architecture-flavor template-draw consumer: not present in server/src/atlas/skeleton_gen.rs → blocked on #977 (pipeline) / #983 (CityGenerationContext trait_selection). (3) D-222 named-landmark reservation: skeleton_gen ReservationFunction has only Park/Terminal (block.landmark is a stub None); named-institution reservation for the Groombridge GSH is NOT implemented → blocked on #957 (quarter-skeleton reservations); confirm #957 scope explicitly covers a named-landmark reservation slot or split a sub-task. This is a CONTENT pass (~30-40 pins + GSH) that requires the above mechanisms first; do not author pins into a non-existent table. Deps wired: 993, 1005, 977, 957.
|
||
|
||
--- From PR #148 review (Tyre): when authoring hero pins, validate that the number of pin rows per body stays within that body''s K budget (Full=5/Moderate=3/Minimal=1). complexity_tier is not available in import_economics, so this check belongs either in the draw consumer (#977) or a generator-side validation — add to acceptance.', 'backlog', 'medium', NULL, 'server', 'D-237', '2026-05-31 16:14:27', '2026-06-03 08:31:47', NULL, 'bc84581ee321b1f61044a76f2e13810d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYZ664SDEJNV3Q7JBC', 'task', '06FB0TNSRWMZBFV1V6F79VW8S4', 'trait_templates + atlas_body_trait_bias tables + catalog bake', 'Table atlas_body_culture(body_id, flavor_index, tag, allow_tags, block_tags, weight, trauma_decay_rate); baked at import (same slot as atlas_city_names). Generator-facing artifact, invariant to the Q-107 source-location decision.
|
||
|
||
Round 3: the tables are trait_templates (shared catalog) + atlas_body_trait_bias (sparse hero bodies). atlas_body_culture + atlas_body_culture_era are RETIRED (not built).', 'done', 'high', NULL, 'server', 'D-232', '2026-05-25 19:11:43', '2026-06-03 09:51:37', NULL, '08b090195bc49eed83f7c60cf279d1bc', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZVKJDW6CG44B92DMC', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Author the core trait-template catalog (~35 templates — cultural entries + visual bundles)', 'The explicit content-authoring deliverable for the D-232 trait-template catalog, split out of 977 so it is not lost between the mechanism tasks. Author the core ~35 templates (40-45 target): each entry = Miri''s cultural layer (tag, label, cultural_description, two-tier eligibility [hard gates bulk_class/prosperity/ubiquity + weight mods role/faction/age/corridor/morphology], zone_affinity, era_scope) + Araminta''s matching visual_bundle (4-axis WallMaterial/RoofForm/FacadeRhythm/StreetSurface allow-block, color register, fallback parents). Must cover, per corridor, a BASELINE pool + a HERITAGE sub-pool, plus the shared cross-corridor (foreign-import) pool. CI guardrails must pass: >=5 templates eligible per economic class, no template >60pct pool weight. Core hand-curated first; the bounded Gemma corpus-distillation pass (992) proposes additions under human review. BLOCKING: the flavor system produces no real output until this exists. Owners: Miri (cultural/eligibility) + Araminta (visual bundles).
|
||
|
||
Round-3 refinement (2026-05-26): the 992 (Gemma methodology) hard-block is REMOVED -- the core ~25-30 templates are hand-authored (Miri cultural + Araminta visual bundles) and do not need the Gemma pass. 992 becomes a follow-on EXTENSION (corpus-distillation to 40-45), gated by the core existing, not a prerequisite. Still blocked by 993 (schema) + 995 (ObjectTag vocab). Per-corridor target: baseline 4-5 + heritage 2-3 each; shared foreign pool 5-8; clear the >=5-eligible-per-economic-class CI guardrail. Color-register vocab: Araminta defines in a TOML preamble.
|
||
|
||
Authoring approach (2026-05-26): order west_reach -> north_reach -> east_reach -> south_reach (baseline 4-5 + heritage 2-3 each) -> shared foreign pool last (needs all corridors first) -> core sector. TOML entry = tag, label, cultural_description, hard-gates (min/max prosperity bps, bulk_class, ubiquity), zone_affinity {DistrictType: bps}, era_scope, base_weight, corridor_weights, morphology_weights, visual_bundle (wall/roof/facade/street allow-block + color_register + fallback_chain), pool_type (baseline|heritage|foreign), corridor. economic_role weight-mod keys = the canonical 10 (D-194); dominant_faction = PoliticalArchetype. Color-register vocab defined in a TOML preamble by Araminta.', 'done', 'high', NULL, 'server', 'D-232', '2026-05-26 17:33:34', '2026-06-03 09:51:37', NULL, '45b0a51d4c990279f32bb0723176a794', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWN78KNTHMER9HN7QR', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Layer 2 — wire economic read-set + prosperity_baseline into generation context', 'Wire the 6-field minimum economic read set (D-199) and prosperity_baseline (D-197) into the city-generation context (D-200). Economic sim is independent of spatial layers (D-198) — this is the interface that feeds population/role/prosperity into placement.
|
||
|
||
Refinement (round 2, 2026-05-25): Also wire the CityGenerationContext extension (D-199 amend: +morphology_zone, +trait_selection, +dominant_bulk_class, +dominant_production_ubiquity), the BulkClass/ProductionUbiquity enums, the D-184 bulk_class value backfill, and the dominant-commodity lookup (D-233). Economic strength is authored-fixed; locations seed-varied (D-167/D-223). Blocked by 980 (data cleanup).
|
||
|
||
Refinement (2026-05-26): READY behind 1006 (types) + 980 (data). bulk_class = the 8->5 projection; dominant commodity DERIVED from the highest-output location-bound production chain (D-178). Denormalize dominant_bulk_class + dominant_production_ubiquity into a systems.db column at build time (import_economics.py, D-200 tier-1), not a runtime Rust join. trait_selection lands as a no-op stub until the catalog (1005) exists. economic_role normalization already in MIGRATION_SQL; confirm via a dry-run importer. Files: import_economics.py, generator.rs CityGenerationContext.
|
||
|
||
--- Closed 2026-06-03: core shipped via PR #145 (D-199 read-set + D-197 prosperity wired; CityGenerationContext extended with morphology_zone/trait_selection/dominant_bulk_class/dominant_production_ubiquity; city_context_reader scaffold). The round-2 ''denormalize dominant_bulk_class/ubiquity into a systems.db column'' sub-part was SUPERSEDED by the D-237 reader-resolution path (resolve via specialization_vocabulary / heuristic) owned by #1014 (blocked on #982). Remaining context fields are documented deferred stubs owned by #1014 (#982), #955 (founding_orientation/placement), #956 (political_archetype). Spine-relevant work complete.', 'done', 'medium', NULL, 'server', 'D-199', '2026-05-22 17:42:34', '2026-06-03 10:07:55', NULL, '3a9986898d1074d347b97261de73a2f1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ9NXNX40J476N2EQM', 'task', NULL, 'Persist deterministic cascade output (build-time bake or local cache)', 'Deferred from the #955 pair session. The Phase-4 cascade (Layers 0-5) is fully deterministic (D-010 + SeedChain) — its output (settlement placements, and eventually the full BodyWorldState) is a pure function of (heightmap, authored context, world seed), so it can be cached rather than re-derived on every cold load.
|
||
|
||
CONSTRAINT: systems.db is read-only from the server''s perspective (schema header) — the runtime server CANNOT write it. So a persistent cache is one of:
|
||
(A) Build-time whole-cascade bake into systems.db (a tool runs the Rust cascade, bakes BodyWorldState/placements; runtime reads). Matches the D-223/#951 ''cascade fills the geometry tables'' intent; staleness handled by the existing meta-stamp. Cost: committed binary artifact + re-bake on input change.
|
||
(B) Runtime local cache in a gitignored .cache/ keyed by (world_seed, schema_version, body_id), written on first derive, read after. No commit/merge issues; per-machine first-derive cost.
|
||
|
||
DESIGN DECISION NEEDED: A vs B (or both — A for shipped worlds, B for dev iteration).
|
||
|
||
WHY DEFERRED (not now): (1) every cascade layer is a PURE function, so a cache wraps it later at ZERO retrofit — determinism makes deferral free. (2) Layer-2 inputs are still churning (#1014/#982 dominant-commodity, #977 trait_selection, #956 political archetype all change placement inputs) — a bake now would be stale/constantly re-baked. (3) Bake the WHOLE cascade once it is end-to-end (post Layer 5, #959), not one layer. (4) No measured perf need yet (Layer 3 = Hungarian on a small grid).
|
||
|
||
TRIGGER: pick this up when the cascade is end-to-end (after #959) OR the Layer-2 context freezes — whichever first. The in-memory hot cache (BodyWorldState / D-203, #968) already covers ''no IO while on a system''; this ticket is only about cross-session/cold-load persistence.
|
||
|
||
Seam: run_layer3 (and each run_layerN) is pure — wrap at the run_cascade call site (a // cache seam comment marks it).', 'backlog', 'low', NULL, 'server', 'D-200', '2026-06-03 10:46:13', '2026-06-03 10:46:13', NULL, '860b2b56d2058ce2f40dc65519d4a099', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWJYWJKF9KNTBW69VC', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Layer 3 — settlement placement (five-phase attractor matching)', 'Five-phase attractor-matching placement (D-211, D-195): largest population areas → capital + cities at terrain features matching role. Derive SettlementClass active/ghost (D-196) and WorldTier (D-218). Settlement names come from the markers name pool (D-223).', 'done', 'high', NULL, 'server', 'D-211', '2026-05-22 17:42:34', '2026-06-03 15:40:48', NULL, '5a2032a7eb173b77fa785075eaf1cce9', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYBG3M83M5JB4WD4NC', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Generation data-quality cleanup — founding_age / economic_tier / role / archetype', 'Prerequisite data fixes the placement + tag engines need (surfaced by the round-2 repo scan). (1) founding_age_years NULL on ALL 273 inhabited bodies -- gates ConstructionEra (D-229) + block irregularity (D-216). (2) economic_tier NULL on ~97% of systems -- gates economic context (D-199). (3) economic_role has 5 variant spellings -- normalize to one canonical set. (4) behavioral_archetype mostly NULL. SOURCE-CANONICAL per asset-pipeline rules: edit the TOML/JSON sources + regen-db; NEVER direct-write systems.db. Blocks Layer-2 (954) and Layer-4 (957).
|
||
|
||
Refinement (2026-05-26): founding_age DECIDED -> derive from settlement_wave. A MIGRATION_SQL block in import_economics.py writes bodies.founding_age_years from system_history.settlement_wave via EVENTS-FIRST derivation: COALESCE the system''s authored founding/first_settlement/colonization event from historical_events.age_years (the precise per-system value, e.g. Van Maanen 180yr) with a wave fallback ONLY when no founding event exists. Canonical wave->age fallback (founding-edge, from systems-framework-final-miri.md): wave_1=600, wave_2=500, wave_3=300, wave_4=100, wave_5=40 yr. EXCLUDE Sol entirely (settlement_wave=origin) -- Sol is out of player scope (Atlas highest-level only, no zoom; deeper Sol = future DLC), bodies in Sol stay NULL and never enter the generation cascade. economic_role normalization already in MIGRATION_SQL (dry-run importer to surface new variants vs the canonical 10). economic_tier is NOT a D-199 required field -> derive via COALESCE-from-population in the importer, do not mass-author wiki; confirm it does not gate generation. behavioral_archetype (1002) is on corporations, not consumed by the Phase-4 cascade -> low priority, trails the other two. Source-canonical + regen-db throughout.', 'done', 'high', NULL, 'server', NULL, '2026-05-25 19:09:07', '2026-06-03 21:18:13', NULL, 'c1f8e0960acde01e0592dace94ea8ef3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWEFGSNFM136PXPNN8', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Rename DistrictSkeleton→QuarterSkeleton and perception ''sim tile''→Subtile terminology (D-222)', 'Naming alignment follow-up from D-222 (spatial hierarchy rename). The 512m generation cell is now the Quarter (was District). (1) Rename the generation skeleton code: DistrictSkeleton -> QuarterSkeleton (server/src/simulation/generator.rs and references); the 2048m District is a new tier above it. (2) Update perception D-records and any code that says ''0.5m sim tile'' / ''1x1 sim tiles'' to the Tile/Subtile vocabulary (Subtile = 0.5m). Pure naming, no behavior change. Deferred from the D-222 design session.', 'done', 'low', NULL, 'server', 'D-222', '2026-05-22 16:05:10', '2026-06-05 11:26:38', NULL, '95308f4d703e6a4754d3bbf0775037fc', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXXWGAQF1WMC4KX3N0', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Layer 3 — territorial status + political archetype + founding orientation', 'Per placed settlement: TerritorialStatus priority-ordered derivation (D-212), PoliticalArchetype (D-214) and its five explicit spatial arrangement patterns (D-215), FoundingOrientation + grid rotation (D-213). Drives the spatial character of each settlement''s grid.
|
||
|
||
---
|
||
Refinement (2026-06-03): gaps resolved. (1) TerritorialStatus DATA SOURCE — map existing dominant_faction (8-value D-237 vocab) -> TerritorialStatus variants; NO schema change. concord_assembly->CommissionControlled, syndic_dominant->CorpTerritory, disputed->ContestedZone, independent->FrontierUnclaimed, etc. Loses population-density Derelict nuance (acceptable). AMENDS D-212 derivation method (write the amendment + final mapping table during impl; claim a D- id). (2) GRANULARITY — derive TerritorialStatus per-Province on DrainageBasin (faithful to D-212, it is a territorial/area property); add the field to DrainageBasin; each settlement inherits its containing basin status. (3) D-215 SCOPE — #956 only DERIVES+STORES PoliticalArchetype (D-214) + which of the 5 arrangement patterns applies + FoundingOrientation/bearing; block-adjacency ENFORCEMENT deferred to Quarter-skeleton gen (#957). (4) BEARING (D-213) — currently hardcoded 0; seed-derive integer bearing 0-359 from a per-settlement SeedChain (thread the carried SeedChain into run_layer3 / derive per city_id); stays integer-deterministic (D-010). (5) ATTACH POINT — PoliticalArchetype/FoundingOrientation/arrangement-pattern on CityPlacement (per-settlement); TerritorialStatus on DrainageBasin (per-province). Enums: confirm TerritorialStatus/PoliticalArchetype/FoundingOrientation exist (check #1006 output in generator.rs) or define. run_layer3 becomes seed-consuming for bearing only.', 'done', 'medium', NULL, 'server', 'D-215', '2026-05-22 17:42:34', '2026-06-05 13:14:32', NULL, '74b223bceb33a6f9283807b4a039396d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXMXGWS6NJ1FBJQ1GM', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Layer 4 — Quarter skeleton (density + district mix + block grid/zoning/reservations)', 'Generate the Quarter skeleton (512m cell, D-222): density model + footprint/fill (D-220), three-component district mix (D-194), 4×4 block grid with zoning + multi-block reservations. skeleton_gen.rs exists — complete it under the D-222 naming (Quarter, not District).
|
||
|
||
Refinement (round 2, 2026-05-25): The skeleton now also emits a BuildingPropertyTag per footprint (D-229: zone_type_id wired to the 31 zone-type RON files, FloorExtent resolving Q-104, BuildingEntryClass, era/era_cause, flavor_ref, initial_condition) inside the extended GenerateSkeleton plan-phase that produces DistrictWorldState{block_tags} (D-230). Also fix GenCompletion::SkeletonGenerated to carry the DistrictWorldState back (current code gap, returns only city_id). Blocked by 954.
|
||
|
||
Refinement (2026-05-26): READY behind 1006. Type defs move to 1006; this story owns LOGIC: zone_type_id selection via a static (ZoningType x economic_role) -> candidate-id-slice table, seed-picking from the 31 RON ids; BuildingEntryClass derivation (zone x layout_mode x prosperity, incl. Commission/Organic credential fork + U-curve degrade); era from founding_age + distance-to-origin (wear, not material); initial_condition from prosperity (D-217 thresholds). BlockSkeleton.era String stub REMOVED (era lives on BuildingPropertyTag). Files: skeleton_gen.rs (assign_building_tags), district_mix.rs, generator.rs.
|
||
|
||
---
|
||
Refinement (2026-06-05, /whats-next): gaps resolved. GAP1 zone_type_id selection — AUTHORED a (ZoningType x economic_role x setting) -> candidate-ZoneTypeId-slice table for the PLANETARY cascade; setting is a TWEAKER (Maritime->port_maritime/fishing/aquaculture/extraction_platform; Agricultural->rural bias; Wilderness->wilderness_frontier/dispersed), NOT a surface/station switch. Station-only ids (residential_station, extraction_space, port_space, rural_orbital) EXCLUDED — separate cascade (see Q-109). Every cell non-empty; unknown role->ZoningType default; seed-pick from slice. Record as D-229 amendment during impl. GAP2 BuildingEntryClass low-prosperity->BreachOnly uses D-217 bands (<0.23 BreachOnly, 0.23-0.43 Restricted, etc.) + Commission/Organic credential fork. GAP3 era = D-229 (founding_age_years + prosperity_baseline + seed); DROP the ungrounded round-3 distance-to-origin phrase. GAP4 remove BlockSkeleton.era String stub (era lives on BuildingPropertyTag); fix construction sites. GAP5 FloorExtent = D-220 density-class midpoints + seed-jitter within range. GAP6 BuildingPropertyTag.doors OUT OF SCOPE -> belongs to #979 (DoorSpec/D-231); stub Vec::new() here. Confirmed present: #1006 type defs (generator.rs), 31 zone-type RON files (server/content/global/zone-types/), district_mix.rs three-component mix, GenCompletion::SkeletonGenerated already carries QuarterWorldState (gap closed prior merge). New seam Q-109 filed (cascade generation-source dispatch).', 'done', 'high', NULL, 'server', 'D-220', '2026-05-22 17:42:34', '2026-06-06 09:01:11', NULL, '672b6ccdd2ec544bb3c4827be4e0c3df', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXHFC6WMAMC30Q32CM', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Author economy label for Glimkop (GJ1245Bb) — NULL economic_role in placeholder system', 'Glimkop (GJ1245Bb, pop 4200, system PLACEHOLDER_087) has economic_role NULL despite inhabited>0 — surfaced during #1001 regen-verify. Pre-existing content gap, not a normalization bug. Either author a canonical economic_role in the wiki source, or confirm PLACEHOLDER_* systems are excluded from the Phase-4 generation cascade (in which case close as wontfix).', 'backlog', 'low', NULL, 'server', NULL, '2026-05-31 09:27:38', '2026-06-06 19:39:58', NULL, '6856d5db3a89ae45d1eb5a90812f1be9', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZXCHGS16BFHSSGSV4', 'epic', '06FB0TNSRZE4CSS8YR0FCEXMK8', 'Phase 4: World generation (tile/chunk/block) — deterministic multilayer seed-to-tile cascade + per-layer Atlas maps + asset pipeline', 'Deliverable: Walkable generated world + asset creation catalog with production status. Automated tile/chunk/block generation (NPC layer ignored). Parallel asset pipeline: rural walls, barns, station walls, auto doors, cars, lamp posts, TVs, billboards etc. Depends on Phases 1-4 (world structure + rendering pipeline exist).', 'in_progress', 'high', NULL, NULL, NULL, '2026-03-25 13:30:00', '2026-06-06 19:39:58', NULL, 'b5cff72f38dacf54b6a4a6903d449f99', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZT9E0PFG8WFS61XAC', 'task', '06FB0TNSRXMXGWS6NJ1FBJQ1GM', 'zone_type_id selection + BuildingEntryClass / era / initial_condition derivation', 'zone_type_id from (ZoningType + economic_role + seed) -> one of the 31 D-142 RON files. BuildingEntryClass from (zone_type x layout_mode x prosperity) incl. Commission/Organic credential fork + U-curve degrade. era from founding_age+prosperity+seed; initial_condition from prosperity_baseline (D-217).
|
||
|
||
Closed via board reconciliation (pql migration cleanup, 2026-06-06): zone_type_for / building_entry_class / construction_era / initial_condition all implemented + wired in server/src/atlas/skeleton_gen.rs; 31 D-142 zone-type RON files present. Implemented under T-957/T-1006; verified.', 'done', 'high', NULL, 'server', 'D-229', '2026-05-25 19:11:15', '2026-06-06 21:34:05', NULL, '113600082826dcc7745930fd1dafc117', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXP0HK3ZX93VPY56QR', 'task', '06FB0TNSRXMXGWS6NJ1FBJQ1GM', 'Extend GenerateSkeleton to emit DistrictWorldState{block_tags} + fix GenCompletion to carry it', 'Plan phase (background, no budget): produce block_tags inside the extended GenerateSkeleton; output DistrictWorldState{skeleton, block_tags: BTreeMap}. Store under BodyWorldState.districts. Fix GenCompletion::SkeletonGenerated to carry DistrictWorldState (today returns only city_id -- code gap).
|
||
|
||
Closed via board reconciliation (pql migration cleanup, 2026-06-06): the work — District/QuarterWorldState{skeleton, block_tags}, assign_all_block_tags wired into GenerateSkeleton, GenCompletion::SkeletonGenerated carrying state, BodyWorldState.quarters storage — was implemented under T-957/T-1006 and verified in server/src. Ticket had drifted in backlog.', 'done', 'high', NULL, 'server', 'D-230', '2026-05-25 19:11:12', '2026-06-06 21:34:05', NULL, '444d810c147987207c0226302abb5b97', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWX0DA0HVSP55T5T60', 'task', '06FB0TNSRXMXGWS6NJ1FBJQ1GM', 'BuildingPropertyTag + FloorExtent/FloorHeightProfile structs; replace BlockSkeleton String stubs', 'Define BuildingPropertyTag (zone_type_id, footprint, extent, entry_class, flavor_ref, era/era_cause, initial_condition) + FloorExtent{base_floor,floor_count,FloorHeightProfile::{Uniform|Variable}}. Resolves Q-104: floor_at_voxel_z / voxel_range_for_floor pure fns. Replaces era/society_profile/zone_palette/chunk_layout String stubs in generator.rs.', 'done', 'high', NULL, 'server', 'D-229', '2026-05-25 19:11:10', '2026-06-06 21:48:14', NULL, '880f3fa02892ad334304cf04da42ded9', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW66RS5T81X1ZWAY4C', 'task', '06FB0TNSRXKN6CKKNDS5PC69Z0', 'Morphology -> permitted street-pattern lookup gating D-215 patterns', 'Lookup: per morphology zone, which D-215 arrangement patterns are legal + the street-shape constraint (fjord/canyon->ribbon|hub-spoke, delta->hub-spoke w/ bridge nodes, alluvial-plain->any, island->hub-spoke, mountain-pass->ribbon). Prevents radial cities in fjords.', 'done', 'high', NULL, 'server', 'D-234', '2026-05-25 19:11:22', '2026-06-07 08:10:16', NULL, '1c4a53a416526d63874853aa26641fa6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW0M5DBNY68RPDPEX0', 'task', '06FB0TNSRXKN6CKKNDS5PC69Z0', 'Street/corridor network + district access_points geometry (+/-45 cap)', 'Fill the chunk_layout/corridors/access_points stubs: street network within/between blocks, district entries/exits, +/-45 deg pathfinding cap (D-096), no curves; straight lines only where authored (D-228 cohesion).
|
||
|
||
Closed via Si vet (2026-06-07): AccessPoint/CorridorSpine/ChunkLayout filled with real geometry (Prim-MST, snap45 ±45° cap), wired + tested in skeleton_gen.rs under T-957. Drift.', 'done', 'high', NULL, 'server', 'D-234', '2026-05-25 19:11:23', '2026-06-07 08:10:17', NULL, '8261fe896c26bad9bf4935c29b20fe35', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWRQ45V979JDHQD5KC', 'task', '06FB0TNSRXKN6CKKNDS5PC69Z0', 'Block footprint subdivision + interstitial + waterfront rule', 'Subdivide a block into building plots + interstitial (parks/lots/gardens), respecting density (D-220) + BulkClass roofed-coverage (D-233). Waterfront footprint rule: pier/quay geometry (no setback, dock-orthogonal) on the water-facing edge, standard frontage inland.
|
||
|
||
Closed via Si vet (2026-06-07): bsp() + subdivide_block_footprints() + D-233 coverage + D-234b waterfront rule implemented + tested in skeleton_gen.rs under T-957. Drift. Waterfront dormant until the Layer-3→Layer-4 dispatch lands (new ticket).', 'done', 'high', NULL, 'server', 'D-234', '2026-05-25 19:11:25', '2026-06-07 08:10:17', NULL, 'b80e6bc926cc7ba3a12323a7faacf5c8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXKN6CKKNDS5PC69Z0', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Layer 4 — street & footprint geometry (morphology-gated, D-234)', 'Fill the Layer-4 skeleton stub fields (chunk_layout/corridors/access_points) with real geometry, per D-234. (a) Morphology zone -> permitted street patterns lookup gating the D-215 arrangement patterns (fjord/canyon -> ribbon|hub-spoke, delta -> hub-spoke following channels w/ bridges as forced nodes, alluvial-plain -> any, island -> hub-spoke, mountain-pass -> ribbon). (b) Street/corridor network + district access_points within/between blocks (+/-45 deg cap, D-096; no curves). (c) Block footprint subdivision into building plots + interstitial space (parks/lots/gardens), respecting density (D-220) and BulkClass roofed-coverage fraction (D-233). (d) Waterfront footprint rule: pier/quay geometry on water-facing edge, standard frontage inland. Depends on 957 (skeleton).
|
||
|
||
Refinement (2026-05-26): READY behind 1006/957. Two-layer streets (D-234 refined): corridors = MST/least-cost graph over access-points + reservations + landmarks (Civ6 arterials, the audit graph; ribbon = MST on linear nodes, hub-spoke = MST + forced centroid hub); chunk_layout = +/-45 grid lattice per block (Civ4 local), modulated by D-096 Grid/Organic. Morphology -> permitted-pattern lookup gates D-215. Bridge node = waterfront block on a corridor (no separate type). Footprint subdivision = recursive bisection over the 128x128 integer grid, aggregate roofed area within the BulkClass coverage range. Waterfront = pier/quay on the water-facing edge. CorridorSpine/AccessPoint typed structs defined in 1006. Files: skeleton_gen.rs, generator.rs.
|
||
|
||
---
|
||
Largely SUBSUMED by #957 (2026-06-06): the footprint subdivision (BSP + D-233 coverage), the street network (typed AccessPoint/CorridorSpine/ChunkLayout, morphology-gated arterials per D-234a, ±45° local lattice), and the waterfront rule (D-234b) all landed in skeleton_gen.rs as one coherent walkable-quarter deliverable. REMAINING scope: the per-block-EDGE open-water adjacency refinement — applying pier geometry to the exact block edges that touch water — which needs Layer-1 terrain water-adjacency threaded to the quarter via the Layer-3 placement -> Layer-4 GenerateSkeleton dispatch (city_context_reader still stubs founding_orientation=Cardinal). Blocked on that dispatch; the waterfront rule is implemented and activates when real per-settlement orientation flows.
|
||
|
||
Closed via Si vet (2026-06-07): all four D-234 geometry deliverables (morphology gating, corridor/access-point net, BSP footprint subdivision, waterfront rule) landed + tested under T-957. The genuine residual — Layer-3→Layer-4 GenerateSkeleton dispatch (founding_orientation wiring) — is a distinct cross-layer concern, split into its own ticket.', 'done', 'high', NULL, 'server', 'D-234', '2026-05-25 19:08:51', '2026-06-07 08:10:17', NULL, 'c25e7bfcb928ecbeb43f36409770f0e6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWHCN0CCKE1Q5YARJG', 'story', '06FB0TNSRW8G7MTH1FRGR1FN1W', 'Own the ocean/lake water mask', 'Concrete current gap surfaced by Tyre in the atlas-derivation workshop: D-223 stripped the topographic polygons from markers.json, but D-209 CoastalAccess/LakeShore attractor extraction still references oceans[]/lake polygons that no longer exist. The ocean/lake mask must instead be derived from the heightmap sea-level threshold (or a baked water-bodies layer). Unlike the rest of the epic (which lands with future cascade layers), this affects attractor extraction today.
|
||
|
||
Closed via Si sweep (2026-06-07): ocean_mask/lake_mask derived from heightmap sea-level in features.rs:10-14, consumed by CoastalAccess/LakeShore (426/452). D-209/D-223 reconciliation done. Drift.', 'done', 'medium', NULL, 'server', 'Q-101', '2026-05-25 10:52:23', '2026-06-07 08:32:25', NULL, '6df2de16a68d8d4933c1ec257fe2f5da', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRX9R8486E64KBAHGMW', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Layer 4 — block irregularity from founding age', 'Apply BlockIrregularity derived from founding_age (D-216) to the block grid geometry — older settlements get more irregular streets. Orthogonal to density. block_irregularity.rs exists.', 'done', 'medium', NULL, 'server', 'D-216', '2026-05-22 17:42:34', '2026-06-07 08:32:25', NULL, 'b40108e7c047956561074a0cde785ac2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYYTGSXMRP7HDRPZ48', 'task', '06FB0TNSRWN78KNTHMER9HN7QR', 'CityGenerationContext extension (morphology_zone, trait_selection, dominant_bulk_class, dominant_production_ubiquity)', 'D-199 amendment: add the four new context fields feeding Layer-4 fill. morphology_zone from the Layer-1 cascade; trait_selection (Arc) drawn via the trait-template catalog (977); the two commodity signals from 954 lookup.
|
||
|
||
Closed via Si sweep (2026-06-07): all four fields (morphology_zone, trait_selection, dominant_bulk_class, dominant_production_ubiquity) present on CityGenerationContext (generator.rs:1065-1073), shipped under T-954/PR #145. Drift.', 'done', 'medium', NULL, 'server', 'D-199', '2026-05-25 19:11:07', '2026-06-07 08:32:25', NULL, 'd53f40f7501ccef1bd4a00ef81706f8d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ9NP0FSP7EMHP0D3M', 'task', '06FB0TNSRYE43XRXRWS6GZK4PW', 'Condition overlay Bevy system (BuildingConditionState/OccupancyState) on EconEvent', 'Separate Bevy system triggered by EconEvent (D-180), painting over the frozen structural fill: BuildingConditionState{New|Maintained|Worn|Derelict|Abandoned}, OccupancyState, VegetationEncroachment; feeds D-100 DamageOverlay. Hard wall: cannot change a BuildingTag; holds no PressureState ref.
|
||
|
||
Clarification (Si sweep 2026-06-07): supersedes the description''s ''feeds D-100 DamageOverlay'' line. Per the T-979 refinement (authoritative), the condition overlay does NOT feed D-100 — BuildingConditionState is a standalone system (OccupancyState/VegetationEncroachment over EconEvent). Implementer: ignore the D-100 reference; do not wire DamageOverlay.', 'backlog', 'medium', NULL, 'server', 'D-198', '2026-05-25 19:11:55', '2026-06-07 08:40:15', NULL, '07f2246ef3f4de2648386ffc98cfcbc2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ8BFVNWDH17CMH1YM', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Per-layer Atlas map viewer (generation progress viewer)', 'Render each cascade layer as a MAP in the implant Atlas (D-191, the Phase 3 viewer — D-166 amendment): terrain → water → biome → settlements → political zones → quarter/block skeleton → tiles. This is the progress-viewer deliverable; NO in-world rendering. Grows as each layer lands.
|
||
|
||
---
|
||
Refinement (2026-05-23, /whats-next):
|
||
- DATA TRANSPORT (resolves Q-098): NO bake — baking derived layer data makes mods second-class. A server-side FILE STREAM PROXY: resolves a body source files across base + mod paths, runs the deterministic cascade on demand (run_cascade, LRU-cached per D-203, ~45ms), and streams serialized layer data to the Godot client over IPC. First-party and mod bodies use the identical path; no pre-baked derived artifacts. Protocol/stream spec designed with Tyre and recorded in a D-record resolving Q-098.
|
||
- UI: layer selector in the existing regional Atlas view; layers are ADDITIVE overlays (toggle heightmap + rivers + attractors + sub-biome together and composite), not one-at-a-time — matching the existing overlay-bar model (D-191).
|
||
- SCOPE NOW: only Layer 0 (heightmap) + Layer 1 (rivers/basins/attractors/sub-biome) exist; the viewer grows as layers land (D-166). Acceptance: Layer 0 + Layer 1 render as additive, toggleable overlays for a body, fed by the proxy.
|
||
|
||
---
|
||
Design (D-226, Araminta, 2026-05-24) — human-visual layer of the inspection harness. Extend OVERLAY_DEFS / AtlasOverlayBar with a generation overlay group (second row) + a left-side legend panel; do NOT build a separate viewer. Encoding: relief base; rivers as blue polylines (mouths = double-circle markers, confluences where in-degree >= 3); basin fills very translucent + thin boundary polylines; attractors as markers where SHAPE encodes the 7 AttractorTypes (circle/half-circle/diamond/down-tri/up-tri/hollow-circle/square) and COLOR encodes sub-biome (shape carries identity in headless/monochrome; color is additive); size scales with strength, skip strength < 0.15. Stable button ids gen_l0_heightmap / gen_l1_rivers / gen_l1_basins / gen_l1_attractors; start pending/locked, unlock+activate via notify_gen_layer_ready(id) as data arrives (grows as layers land, D-166). Consumes the live proxy (#969); the agent channel (#971) drives this same UI.
|
||
|
||
Remaining to close (Si sweep 2026-06-07): add the gen_l0_heightmap overlay to OVERLAY_DEFS + render path in atlas_viewer.gd / atlas_marker_overlay.gd — required by the D-226/T-960 acceptance criteria but currently absent. Layer-1 overlays (rivers/basins/attractors) + proxy wire + pending indicator are already implemented; this Layer-0 overlay is the sole remaining piece.', 'in_progress', 'high', NULL, 'client', 'D-191', '2026-05-22 17:42:34', '2026-06-07 08:40:15', NULL, '4db4f39acbdd3e9313877b9403461bd3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZJ0R21VMF3PP4WSB0', 'story', NULL, 'v0.1 prototype scope', NULL, 'done', 'medium', NULL, NULL, 'Q-002', '2026-02-09 15:21:44', '2026-06-07 12:31:26', NULL, '78cf807b2bf473c1e4c410b3b717b922', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYEFGG8JX0QE7E25EG', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Layer-3 -> Layer-4 GenerateSkeleton dispatch (founding_orientation wiring)', 'Wire Layer-3 settlement placement to Layer-4 quarter generation so the already-implemented Layer-4 geometry runs in production with real per-settlement orientation. Today there is NO production call site that dispatches GenerateSkeleton from a placement: city_context_reader.rs:484 stubs founding_orientation=Cardinal, so the implemented D-234b waterfront rule (and morphology-correct streets) stay dormant.
|
||
|
||
Scope: on GenCompletion::BodyAnalyzed, iterate state.placements and submit one GenerateSkeleton work item per placed settlement, building CityGenerationContext from each CityPlacement (context_from_read_set, city_context_reader.rs:~462) and overriding founding_orientation with the attractor-matched CityPlacement.founding_orientation (already computed in attractor_matching.rs:~535, carried on CityPlacement:~63).
|
||
|
||
Call sites: plugin.rs BodyAnalyzed handler (~84), gen_queue.rs GenerateSkeleton arm, city_context_reader.rs (stub at 484), attractor_matching.rs. Q-109 (multi-source/station dispatch) is adjacent but non-blocking for the planetary path. Surfaced by Si vetting (2026-06-07): T-976/989/990/991 geometry is done+tested but dormant without this dispatch.
|
||
|
||
---
|
||
Refinement (Si, 2026-06-07) — READY:
|
||
|
||
Wiring point: drain_generation_completions in server/src/atlas/plugin.rs:78. The BodyAnalyzed arm (line 84) currently calls cache.insert(state) and discards placements. Expand it: after cache insert, iterate state.placements (Vec<CityPlacement>, body_world_state.rs:85) and submit one GenWorkItem::GenerateSkeleton per placement. System signature grows by Option<Res<CityContextReaderResource>> + Option<Res<SimRng>> (world_seed), mirroring serve_atlas_requests; both already imported.
|
||
|
||
Per placement: ctx = reader.build_context(placement.city_id, world_seed) (city_context_reader.rs:221) -> read_set -> context_from_read_set -> CityGenerationContext. Override the stub: ctx.founding_orientation = placement.founding_orientation.clone() (the one field stubbed Cardinal at city_context_reader.rs:484; value computed by founding_orientation() at attractor_matching.rs:535, carried on CityPlacement:63 from attractor.water_bearing + territorial_status).
|
||
|
||
GenerateSkeleton other fields: economic_role/population/founding_age_years from reader.read_set() CityEconomicReadSet (call read_set directly to capture them; carried separately per gen_queue.rs:93-108). body_id = state.body_id.clone(). chain = SeedChain::for_body(world_seed,&body_id).derive(SeedDomain::Layer4Quarter, placement.city_id) (Layer4Quarter at seed.rs:92; mirrors Layer3Settlement use at city_context_reader.rs:389).
|
||
|
||
DECISION for implementer (no open Q, one-liner): quarter_id has no canonical derivation yet (test placeholder city_id*10). Use SeedChain::for_body(world_seed,&body_id).derive(SeedDomain::Layer4Quarter, placement.city_id).seed() — deterministic, namespace-isolated; add a comment referencing D-194/D-230.
|
||
|
||
Edge cases: empty state.placements -> loop submits nothing, returns normally (no special case). Q-109 (station/multi-source dispatch) non-blocking — BodyAnalyzed only fires on the planetary AnalyzeBody path; stations have no AnalyzeBody enqueue site yet.
|
||
|
||
Verified: Layer-4 geometry (D-234a/b) fully implemented in server/src/atlas/skeleton_gen.rs (derive_corridors reads morphology_zone, derive_access_points reads road_entry_directions, waterfront rule ~108-113 reads founding_orientation). Only the dispatch is dormant.', 'done', 'high', NULL, 'server', 'D-234', '2026-06-07 08:10:17', '2026-06-07 16:46:01', NULL, 'c4ca1ed55d31df680c0ff4ae173e6b80', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRX7Y62J6V46R877ZM8', 'task', '06FB0TNSRW8G7MTH1FRGR1FN1W', 'Anti-squaring domain warp — stateless f64-to-voxel', 'D-239 section 4. Stateless hash-based pure fn(seed,body_id,pos) — no lookup table / thread-local cache (order-independent across threads/platforms). Keep f64 sub-metre precision to the final voxel coordinate, then truncate (a cast, NOT a comparison) to the integer voxel address -> IEEE-754-deterministic across targets. +/-8m range makes FMA-contraction ULP variance harmless (no platform guards). Cross-target determinism test. Position math only — D-010 integer discipline preserved on all material/morphology decisions.', 'done', 'high', NULL, 'server', 'D-239', '2026-06-07 10:33:47', '2026-06-08 09:25:20', NULL, '1109f629c46f177b4435cb30454f6e53', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW8ADSD8ZK32K7SWSC', 'task', '06FB0TNSRW8G7MTH1FRGR1FN1W', 'District climate primitives — temperature + moisture (2x2km)', 'D-239 section 2. Scalar district temperature in degrees C, NULLABLE (no atmosphere -> null -> climate branch absent; airless surface ice is geology per D-227). Derived from sun (luminosity+insolation), planet (latitude+elevation lapse+orbital/axial phase=season term, day-phase=diurnal term), atmosphere (greenhouse->base, heat-retention->diurnal-swing amplitude; thick air=small swing). Separate moisture primitive from hydrosphere. Formalises D-210''s temperature proxy. Tiles inherit district values.
|
||
|
||
---
|
||
Refinement (/whats-next 2026-06-07) — gaps resolved with Jeroen:
|
||
|
||
1. Data inputs (hybrid): import axial_tilt_deg into the bodies table from the
|
||
already-authored planet-gen body-def TOMLs (via the import pipeline); derive
|
||
the rest at runtime in Rust — luminosity from spectral_class lookup, orbital
|
||
distance (AU) from orbital_period_days via Kepler''s third law + star mass.
|
||
Do NOT re-encode the full Python tuning tables in Rust beyond these.
|
||
|
||
2. Carrier rung: temperature is carried as `temperature_c: Option<f32>` (+ a
|
||
moisture primitive) ON the T-1023 RegionProfile struct — NOT a new carrier
|
||
tier. Compute on a 2x2km climate grid; regions sample it. The "~1km vs 2km"
|
||
label is cosmetic. Needs a one-line D-239 clarification (see note below).
|
||
|
||
3. Diurnal-swing values: reuse the tuned greenhouse offsets from
|
||
tooling/planet-gen planet_simulation.py; add a NEW small atmosphere ->
|
||
diurnal_amplitude_C table (5 classes; airless/thin large swing ~40-60C,
|
||
dense/thick small swing ~2-5C). Store these constants in a SOURCE TOML
|
||
(source-canonical, tunable without recompiling), not hardcoded in Rust.
|
||
|
||
4. Season term: produce a MEAN-ANNUAL scalar temperature (orbital phase fixed,
|
||
e.g. equinox); carry diurnal swing as an amplitude only — NO time argument.
|
||
No clock dependency. The dynamic clock-bound seasonal branch stays deferred
|
||
to Q-105 / Phase 5. Per Jeroen: these calculations don''t need perfection;
|
||
plausible-and-present beats precise.
|
||
|
||
Blocked-by T-1023 (temperature fields live on RegionProfile, which T-1023 defines).
|
||
|
||
D-239 follow-up: the implementer should add a one-line clarification to D-239
|
||
(§1/§2) recording that district temperature is a nullable field on RegionProfile
|
||
sampled from a 2km climate grid, and that climate physics inputs come via the
|
||
hybrid import/derive strategy above. Fold into the implementation PR.', 'done', 'high', NULL, 'server', 'D-239', '2026-06-07 10:33:47', '2026-06-08 09:25:20', NULL, '18c3dadade93f9126d3a5ef9439dfbd8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYMFY5VFPXGANNRSXW', 'task', '06FB0TNSRW8G7MTH1FRGR1FN1W', 'RegionProfile carrier (~1km) + derived gating params + BodyWorldState cache', 'First stage of the D-239 three-carrier chain. Define the RegionProfile struct (morphology_zone, tectonic_class, glaciation_grade, slope/lithology/elevation summaries, and a derived per-body-class RIVER_THRESHOLD via (hydrosphere,tectonic_activity,precipitation_class)->threshold, NOT the global 200). Pure region-derivation fn(seed,atlas,body-params,pos). Cache in BodyWorldState (D-203, ~6k regions/body) populated in the D-206 background pass so the Atlas reads zone labels without triggering voxel derivation. No authoring at this layer — all gating params derived from body params. D-239 sections 1,10.
|
||
|
||
---
|
||
Refinement (/whats-next 2026-06-07) — Si review: READY.
|
||
|
||
Scope note: the existing MorphologyZone enum (server/src/simulation/generator.rs,
|
||
12 variants) does NOT need reconciling to the D-239 §6 frozen 17-zone vocabulary
|
||
in this ticket — that reconciliation is T-1027''s job (Morphology classifier —
|
||
17-zone frozen vocab + 8-family gate). T-1023 uses the existing MorphologyZone
|
||
(or a placeholder field) and does not block on the vocabulary change.
|
||
|
||
Companion note: T-1024 will add temperature_c: Option<f32> + a moisture primitive
|
||
as fields on the RegionProfile struct defined here (see T-1024 refinement). Define
|
||
the struct so those fields can be added without churn.
|
||
|
||
Cache populate hooks into the same GenCompletion::BodyAnalyzed drain arm
|
||
(server/src/atlas/plugin.rs) that T-1022 just wired for L3->L4 dispatch.', 'done', 'high', NULL, 'server', 'D-239', '2026-06-07 10:33:47', '2026-06-08 09:25:20', NULL, '9c9abdbeeafe9138acaf064a5d4c312a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZXWJ6H5YW6G121S7W', 'task', '06FB0TNSRW8G7MTH1FRGR1FN1W', 'Dispatch RegionProfile layer in production — read BodyParams from DB at AnalyzeBody enqueue', 'The D-239 carrier foundation (T-1023/1024/1026, PR #158) built RegionProfile + climate derivation and wired the cascade to run the RegionProfile layer when GenWorkItem::AnalyzeBody carries body_params. But every production enqueue site currently passes body_params: None (see layer_proxy.rs TODO), so the region/climate layer only runs in unit tests, never in production. Wire the DB read: at AnalyzeBody enqueue, load each body''s physical params (axial_tilt_deg, spectral_class, star_type, hydrosphere, atmosphere, orbital_period_days, lat/elevation) from the bodies/star_systems tables, build BodyParams, and pass Some(Box::new(..)). Then BodyWorldState.regions populates in the D-206 background pass as T-1023 intended. Mirrors the T-1022 dormant-until-dispatched pattern.', 'done', 'high', NULL, 'server', 'D-239', '2026-06-08 08:29:23', '2026-06-08 10:53:48', NULL, '41c3cd7b3329b5cfdf8a181121c0891b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYRADFJ0FF2WW1G2QM', 'task', '06FB0TNSRW8G7MTH1FRGR1FN1W', 'Climate-derived fields — precipitation, GlaciationGrade, vegetation/treeline', 'D-239 section 2. Everything climatic derives from temperature(+moisture): precipitation_class = f(temp,moisture); GlaciationGrade from long-term/seasonal-minimum temperature (consumed by morphology gating); vegetation/treeline = temperature bands x elevation (Forest->Scrub->Barren no-skip, riparian 1-3 tile band). All derived, none authored. Blocked by the temperature/moisture primitives.', 'done', 'high', NULL, 'server', 'D-239', '2026-06-07 10:33:47', '2026-06-08 11:27:11', NULL, 'e5ed17198597e24773bb56cb5c1ec339', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRX2TD5M8RQDJRNXA24', 'task', '06FB0TNSRW8G7MTH1FRGR1FN1W', 'Morphology classifier — 17-zone frozen vocab + 8-family gated selector + seam matrix', 'D-239 sections 5,6,7. Frozen 17-zone MorphologyZone Rust enum (the canonical freeze point; add/rename/remove needs a D-record amendment; classifier tuning stays free). 8-family gated decision tree over integer RegionProfile inputs: LavaField,FjordWall,CliffCoast,BraidedDelta,DuneStrand,IncisedGorge,MeanderReach,AlluvialPlain(fallback). Hard gates pre-selection in tree order: fjord>=GlaciationGrade2, LavaField=tectonic_class Volcanic, lithology bounds slope/form. Build-time compatibility-matrix invariant test blocking incompatible adjacencies (e.g. Meander<->Volcanic) — never a runtime override. Four zones (tidal flat, estuarine, alpine, wetland) are derived sub-classifications, not families. Blocked by RegionProfile + climate-derived GlaciationGrade.', 'done', 'high', NULL, 'server', 'D-239', '2026-06-07 10:33:47', '2026-06-08 11:27:11', NULL, 'f58734383a9c2ebc1de0f843a426416a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWYP6R87MWZC93HPAR', 'task', '06FB0TNSRW8G7MTH1FRGR1FN1W', 'VoxelColumn pipeline (walking skeleton) — ChunkContext + voxel derive/cache + AlluvialPlain', 'D-239 sections 1,7,10. Walking skeleton of the lower chain. ChunkContext (64m) carrier: one basin-direction + global meander-curve params (NO per-tile flow_direction[64x64] — D8 ~152m/cell is coarser than a chunk; features with wavelength >64m seed from Region-or-higher). VoxelColumn (1m) on-demand derive + cache, never persisted (D-227); compose into the D-228 tile axes (TerrainMaterial/FloorMaterial/Vegetation/Water/elevation). Wire the domain warp through chunk/voxel. End-to-end with ONLY the AlluvialPlain fallback generator to prove region->chunk->voxel->tile before specialized families. Blocked by warp + morphology classifier.', 'done', 'high', NULL, 'server', 'D-239', '2026-06-07 10:34:11', '2026-06-08 13:18:36', NULL, '4c202dd1472ba05462e8bd62f5e8113c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXFCP7EJV7RZK0TBF4', 'task', '06FB0TNSRW8G7MTH1FRGR1FN1W', 'Specialized morphology geometry generators (7 families)', 'D-239 sections 5,8. Implement LavaField, FjordWall, CliffCoast, BraidedDelta, DuneStrand, IncisedGorge, MeanderReach geometry on the F1 VoxelColumn pipeline. Each honours the binding believability laws (drainage monotonicity / D8 thalweg; lithology->landform; glaciation->form U-valleys/moraines/cirques) and game-feel chokepoint widths (river crossings 3-15m, gorge floors 2-8m). Validate per-family <5ms/chunk (FjordWall/IncisedGorge are far costlier than the AlluvialPlain fallback). May split per-family during refinement. Blocked by the F1 pipeline.', 'done', 'high', NULL, 'server', 'D-239', '2026-06-07 10:34:11', '2026-06-08 14:44:25', NULL, '1280f4ae5c01ea0e8fc80da086518f47', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZPYJZ9YTSPD9MAJT4', 'task', '06FB0TNSRW8G7MTH1FRGR1FN1W', 'Scattered transient freeze/snow model', 'D-239 section 3. Phase transition as a band with deterministic spatially-coherent scatter (clustered patches, never per-tile dice): freshwater (lakes/rivers) +5 to -10 C district mean (the +5 is night-frost reaching the coldest tiles); sea ice own lower/wider band (~-2 onset, pack-ice sheets+leads pattern); snow (land) moisture-gated. TRANSIENT in the marginal band — forms in the cold phase, melts in the warm phase (day/night, season) -> time-of-day passability shifts. The transient/clock-bound portion is a forward contract to Q-105 (region seasonal/clock state); the static scattered model is buildable now. Blocked by climate-derived fields.', 'done', 'medium', NULL, 'server', 'D-239', '2026-06-07 10:34:11', '2026-06-08 15:34:04', NULL, '0e85063af9c5645d085d04bd15a69d0b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ8Y4TJVADD2GYM1H4', 'story', '06FB0TNSRW8G7MTH1FRGR1FN1W', 'Class-envelope temperature model — drop non-canonical orbit/star inputs (D-240)', 'Rewrite derive_temperature_c (region_profile.rs) to the D-240 planet_class temperature-envelope model: drop ALL orbit/star physics (derive_distance_au, the luminosity() lookup + [star_luminosity] table, orbital_period_days, spectral_class, star_type as inputs). Temperature base = planet_class envelope (source-canonical in climate_constants.toml); latitude maps across it (pole=cold end, equator=warm end); atmosphere/hydrosphere/elevation modulate within bounds; the body seed adds a small bounded nudge for variety. Strip the now-dead orbit/star fields from BodyParams + BodyParamsReader + the bodies-table read (audit 2026-06-08 confirmed derive_temperature_c is the only consumer). Then regenerate the T-1031 golden so it pins correct temps. Blocks T-974 completion.
|
||
|
||
Approved first-pass planet_class temperature envelope (°C, pole end → equator end). Tunable in server/data/climate_constants.toml. Parse cold_*/hot_*/warm_* prefixes to shift the band; sane default for unknown classes.
|
||
|
||
| planet_class | band (pole → equator) |
|
||
|---|---|
|
||
| frozen / ice | -90 → -25 |
|
||
| boreal | -35 → 12 |
|
||
| cold_arid | -40 → 20 |
|
||
| temperate / oceanic | -12 → 28 |
|
||
| subtropical / warm_ocean | 2 → 34 |
|
||
| tropical | 16 → 40 |
|
||
| arid | -5 → 45 |
|
||
| hot_arid | 20 → 58 |
|
||
| volcanic / geothermal | 30 → 90 (special-cased) |
|
||
| barren (airless / atmosphere=none) | none (climate branch absent, per D-239 §2) |
|
||
|
||
Latitude maps the region linearly across the band (|lat|/90). Atmosphere greenhouse shifts toward the warm end + sets diurnal swing; elevation lapse pulls highlands toward the cold end; clamp to the band. Seed nudge: a few °C of deterministic per-body variation, clamped within the band.', 'done', 'high', NULL, 'server', 'D-240', '2026-06-08 16:06:13', '2026-06-08 17:17:58', NULL, 'd674125a71e2f09d4d78050eaee6913d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXTPRZ40AC8HJGSQZ0', 'task', '06FB0TNSRW8G7MTH1FRGR1FN1W', 'Believability + determinism + <5ms budget verification harness', 'D-239 sections 1,8,9. Golden-seed regression for the binding laws (drainage monotonicity, lithology->landform, glaciation->form with no glacial-U on GlaciationGrade 0, climate->vegetation no-skip + riparian band), per-family <5ms/chunk budget assertion, and the validation-case bodies: Kallast=alluvial plain/Soil, Velen=tidal-flat/dune coast (VERIFY it has a moon param for the tidal term first), Cygni B=volcanic immature drainage, Ross 128=ocean island terrain, Gruenfeld=marginal Gravel/Scrub. If a body reads wrong, fix its params — never patch the derivation (D-239 section 1). Blocked by the family generators.
|
||
|
||
---
|
||
Note from T-1028 review (Tyre, 2026-06-08): VoxelCache LRU eviction is an O(capacity) linear scan for the minimum access_gen (default cap 8192). Latent — at the D-239 §10 ~2.2-4.2 ms/chunk budget (4096 voxels) an 8k scan is measurable noise, not a blocker. If it shows up in this ticket''s profiling, the fix is a secondary BTreeMap<(access_gen, CacheKey), ()> eviction index (stays D-010-compliant). Scope before the budget test runs.
|
||
|
||
---
|
||
RESUME NOTE (2026-06-08, context reset). Where T-974 stands and how to finish it.
|
||
|
||
STATUS: Epic T-974 (Atlas-to-tile derivation) is ~done. Merged this session:
|
||
T-1023/1024/1025/1026/1027/1028/1029/1030/1032 + T-1033 (class-envelope temperature,
|
||
D-240). Only T-1031 (this ticket) + T-1034 remain to close T-974.
|
||
|
||
D-240 (just landed): registry orbit/star data is non-canonical placeholder; temperature
|
||
derives from planet_class envelope + atmosphere + hydrosphere(maritime moderation) +
|
||
seed — NO orbit/star inputs. This FIXED the +356C "temperate" worlds. BodyParams was
|
||
stripped of orbital_period_days / spectral_class / star_type / axial_tilt_deg.
|
||
|
||
T-1031 IS PARKED in a worktree at .worktrees/verification-harness (branch
|
||
verification-harness), created BEFORE T-1033. The harness (server/tests/derivation_harness.rs)
|
||
is built: golden-seed determinism + §8 law sweeps + per-family budget + validation bodies
|
||
(Kallast pass; Velen/Gruenfeld skipped-not-in-wiki). It also made derive_morphology_zone pub.
|
||
|
||
TO FINISH T-1031 (3 steps):
|
||
1. Rebase/merge current main into the verification-harness worktree. It will then FAIL TO
|
||
COMPILE: the harness test fixtures construct BodyParams with the now-removed fields
|
||
(orbital_period_days/spectral_class/star_type/axial_tilt_deg) — strip those from the
|
||
fixtures. Also re-check any validation-body temperature assertions against the NEW
|
||
class-envelope temps (the harness previously noted Marevna -56C as a param issue — that
|
||
may now read differently).
|
||
2. Generate the golden against the CORRECTED temps: from the worktree,
|
||
`cd server && UPDATE_GOLDEN=1 cargo test --test derivation_harness -- golden_seed_determinism_regression`
|
||
then commit tests/golden/derivation_harness.json + the harness + the region_profile.rs
|
||
pub-visibility change together.
|
||
3. Lead verify (cargo test/clippy -D warnings/fmt — the push gate runs all), then /pr-review
|
||
(Hoshe+Tyre) -> merge -> mark T-1031 done -> T-974 CLOSES.
|
||
|
||
ALSO PENDING (separate, fast-follow):
|
||
- T-1034 (high, under T-974): derive_moisture_q hydrosphere vocab mismatch — expects ''ocean''
|
||
but DB uses ''liquid_water'' (175 bodies) -> wrong moisture/precip/glaciation/vegetation.
|
||
The T-1033 [hydrosphere_maritime] table in climate_constants.toml has the real vocab as a
|
||
reference. NOTE: this is now important (water worlds get right temp, wrong moisture).
|
||
- Flaky test (no ticket yet, offer to file): voice::lookup::cache_miss_returns_base_text
|
||
intermittently fails the full-suite push gate under parallelism (passes in isolation;
|
||
unrelated to climate work). CI-hygiene.
|
||
|
||
WORKFLOW REMINDERS for the resumer: lead drives all git; agents run lean (don''t pre-run
|
||
fmt/clippy/test — the pre-push gate enforces them + cargo test now); review caught real
|
||
bugs on EVERY PR this session (hollow tests, a cache-coherence bug hidden by a tautological
|
||
test, the +356C climate bug) — keep reviewing + verifying agent output, don''t trust "all green".', 'done', 'high', NULL, 'server', 'D-239', '2026-06-07 10:34:11', '2026-06-08 20:38:59', NULL, 'a42cfd7c49d216e0d28a098be46284ae', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW8G7MTH1FRGR1FN1W', 'epic', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Atlas-to-tile derivation model', 'Foundational world-derivation model from the atlas-derivation workshop. D-227 (deterministic-rebuild world model: pure function of seed+atlas, derived on demand + cached, only tile mutators persisted, fully volumetric voxel/subvoxel, vertical extent physical not floor-count, variable-height floors) + D-228 (composite tile schema: orthogonal axes TerrainMaterial/FloorMaterial/Vegetation/Water/elevation, derived shape/tactical-form, region-level morphology zones, cohesion matrix, dynamic clock-bound region seasonal state). Most implementation lands as the cascade reaches the tile layers (Phase 4+). Open design tracked in Q-100 (biome authority), Q-101 (refinement contract + body-class river density + ocean mask), Q-102 (cohesion-matrix algorithm), Q-103 (mutator op schema), Q-104 (floor-to-voxel-z mapping), Q-105 (region seasonal/clock state: water/snow/weather/crops).', 'done', 'high', NULL, 'server', 'D-228', '2026-05-25 10:51:49', '2026-06-08 21:01:34', NULL, '3ee28eefc0cb8acf63bdd59bd24a5eb5', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWHN6KDZ5F97XDBD48', 'bug', '06FB0TNSRW8G7MTH1FRGR1FN1W', 'derive_moisture_q hydrosphere vocab mismatch — liquid_water etc. fall to default', 'derive_moisture_q (region_profile.rs) matches hydrosphere on ''ocean''/''rivers''/''ice''/''subsurface''/''none'', but the actual bodies.hydrosphere vocab in systems.db is: liquid_water (175 bodies), ice (962), rivers (31), moderate (21), ocean (only 19), minimal (10), trace (8), subsurface_liquid (7), rivers-lakes (4), extensive (4), subsurface_ice (3), ocean-coastal (1), plus NULL (1649). So ''liquid_water'' and most surface-water worlds fall to the ''_ => 30'' default instead of high moisture — propagating wrong precipitation_class / glaciation_grade / vegetation_class for ~175+ water worlds. Same root cause as D-240 (code keying on a vocab the data doesn''t use). Fix: align derive_moisture_q (and audit any other hydrosphere consumer) to the real vocab — surface liquid (liquid_water/ocean/ocean-coastal/extensive) -> high; rivers/rivers-lakes/moderate -> mid; ice/subsurface* -> low; minimal/trace/none/NULL -> arid. T-1033''s maritime_factor table already maps the real vocab and can be the reference. Found during T-1033 verification (2026-06-08).', 'done', 'high', NULL, 'server', 'D-240', '2026-06-08 17:00:07', '2026-06-08 21:01:34', NULL, '9b9e1f52e3e4ef7ad71febff14cd0e2c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ9FH06QVXD4T20BF8', 'bug', NULL, 'voice::lookup tests share an on-disk cache dir — flaky under parallelism', 'voice::lookup::cache_miss_returns_base_text intermittently fails the full-suite push gate under cargo''s default parallel execution (passes in isolation). Root cause is test-isolation, not production nondeterminism: the test helper test_cache() builds every store with the SAME base_dir (temp_dir/sr-voice-lookup-test) and world_seed (99), so all four module tests share the on-disk zone path .../99/100.msgpack. VoiceCacheStore persists to disk on Drop (save_all) and reads it back on first zone access (load_zone). cache_hit_returns_voiced_text stores ''Voiced line.'' under the IDENTICAL (zone_id=100, CacheKey) that cache_miss_returns_base_text looks up; model/injector versions match so the invalidation guard doesn''t help. When the hit test''s Drop/save interleaves with the miss test (after its remove_dir_all, before its lookup), the miss test loads the leaked entry and returns ''Voiced line.'' instead of ''Base line.'' -> assertion fails. Fix: isolate each test''s cache directory (per-test label + process id) so neither parallel tests nor concurrent cargo test runs collide. Found during T-1031/T-1034 verification (2026-06-08).', 'done', 'medium', NULL, 'server', NULL, '2026-06-08 21:24:06', '2026-06-09 06:18:57', NULL, 'edfdf21f37c9610d280b0ff16e49f7f2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPPMMF7HS6FWRYAKMECTXX0', 'epic', '06FB0TNSRZE4CSS8YR0FCEXMK8', 'Post-cascade gameplay & scenario parking lot', 'Parking lot for game-making work that resumes only after the cascade delivers a traversable world (D-166 amendment 2026-06-12: ''Before this is a game I want it to be a Reach a character can travel through''). Holds scenario/bookmark/storyteller/gameplay-system tickets — including the surviving functional ideas from the dropped v0.2 target (tycoon bookmark, verbs, world feel; D-114/D-115/D-117/D-118/D-120 superseded by D-166). Tickets here are deliberately preserved, not cancelled: functional requirements survive scope pivots. Not a phase — sits beside the six phase epics under T-745 and is excluded from phase kanban queries.', 'backlog', 'low', NULL, NULL, NULL, '2026-06-12 10:22:16', '2026-06-12 10:22:16', NULL, '7d9a8938d359f9aaacec225f934e08f1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPPMZNNEV052DBYYY3A897C', 'initiative', NULL, 'Maintenance & test debt (phase-independent)', 'Standing home for test-failure debt, test-infrastructure work, build/process hygiene, and other phase-independent maintenance (created 2026-06-12 during the cascade-refocus cleanup; absorbs the open children of done umbrella T-871, the former T-34 test-infrastructure tree, and stray hygiene tasks). Deliberately parentless: maintenance is not a cascade phase. Per the broken-tests rule, failing-test children here need a fix or a dated disposition — parking is tracking, not forgetting.', 'backlog', 'medium', NULL, NULL, NULL, '2026-06-12 10:22:19', '2026-06-12 10:22:19', NULL, '01f97e13a5afcaf96fcd48d06d33c09d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYXCMB1D08PW87FR9C', 'story', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Art direction', NULL, 'backlog', 'medium', NULL, NULL, 'Q-003', '2026-02-09 15:21:44', '2026-06-12 10:23:02', NULL, 'feebc02db2e7effe635f48f8b211bf09', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYXCMB1D08PW87FR9C', 'story', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Art direction', 'Parked under Phase 5 epic per cascade refocus 2026-06-12 — art direction (Q-003, still open) is decided when in-world rendering with final-version assets begins.', 'backlog', 'medium', NULL, NULL, 'Q-003', '2026-02-09 15:21:44', '2026-06-12 10:23:02', NULL, 'fdbc63dd9b6518a2796c6f7738ba56fd', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYWZ8VC3HVQJ6HA59R', 'story', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Licensing/distribution', NULL, 'backlog', 'medium', NULL, NULL, 'Q-008', '2026-02-09 15:21:44', '2026-06-12 10:23:02', NULL, 'a228f257b4f9eac1c1d2356c47cfadaa', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYWZ8VC3HVQJ6HA59R', 'story', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Licensing/distribution', 'Parked post-cascade per refocus 2026-06-12 — licensing/distribution (Q-008, still open) is a making-it-a-game/shipping concern with no generation dependency.', 'backlog', 'medium', NULL, NULL, 'Q-008', '2026-02-09 15:21:44', '2026-06-12 10:23:02', NULL, 'c01966c995b3da12b11764132eb84b42', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY7PWMK1F1DAWC08T8', 'story', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Storyteller AI design', NULL, 'backlog', 'medium', NULL, NULL, 'Q-010', '2026-02-09 15:21:44', '2026-06-12 10:23:02', NULL, '1d86a79a61e8d3d21e36136a3682b8ca', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY7PWMK1F1DAWC08T8', 'story', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Storyteller AI design', 'Parked post-cascade per refocus 2026-06-12 — storyteller AI (Q-010, still open) is a gameplay system with no generation dependency; functional requirement preserved.', 'backlog', 'medium', NULL, NULL, 'Q-010', '2026-02-09 15:21:44', '2026-06-12 10:23:02', NULL, 'd9ea9b1f8fa208612bf39d2f48ab71c8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWABN2YJ0SNKRW9D7G', 'epic', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Simulation Tier System', 'Four-tier NPC simulation: Active (full sim), Background (state machines), State-saved (frozen structs), Ungenerated. Timestamp-based LRU eviction, scope tags.', 'backlog', 'critical', NULL, NULL, 'D-026', '2026-02-10 23:15:58', '2026-06-12 10:23:02', NULL, '7721b55841fe4a39d7504a8ee954b3be', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWABN2YJ0SNKRW9D7G', 'epic', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Simulation Tier System', 'Four-tier NPC simulation: Active (full sim), Background (state machines), State-saved (frozen structs), Ungenerated. Timestamp-based LRU eviction, scope tags.
|
||
|
||
Re-parented under Phase 6 epic per cascade refocus 2026-06-12 — background NPC simulation tiers follow world generation and door boundary contracts; former parent T-29 is cancelled. Functional requirement preserved.', 'backlog', 'critical', NULL, NULL, 'D-026', '2026-02-10 23:15:58', '2026-06-12 10:23:02', NULL, 'fdc0c5552ef65c813d90b71e2257ce35', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWCSXFAG1E4TS7HAB4', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Fog of Perception - Vision System', 'LOS-based shadowcasting per z-level. Vision cone (forward/peripheral/behind). Walls block vision, fog returns on departure. Universal for all entities.', 'backlog', 'critical', NULL, NULL, 'D-011', '2026-02-10 23:16:24', '2026-06-12 10:23:02', NULL, '418e201b566c298be5b1dc9f6d42ccd3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWCSXFAG1E4TS7HAB4', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Fog of Perception - Vision System', 'LOS-based shadowcasting per z-level. Vision cone (forward/peripheral/behind). Walls block vision, fog returns on departure. Universal for all entities.
|
||
|
||
Re-parented under Phase 5 epic per cascade refocus 2026-06-12 — fog-of-perception vision is a player-surface system built on generated tiles; functional requirement preserved.', 'backlog', 'critical', NULL, NULL, 'D-011', '2026-02-10 23:16:24', '2026-06-12 10:23:02', NULL, '948a7539aa2cb43aea76a350323d9150', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY3PA3E31NAVQHR5GC', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Camera System', 'Locked to character, no panning. Optional rotation to facing direction (deferred to post-v0.1). Fixed-north for v0.1.', 'backlog', 'critical', NULL, NULL, 'D-015', '2026-02-10 23:16:24', '2026-06-12 10:23:02', NULL, '8c5fb1850e23d3661badb36c2e867abc', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY3PA3E31NAVQHR5GC', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Camera System', 'Locked to character, no panning. Optional rotation to facing direction (deferred to post-v0.1). Fixed-north for v0.1.
|
||
|
||
Re-parented under Phase 5 epic per cascade refocus 2026-06-12 — locked camera is player-control work; functional requirement preserved.', 'backlog', 'critical', NULL, NULL, 'D-015', '2026-02-10 23:16:24', '2026-06-12 10:23:02', NULL, 'cd374ab66d33b4281051389fed254d64', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWBH6313PF00570RGR', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Internal Monologue System', 'Character voice narration for non-visual perception, atmosphere, diegetic hints. Contextual line selection based on situation, character personality, knowledge state.', 'backlog', 'high', NULL, NULL, 'D-016', '2026-02-10 23:16:24', '2026-06-12 10:23:02', NULL, '296e9334c952731fe3627f0c1f58583e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWBH6313PF00570RGR', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Internal Monologue System', 'Character voice narration for non-visual perception, atmosphere, diegetic hints. Contextual line selection based on situation, character personality, knowledge state.
|
||
|
||
Re-parented under Phase 5 epic per cascade refocus 2026-06-12 — internal monologue is a player perception surface; line-content detail can deepen in Phase 6. Functional requirement preserved.', 'backlog', 'high', NULL, NULL, 'D-016', '2026-02-10 23:16:24', '2026-06-12 10:23:02', NULL, 'c1f745b624eea830933397d905d5062a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZP5KQ8RHFQQZK1ZJ0', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Sound Propagation Model', 'Three-range sound: Close (stereo audio), Medium (fog-edge indicators + monologue), Long (insert notifications - stretch). Event classification, directional info.', 'backlog', 'high', NULL, NULL, 'D-018', '2026-02-10 23:16:24', '2026-06-12 10:23:02', NULL, 'fd9cab58eca1544e079a621d05687d28', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZP5KQ8RHFQQZK1ZJ0', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Sound Propagation Model', 'Three-range sound: Close (stereo audio), Medium (fog-edge indicators + monologue), Long (insert notifications - stretch). Event classification, directional info.
|
||
|
||
Re-parented under Phase 5 epic per cascade refocus 2026-06-12 — three-range sound propagation is a player perception surface; functional requirement preserved.', 'backlog', 'high', NULL, NULL, 'D-018', '2026-02-10 23:16:24', '2026-06-12 10:23:02', NULL, 'f6535180332df2caba5223f657bc8743', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW1VJS6GTSSYHK63F8', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Top-down Renderer', 'Tile-based rendering, sprite system, z-level visualization, fog overlay. 3D cutscenes deferred post-v0.1.', 'backlog', 'critical', NULL, NULL, 'D-019', '2026-02-10 23:16:24', '2026-06-12 10:23:02', NULL, '43d6b62fb3f70b687a9426379c460dec', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW1VJS6GTSSYHK63F8', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Top-down Renderer', 'Tile-based rendering, sprite system, z-level visualization, fog overlay. 3D cutscenes deferred post-v0.1.
|
||
|
||
Re-parented under Phase 5 epic per cascade refocus 2026-06-12 — in-world tile/sprite rendering on generated tiles (D-019 superseded by D-148); functional requirement preserved.', 'backlog', 'critical', NULL, NULL, 'D-019', '2026-02-10 23:16:24', '2026-06-12 10:23:02', NULL, 'b2d399cf427665ffc8b0b3f330306dec', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY8XYH2CGTVR0TJ7W8', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Perception Mode Framework', 'Natural vision baseline for v0.1. Modular architecture for future modes (thermal, camera feeds, unisphere tracking, audio analysis). Observer query pattern.', 'backlog', 'medium', NULL, NULL, 'D-017', '2026-02-10 23:16:24', '2026-06-12 10:23:02', NULL, '1ed0c69966f724d8c4660bb7cf24b9a6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY8XYH2CGTVR0TJ7W8', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Perception Mode Framework', 'Natural vision baseline for v0.1. Modular architecture for future modes (thermal, camera feeds, unisphere tracking, audio analysis). Observer query pattern.
|
||
|
||
Re-parented under Phase 5 epic per cascade refocus 2026-06-12 — perception mode framework extends the player vision baseline; functional requirement preserved.', 'backlog', 'medium', NULL, NULL, 'D-017', '2026-02-10 23:16:24', '2026-06-12 10:23:02', NULL, '00139894e437d285a7ceed4480545f56', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYTW3T8YYBJ0VSSZM8', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Information Boundary System', 'First-class information tagging. Every piece of game state tagged with observer access. Foundation for fog, perception modes, NPC knowledge.', 'backlog', 'critical', NULL, NULL, 'D-010', '2026-02-10 23:16:38', '2026-06-12 10:23:02', NULL, '62e43e4e91964a85e046320911ea5dc3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYTW3T8YYBJ0VSSZM8', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Information Boundary System', 'First-class information tagging. Every piece of game state tagged with observer access. Foundation for fog, perception modes, NPC knowledge.
|
||
|
||
Re-parented under Phase 5 epic per cascade refocus 2026-06-12 — observer-access information tagging is the foundation for fog/perception player surfaces; functional requirement preserved.', 'backlog', 'critical', NULL, NULL, 'D-010', '2026-02-10 23:16:38', '2026-06-12 10:23:02', NULL, '0d391cbe9651a3bc75c75137de845597', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXX5X1PDENVXC4DRJ4', 'epic', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Chunk-based Map System', 'Chunk generation and loading. Bounded maps with internal chunks for v0.1. Architecture supports future borderless generation.', 'backlog', 'high', NULL, NULL, 'D-012', '2026-02-10 23:16:38', '2026-06-12 10:23:02', NULL, 'ce059616258642310cecff6f8c5b625a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXX5X1PDENVXC4DRJ4', 'epic', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Chunk-based Map System', 'Chunk generation and loading. Bounded maps with internal chunks for v0.1. Architecture supports future borderless generation.
|
||
|
||
Re-parented under Phase 4 epic per cascade refocus 2026-06-12 — chunk generation/loading is tile/chunk world-generation work; functional requirement preserved.', 'backlog', 'high', NULL, NULL, 'D-012', '2026-02-10 23:16:38', '2026-06-12 10:23:02', NULL, 'a9173a092dbf6fb17794659f7cdf2ce9', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXZK7C4X2DHQ6A0CKR', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Diegetic Insert/Minimap', 'Neural insert UI. POI discovery system (background, NPC tips, research, discovery). Minimap with directional arrows for distant POIs.', 'backlog', 'high', NULL, NULL, 'D-013', '2026-02-10 23:16:38', '2026-06-12 10:23:02', NULL, 'ff9c54ef6d3119a5c00a43718ca88737', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXZK7C4X2DHQ6A0CKR', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Diegetic Insert/Minimap', 'Neural insert UI. POI discovery system (background, NPC tips, research, discovery). Minimap with directional arrows for distant POIs.
|
||
|
||
Re-parented under Phase 5 epic per cascade refocus 2026-06-12 — minimap/POI discovery is a HUD navigation surface for in-world play; functional requirement preserved.', 'backlog', 'high', NULL, NULL, 'D-013', '2026-02-10 23:16:38', '2026-06-12 10:23:02', NULL, 'd3d9d1682a09c509a70f316799bc8e06', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY5H0R4JCAJ6MY4X44', 'epic', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Station District Map - v0.1 Revision', 'Revise D-014 for vertical slice: station district layout, workplace/bar/smuggling ring locations, 15-40 tile functional clusters, 2-3 z-levels.', 'backlog', 'high', NULL, NULL, 'D-014, D-027', '2026-02-10 23:16:38', '2026-06-12 10:23:02', NULL, '002412bb8ab724eaf4ae4ed60c863576', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY5H0R4JCAJ6MY4X44', 'epic', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Station District Map - v0.1 Revision', 'Revise D-014 for vertical slice: station district layout, workplace/bar/smuggling ring locations, 15-40 tile functional clusters, 2-3 z-levels.
|
||
|
||
Re-parented under Phase 4 epic per cascade refocus 2026-06-12 — the v0.1 vertical-slice framing is superseded, but station district layout with functional clusters survives as econ-layer/building-placement generation work.', 'backlog', 'high', NULL, NULL, 'D-014, D-027', '2026-02-10 23:16:38', '2026-06-12 10:23:02', NULL, '6bb3ffd815431c28f75ab8386cc26db9', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW1K4QJHAVSJF2ECSC', 'epic', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Three-Tier Content Pipeline', 'Tier 1: Drama module pool system. Tier 2: Template instantiation engine. Tier 3: Procedural filler generation. Storyteller activation logic.', 'backlog', 'high', NULL, NULL, 'D-023', '2026-02-10 23:16:54', '2026-06-12 10:23:02', NULL, '4ebacb1a412cc0f5afd3a9a220275cff', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW1K4QJHAVSJF2ECSC', 'epic', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Three-Tier Content Pipeline', 'Tier 1: Drama module pool system. Tier 2: Template instantiation engine. Tier 3: Procedural filler generation. Storyteller activation logic.
|
||
|
||
Parked post-cascade per refocus 2026-06-12 — drama modules, storyteller activation, and narrative content pipeline are game-making systems with no generation dependency; functional requirement preserved.', 'backlog', 'high', NULL, NULL, 'D-023', '2026-02-10 23:16:54', '2026-06-12 10:23:02', NULL, '048fc5463c27d51fa7a3a75c94cabe05', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW5FXRP4KGCC3CBMAW', 'epic', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Social Site Template System', 'Functional cluster definition: 4-8 NPC roles, 15-40 tile spaces, sightline requirements. Single-ownership with reference links. Template → instance lifecycle.', 'backlog', 'high', NULL, NULL, 'D-025', '2026-02-10 23:16:54', '2026-06-12 10:23:02', NULL, '3bff76dc2dbcf574aedbe699233cdb38', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW5FXRP4KGCC3CBMAW', 'epic', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Social Site Template System', 'Functional cluster definition: 4-8 NPC roles, 15-40 tile spaces, sightline requirements. Single-ownership with reference links. Template → instance lifecycle.
|
||
|
||
Re-parented under Phase 4 epic per cascade refocus 2026-06-12 — the spatial functional-cluster template (15-40 tile spaces, sightlines, template-to-instance lifecycle) is the building-templates cascade step; NPC-role population detail follows in Phase 6.', 'backlog', 'high', NULL, NULL, 'D-025', '2026-02-10 23:16:54', '2026-06-12 10:23:02', NULL, '92d805f095da86db0877be554f74f8e3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXXVCGN5D35ZJ7M0MW', 'epic', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Dialogue System Architecture', 'Tagged line pools with systemic selection. Four relational layers: access tiers, relationship history, trust-gated gossip, unprompted disclosure. Trait modifier system.', 'backlog', 'high', NULL, NULL, 'D-028', '2026-02-10 23:16:54', '2026-06-12 10:23:02', NULL, '1c766a202d0efda4006ca96ef5fbb7c4', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXXVCGN5D35ZJ7M0MW', 'epic', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Dialogue System Architecture', 'Tagged line pools with systemic selection. Four relational layers: access tiers, relationship history, trust-gated gossip, unprompted disclosure. Trait modifier system.
|
||
|
||
Re-parented under Phase 6 epic per cascade refocus 2026-06-12 — dialogue architecture and relational layers are NPC detail-coloring work; functional requirement preserved.', 'backlog', 'high', NULL, NULL, 'D-028', '2026-02-10 23:16:54', '2026-06-12 10:23:02', NULL, '55e50c06c24a105e4f983df2a467974e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXYZC8QDKK423KFSKC', 'epic', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Population Management', '30/50/20 entanglement ratio (flat/mundane/intrigue). Variable per seed. Module attachment to known NPCs (60-70/30-40 ratio, also variable).', 'backlog', 'medium', NULL, NULL, 'D-029', '2026-02-10 23:16:54', '2026-06-12 10:23:02', NULL, 'ad5d5cec3164efa8ed7e4cbf2577a574', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXYZC8QDKK423KFSKC', 'epic', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Population Management', '30/50/20 entanglement ratio (flat/mundane/intrigue). Variable per seed. Module attachment to known NPCs (60-70/30-40 ratio, also variable).
|
||
|
||
Re-parented under Phase 6 epic per cascade refocus 2026-06-12 — population entanglement ratios are background-NPC-layer work; functional requirement preserved.', 'backlog', 'medium', NULL, NULL, 'D-029', '2026-02-10 23:16:54', '2026-06-12 10:23:02', NULL, 'd8067a374a5a7cdcdac989c5ee413577', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ5AP28E96W00KB0R4', 'epic', '06FBPPMZNNEV052DBYYY3A897C', 'Rust/bevy_ecs Test Infrastructure', 'Test harness for simulation server. External test modules, deterministic replay, ECS state inspection, behavior validation. Minimal production code pollution.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:17:38', '2026-06-12 10:23:02', NULL, 'f35b5e6fc0a225aafdea63a0b9507e70', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ5AP28E96W00KB0R4', 'epic', '06FBPPMZNNEV052DBYYY3A897C', 'Rust/bevy_ecs Test Infrastructure', 'Test harness for simulation server. External test modules, deterministic replay, ECS state inspection, behavior validation. Minimal production code pollution.
|
||
|
||
Re-homed under the maintenance umbrella per cascade refocus 2026-06-12 — server test infrastructure is ongoing infra hygiene (much already delivered via the Gauntlet/verification harness); remaining scope preserved.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:17:38', '2026-06-12 10:23:02', NULL, '9f77e277d1467a352082bb0594e73233', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYDYTDC36V3EPDD7VR', 'epic', '06FBPPMZNNEV052DBYYY3A897C', 'Godot Client Test Infrastructure', 'Test harness for rendering client. Scene testing, input simulation, rendering verification, fog/UI validation.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:17:38', '2026-06-12 10:23:02', NULL, '2ca6965b9f752c1b212d0d0a2667ba15', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYDYTDC36V3EPDD7VR', 'epic', '06FBPPMZNNEV052DBYYY3A897C', 'Godot Client Test Infrastructure', 'Test harness for rendering client. Scene testing, input simulation, rendering verification, fog/UI validation.
|
||
|
||
Re-homed under the maintenance umbrella per cascade refocus 2026-06-12 — client test infrastructure is ongoing infra hygiene (TestHarness and live-tier testing already exist); remaining scope preserved.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:17:38', '2026-06-12 10:23:02', NULL, '270d69970b9b853bcb0954e8be3d50f5', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWYX9HMVEXES6GHXPW', 'epic', '06FBPPMZNNEV052DBYYY3A897C', 'Integration Test Framework', 'End-to-end tests across IPC boundary. Protocol validation, sync verification, full playthrough automation.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:17:38', '2026-06-12 10:23:02', NULL, '80285c89dd7722c73cde7a3360f2a137', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWYX9HMVEXES6GHXPW', 'epic', '06FBPPMZNNEV052DBYYY3A897C', 'Integration Test Framework', 'End-to-end tests across IPC boundary. Protocol validation, sync verification, full playthrough automation.
|
||
|
||
Re-homed under the maintenance umbrella per cascade refocus 2026-06-12 — cross-IPC integration testing is ongoing infra hygiene (live Gauntlet pipeline already covers much of it); remaining scope preserved.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:17:38', '2026-06-12 10:23:02', NULL, 'cc7067391bc544ed46b17b432699e980', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWRV5KJ6DVD742S678', 'story', '06FBPPMZNNEV052DBYYY3A897C', 'Standalone CLI test harness', 'Run simulation headless via terminal. Log output for verification. No GUI dependency.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:17:59', '2026-06-12 10:23:02', NULL, 'f353d713819ff7e22f95584bedaf25e0', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWRV5KJ6DVD742S678', 'story', '06FBPPMZNNEV052DBYYY3A897C', 'Standalone CLI test harness', 'Run simulation headless via terminal. Log output for verification. No GUI dependency.
|
||
|
||
Re-homed under the maintenance umbrella per cascade refocus 2026-06-12 — headless CLI harness is test tooling hygiene under done epic T-35; verify remaining gap vs the existing --test-mode/Gauntlet headless path.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:17:59', '2026-06-12 10:23:02', NULL, '25d05d75c596cc3aa92391d93bcc9ccb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRX13JY1N9BF76CK8WW', 'story', '06FBPPMMF7HS6FWRYAKMECTXX0', 'NetworkBridge stub', 'TCP-based bridge for future multiplayer. Same interface as LocalBridge, deferred implementation.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:18:24', '2026-06-12 10:23:02', NULL, '2a50025cfd384bb89d2128f754308654', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRX13JY1N9BF76CK8WW', 'story', '06FBPPMMF7HS6FWRYAKMECTXX0', 'NetworkBridge stub', 'TCP-based bridge for future multiplayer. Same interface as LocalBridge, deferred implementation.
|
||
|
||
Parked post-cascade per refocus 2026-06-12 — the TCP NetworkBridge for future multiplayer has no generation dependency and stays deferred; functional requirement preserved (same interface as LocalBridge).', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:18:24', '2026-06-12 10:23:02', NULL, '3b4aecc006ff0f423a503cbbbacd8d0e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW99M5Z3KD8HM0VDT8', 'story', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Mood system', 'MoodState component. Mood affected by events, relationships, job satisfaction, contentment. Mood influences behavior.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:19:21', '2026-06-12 10:23:02', NULL, '6a55fc693a32e335312e3c6a71482e6b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW99M5Z3KD8HM0VDT8', 'story', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Mood system', 'MoodState component. Mood affected by events, relationships, job satisfaction, contentment. Mood influences behavior.
|
||
|
||
Re-parented under Phase 6 epic per cascade refocus 2026-06-12 — NPC mood simulation is background-NPC-layer work; rescued from cancelled parent epic T-41. Functional requirement preserved.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:19:21', '2026-06-12 10:23:02', NULL, '783e82c9d93ad5a7cdee581651902ab6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY0PTZ1MKJEGCR2NYC', 'story', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Job performance simulation', 'Work activity states. Job satisfaction tracking. Performance affects mood and relationships.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:19:21', '2026-06-12 10:23:02', NULL, '0217076ad4addac86308cc1f680ed3eb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY0PTZ1MKJEGCR2NYC', 'story', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Job performance simulation', 'Work activity states. Job satisfaction tracking. Performance affects mood and relationships.
|
||
|
||
Re-parented under Phase 6 epic per cascade refocus 2026-06-12 — NPC job-performance simulation is background-NPC-layer work; rescued from cancelled parent epic T-41. Functional requirement preserved.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:19:21', '2026-06-12 10:23:02', NULL, 'b16bda5453b92497d390622f15526d29', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYHPH9Q44CERYSRYJC', 'story', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Unreliable narrator mechanics', 'Monologue can be wrong. Character misinterpretations. Knowledge-gated accuracy.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:20:40', '2026-06-12 10:23:02', NULL, 'f13672adbdb2b1164bdd7598d6b25aff', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYHPH9Q44CERYSRYJC', 'story', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Unreliable narrator mechanics', 'Monologue can be wrong. Character misinterpretations. Knowledge-gated accuracy.
|
||
|
||
Parked as post-cascade gameplay per cascade refocus 2026-06-12; functional requirement (knowledge-gated monologue accuracy) preserved, not cancelled.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:20:40', '2026-06-12 10:23:02', NULL, '770b2bee51d65f264ed58fa9ce72bc54', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWEGYAEQXDVSMF4THG', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Placeholder art pipeline', 'Colored boxes, simple sprites, labels. Functional but not polished. Per D-014 guidance.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:21:12', '2026-06-12 10:23:02', NULL, '685ae03697216b9f5f4e791d5cfee252', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWEGYAEQXDVSMF4THG', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Placeholder art pipeline', 'Colored boxes, simple sprites, labels. Functional but not polished. Per D-014 guidance.
|
||
|
||
Re-parented under Phase 4 epic (T-750) per cascade refocus 2026-06-12; scope updated from v0.1 placeholder art to the final-version asset pipeline per D-166 (no placeholders, no test map) — functional requirement (asset production pipeline) preserved.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:21:12', '2026-06-12 10:23:02', NULL, '6718c338eb00f8fa703c1f6c12c47061', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW4WB0PWAXS6D67J8R', 'story', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Additional mode stubs', 'Thermal, camera feeds, unisphere tracking, audio analysis. Interface only, no implementation. Post-v0.1 features.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:21:23', '2026-06-12 10:23:02', NULL, 'df1325f7c62d8454b433391b168f8bad', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW4WB0PWAXS6D67J8R', 'story', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Additional mode stubs', 'Thermal, camera feeds, unisphere tracking, audio analysis. Interface only, no implementation. Post-v0.1 features.
|
||
|
||
Parked as post-cascade gameplay per cascade refocus 2026-06-12; thermal/camera-feed/unisphere/audio modes are D-017 character-build features, preserved not cancelled.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:21:23', '2026-06-12 10:23:02', NULL, '4d38b67572b5c02ac8d4d5b49b010f3c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYR09VY1F6C42PACGW', 'story', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Character-specific POI filtering', 'Different characters see different POIs. Profession-based, faction-based, relationship-based visibility.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:22:17', '2026-06-12 10:23:02', NULL, 'bc869a5613c10871e32804f3e898867d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYR09VY1F6C42PACGW', 'story', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Character-specific POI filtering', 'Different characters see different POIs. Profession-based, faction-based, relationship-based visibility.
|
||
|
||
Parked as post-cascade gameplay per cascade refocus 2026-06-12; profession/faction/relationship-gated POI visibility preserved, not cancelled.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:22:17', '2026-06-12 10:23:02', NULL, '78d416703703c36d4191f263e2f5f1d8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWMGK6BB68HARCD500', 'story', '06FBPPMMF7HS6FWRYAKMECTXX0', 'POI manipulation mechanics', 'False POIs (traps), outdated locations, spoofed information. Trust/deception layer.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:22:17', '2026-06-12 10:23:02', NULL, '8a9a1060501c70e4f732153a9477fe62', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWMGK6BB68HARCD500', 'story', '06FBPPMMF7HS6FWRYAKMECTXX0', 'POI manipulation mechanics', 'False POIs (traps), outdated locations, spoofed information. Trust/deception layer.
|
||
|
||
Parked as post-cascade gameplay per cascade refocus 2026-06-12; false-POI/spoofing trust-deception layer preserved, not cancelled.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:22:17', '2026-06-12 10:23:02', NULL, '899f36728e92fe8c7aeff2f2a02a8627', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY9C4JS3NDEMS5QBXC', 'story', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Tier 3 procedural generator', 'Generate filler locations from templates. Ambient NPCs, basic interactions, systemic hooks for template colonization.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:23:54', '2026-06-12 10:23:02', NULL, '28010b342b384cba5a77cf4be1ec1b9c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY9C4JS3NDEMS5QBXC', 'story', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Tier 3 procedural generator', 'Generate filler locations from templates. Ambient NPCs, basic interactions, systemic hooks for template colonization.
|
||
|
||
Parked under Phase 6 epic (T-751) per cascade refocus 2026-06-12; ambient-NPC population of template locations comes after the world is walkable (location geometry itself is covered by Phase 4 template/district work).', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:23:54', '2026-06-12 10:23:02', NULL, '570a8daef7cdab27896f6f946c5b5e1f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY8BRY0E3PH6JA2HAM', 'story', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Cross-template reference system', 'Create reference links between templates. Shared NPCs, relationship propagation, contamination paths.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:24:06', '2026-06-12 10:23:02', NULL, '52b53333bc3611e139647d59d36c4294', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY8BRY0E3PH6JA2HAM', 'story', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Cross-template reference system', 'Create reference links between templates. Shared NPCs, relationship propagation, contamination paths.
|
||
|
||
Parked under Phase 6 epic (T-751) per cascade refocus 2026-06-12; shared-NPC/relationship links between templates belong to the NPC detail layer.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-10 23:24:06', '2026-06-12 10:23:02', NULL, '67678194e45fc82bf34e96a61c834883', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYX9R1F6SDN27PDND8', 'story', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Module attachment logic', '60-70/30-40 known vs stranger ratio for module attachment. Variable per seed. Anti-metagaming.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:24:37', '2026-06-12 10:23:02', NULL, '9e840a81b854503f2576474ebd8d7d6c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYX9R1F6SDN27PDND8', 'story', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Module attachment logic', '60-70/30-40 known vs stranger ratio for module attachment. Variable per seed. Anti-metagaming.
|
||
|
||
Parked as post-cascade gameplay per cascade refocus 2026-06-12; drama-module attachment ratios (anti-metagaming) preserved, not cancelled.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-10 23:24:37', '2026-06-12 10:23:02', NULL, 'eff4a3b8d1df1f4b223faf50dbab8c46', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXJ0QD32XB44NESXDW', 'story', '06FBPPMZNNEV052DBYYY3A897C', 'Testing pattern documentation', 'Document agreed patterns. Test organization conventions, naming, structure. Developer guide.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:27:10', '2026-06-12 10:23:02', NULL, '2866969117769a402ea35cb9167c8df7', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXJ0QD32XB44NESXDW', 'story', '06FBPPMZNNEV052DBYYY3A897C', 'Testing pattern documentation', 'Document agreed patterns. Test organization conventions, naming, structure. Developer guide.
|
||
|
||
Re-homed under maintenance per cascade refocus 2026-06-12; testing-pattern developer guide is documentation/infra hygiene (partially covered by CLAUDE.md testing preferences — reconcile when picked up).', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:27:10', '2026-06-12 10:23:02', NULL, 'a1707e0fc860a696e4185c3407cc4b0e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZHTCRQY5G1J8SEGXM', 'story', '06FBPPMZNNEV052DBYYY3A897C', 'Tooling requirements spec', 'Define required tooling: test runners, assertion libraries, mocking frameworks. Installation/setup docs.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:27:10', '2026-06-12 10:23:02', NULL, '2b4756d4fc1d09884cbde5ca27074650', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZHTCRQY5G1J8SEGXM', 'story', '06FBPPMZNNEV052DBYYY3A897C', 'Tooling requirements spec', 'Define required tooling: test runners, assertion libraries, mocking frameworks. Installation/setup docs.
|
||
|
||
Re-homed under maintenance per cascade refocus 2026-06-12; test-tooling requirements spec is infra hygiene (much is de facto settled: gdUnit4, cargo test, Gauntlet).', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:27:10', '2026-06-12 10:23:02', NULL, '85430c9483f3f62444bf0dfd8db39cd1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY9FP8GJSR96661J9M', 'story', '06FBPPMZNNEV052DBYYY3A897C', 'Production code constraints', 'Define rules: what test hooks are acceptable in production code, what must stay external. Pollution boundaries.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:27:10', '2026-06-12 10:23:02', NULL, '959a0000a9e6b4f20ce8eaa5fc4d76cc', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY9FP8GJSR96661J9M', 'story', '06FBPPMZNNEV052DBYYY3A897C', 'Production code constraints', 'Define rules: what test hooks are acceptable in production code, what must stay external. Pollution boundaries.
|
||
|
||
Re-homed under maintenance per cascade refocus 2026-06-12; production-code test-hook policy is engineering-hygiene documentation.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:27:10', '2026-06-12 10:23:02', NULL, 'd71e4a0bb47bc8f488d408b8ba19afa2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY8KWVN9TCM2G5XXG8', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Movement & Collision', 'Tile collision, pathfinding, NPC movement, and game clock systems. Hard blockers identified in v0.1 gap analysis workshop. Without these, NPCs cannot physically navigate the station.', 'backlog', 'critical', NULL, NULL, NULL, '2026-02-11 00:00:57', '2026-06-12 10:23:03', NULL, 'b1dadd77544073516a99f3db850d6735', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY8KWVN9TCM2G5XXG8', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Movement & Collision', 'Tile collision, pathfinding, NPC movement, and game clock systems. Hard blockers identified in v0.1 gap analysis workshop. Without these, NPCs cannot physically navigate the station.
|
||
|
||
Parked under Phase 5 epic (T-749) per cascade refocus 2026-06-12; previous parent initiative T-29 is cancelled — tile collision/pathfinding/clock is the player-walking foundation (NPC movement portion follows in Phase 6).', 'backlog', 'critical', NULL, NULL, NULL, '2026-02-11 00:00:57', '2026-06-12 10:23:03', NULL, '150ea94645f47777383e0eccef421055', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ202MPMFH0EDH2BT4', 'epic', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Observation & Interaction', 'Unified observation pipeline and player interaction systems. The experience layer that connects perception, knowledge, and monologue into the core gameplay loop. Identified as the missing spine in gap analysis workshop.', 'backlog', 'critical', NULL, NULL, NULL, '2026-02-11 00:01:05', '2026-06-12 10:23:03', NULL, '3421d4a2b8fb1e403763a83876246fc3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ202MPMFH0EDH2BT4', 'epic', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Observation & Interaction', 'Unified observation pipeline and player interaction systems. The experience layer that connects perception, knowledge, and monologue into the core gameplay loop. Identified as the missing spine in gap analysis workshop.
|
||
|
||
Parked as post-cascade gameplay per cascade refocus 2026-06-12; the observation/interaction spine of the core gameplay loop is preserved, not cancelled.', 'backlog', 'critical', NULL, NULL, NULL, '2026-02-11 00:01:05', '2026-06-12 10:23:03', NULL, 'fdb933b02ac2af9d0585e9ff2f0af3a5', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZP48TDBTW18P88WNW', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Game State Management', 'Save/load, session management, and game state serialization systems. Required for playable v0.1 sessions.', 'backlog', 'high', NULL, NULL, NULL, '2026-02-11 00:01:13', '2026-06-12 10:23:03', NULL, '9b5824a7c03adcb2281dfa143444a4cb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZP48TDBTW18P88WNW', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Game State Management', 'Save/load, session management, and game state serialization systems. Required for playable v0.1 sessions.
|
||
|
||
Parked under Phase 5 epic (T-749) per cascade refocus 2026-06-12; save/load and session management are tied to playable sessions (savegame lineage is documented as Phase 5+).', 'backlog', 'high', NULL, NULL, NULL, '2026-02-11 00:01:13', '2026-06-12 10:23:03', NULL, '125b493b4c861ba2a04ae2a9185ed944', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY5PJH0XRB4Z92JBER', 'story', '06FBPPMZNNEV052DBYYY3A897C', 'Test output formatter CLI', 'Normalize cargo-nextest and gdUnit4 output into consistent JSON schema (suite, total, passed, failed, failures array). Low priority — gdUnit4 already outputs JSON natively. Source: Hoshe R1 T-3.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-11 00:05:00', '2026-06-12 10:23:03', NULL, 'e1672de4783731547b2847688810f175', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY5PJH0XRB4Z92JBER', 'story', '06FBPPMZNNEV052DBYYY3A897C', 'Test output formatter CLI', 'Normalize cargo-nextest and gdUnit4 output into consistent JSON schema (suite, total, passed, failed, failures array). Low priority — gdUnit4 already outputs JSON natively. Source: Hoshe R1 T-3.
|
||
|
||
Re-homed under maintenance per cascade refocus 2026-06-12; test tooling, not phase work.', 'backlog', 'low', NULL, NULL, NULL, '2026-02-11 00:05:00', '2026-06-12 10:23:03', NULL, '67ea9105ad606a6e386d2f7fcdb155b1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZHW11BZWVZKB5YTH8', 'story', '06FBPPMZNNEV052DBYYY3A897C', 'Crash reporting infrastructure', 'Crash reporting infrastructure for both codebases:\n- Rust panic handler writes crash.log with backtrace\n- Godot push_error captures client crashes\n- Include version, platform, last 100 log lines\n- Needed before external playtesting\n\nEffort: M\nCodebase: server + client\nSource: Architecture Review Audit 2026-02-11\nSprint: 2+ (before vertical slice playtest)', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-11 20:27:45', '2026-06-12 10:23:03', NULL, '3bb30edc990fb63ea6b0ba530e1fe0a4', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZHW11BZWVZKB5YTH8', 'story', '06FBPPMZNNEV052DBYYY3A897C', 'Crash reporting infrastructure', 'Crash reporting infrastructure for both codebases:\n- Rust panic handler writes crash.log with backtrace\n- Godot push_error captures client crashes\n- Include version, platform, last 100 log lines\n- Needed before external playtesting\n\nEffort: M\nCodebase: server + client\nSource: Architecture Review Audit 2026-02-11\nSprint: 2+ (before vertical slice playtest)
|
||
|
||
Re-homed under maintenance per cascade refocus 2026-06-12; infra requirement preserved unchanged.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-11 20:27:45', '2026-06-12 10:23:03', NULL, '3046ccac1355ecf98b7ff730d8abd03d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXVMATNG8QEJVVVCH0', 'epic', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Workshop: Knowledge Graph & Information Boundaries', 'Design workshop for KnowledgeGraph component to replace Vec<String> placeholder.
|
||
|
||
Scope:
|
||
- Graph structure (nodes, edges, timestamps, certainty)
|
||
- Information boundaries (what NPCs know vs do not know)
|
||
- Propagation rules (gossip, observation, inference)
|
||
- Query interface for dialogue/behavior systems
|
||
- Memory limits and forgetting mechanics
|
||
|
||
Pillar-1 mechanic. CRITICAL priority.
|
||
Sprint 2 blocker.
|
||
|
||
Participants: Tyre (lead), Morve, Dudley, SI
|
||
Source: Architecture Review Audit 2026-02-11', 'backlog', 'critical', NULL, NULL, NULL, '2026-02-11 20:27:52', '2026-06-12 10:23:03', NULL, 'f506ed016009ecb27393e8ce71c41b04', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXVMATNG8QEJVVVCH0', 'epic', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Workshop: Knowledge Graph & Information Boundaries', 'Design workshop for KnowledgeGraph component to replace Vec<String> placeholder.
|
||
|
||
Scope:
|
||
- Graph structure (nodes, edges, timestamps, certainty)
|
||
- Information boundaries (what NPCs know vs do not know)
|
||
- Propagation rules (gossip, observation, inference)
|
||
- Query interface for dialogue/behavior systems
|
||
- Memory limits and forgetting mechanics
|
||
|
||
Pillar-1 mechanic. CRITICAL priority.
|
||
Sprint 2 blocker.
|
||
|
||
Participants: Tyre (lead), Morve, Dudley, SI
|
||
Source: Architecture Review Audit 2026-02-11
|
||
|
||
Parked under Phase 6 epic per cascade refocus 2026-06-12; NPC knowledge systems follow the background NPC layer.', 'backlog', 'critical', NULL, NULL, NULL, '2026-02-11 20:27:52', '2026-06-12 10:23:03', NULL, '41396f69c018ecf29aff0e17689172bc', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ8NCH53C9VAC2N3V8', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Workshop: Observer Snapshot Generation Pipeline', 'Design workshop for perception query algorithm that generates ObserverSnapshot.
|
||
|
||
Pipeline stages:
|
||
1. Spatial query (entities in range)
|
||
2. Line-of-sight filtering
|
||
3. Sound propagation
|
||
4. Knowledge graph integration
|
||
5. Snapshot assembly
|
||
|
||
CRITICAL priority. Sprint 2 blocker.
|
||
Depends on Workshop 1 (Knowledge Graph).
|
||
|
||
Participants: Tyre (lead), Morve, Dudley, SI
|
||
Source: Architecture Review Audit 2026-02-11', 'backlog', 'critical', NULL, NULL, NULL, '2026-02-11 20:28:05', '2026-06-12 10:23:03', NULL, 'a7c69a12c7a6c9e2143a80641947e548', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ8NCH53C9VAC2N3V8', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Workshop: Observer Snapshot Generation Pipeline', 'Design workshop for perception query algorithm that generates ObserverSnapshot.
|
||
|
||
Pipeline stages:
|
||
1. Spatial query (entities in range)
|
||
2. Line-of-sight filtering
|
||
3. Sound propagation
|
||
4. Knowledge graph integration
|
||
5. Snapshot assembly
|
||
|
||
CRITICAL priority. Sprint 2 blocker.
|
||
Depends on Workshop 1 (Knowledge Graph).
|
||
|
||
Participants: Tyre (lead), Morve, Dudley, SI
|
||
Source: Architecture Review Audit 2026-02-11
|
||
|
||
Parked under Phase 5 epic per cascade refocus 2026-06-12; player perception pipeline activates with player viewport work.', 'backlog', 'critical', NULL, NULL, NULL, '2026-02-11 20:28:05', '2026-06-12 10:23:03', NULL, '7e004de68834eca5c9a9038ef1bbe277', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZVC39DY5152CXZMB0', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Workshop: Save/Load Architecture', 'Design workshop for save/load system architecture.
|
||
|
||
Key decisions:
|
||
- Custom SaveState struct vs bevy_reflect
|
||
- Version number scheme and migration strategy
|
||
- Relationship to tier system (serialize by tier?)
|
||
- Incremental saves vs full snapshots
|
||
- Quick save vs named saves
|
||
|
||
MEDIUM priority. Must be resolved before vertical slice.
|
||
|
||
Participants: Dudley (lead), Tyre, Morve, SI
|
||
Source: Architecture Review Audit 2026-02-11', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-11 20:28:16', '2026-06-12 10:23:03', NULL, 'a88b7b40aa2b05fd5baeb91363890c87', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZVC39DY5152CXZMB0', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Workshop: Save/Load Architecture', 'Design workshop for save/load system architecture.
|
||
|
||
Key decisions:
|
||
- Custom SaveState struct vs bevy_reflect
|
||
- Version number scheme and migration strategy
|
||
- Relationship to tier system (serialize by tier?)
|
||
- Incremental saves vs full snapshots
|
||
- Quick save vs named saves
|
||
|
||
MEDIUM priority. Must be resolved before vertical slice.
|
||
|
||
Participants: Dudley (lead), Tyre, Morve, SI
|
||
Source: Architecture Review Audit 2026-02-11
|
||
|
||
Parked under Phase 5 epic per cascade refocus 2026-06-12; savegame lineage already planned as Phase 5+ in asset-pipeline.md.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-11 20:28:16', '2026-06-12 10:23:03', NULL, '54cec88f34afca4fb300884337cab649', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWSBWTKM42BVVMPXJG', 'epic', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Workshop: Map Authoring Pipeline', 'Design workshop for map authoring toolchain and format.
|
||
|
||
Key decisions:
|
||
- Tool selection: Tiled vs Godot TileMap vs YAML
|
||
- Map format (JSON, TMX, custom?)
|
||
- Collision layer specification
|
||
- Entity spawn points
|
||
- Loader implementation (server + client)
|
||
- Hot reload support for iteration
|
||
|
||
MEDIUM priority. Sprint 2-3 target.
|
||
|
||
Participants: Morve (lead), Tyre, Dudley, SI
|
||
Source: Architecture Review Audit 2026-02-11', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-11 20:28:22', '2026-06-12 10:23:03', NULL, 'f62afde5bfff20014eae53dffaec16ed', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWSBWTKM42BVVMPXJG', 'epic', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Workshop: Map Authoring Pipeline', 'Design workshop for map authoring toolchain and format.
|
||
|
||
Key decisions:
|
||
- Tool selection: Tiled vs Godot TileMap vs YAML
|
||
- Map format (JSON, TMX, custom?)
|
||
- Collision layer specification
|
||
- Entity spawn points
|
||
- Loader implementation (server + client)
|
||
- Hot reload support for iteration
|
||
|
||
MEDIUM priority. Sprint 2-3 target.
|
||
|
||
Participants: Morve (lead), Tyre, Dudley, SI
|
||
Source: Architecture Review Audit 2026-02-11
|
||
|
||
Re-parented under Phase 4 epic per cascade refocus 2026-06-12; authoring-tool framing superseded by D-166 (no hand-made maps) — surviving scope is format/collision/loader for generator output.', 'backlog', 'medium', NULL, NULL, NULL, '2026-02-11 20:28:22', '2026-06-12 10:23:03', NULL, '49700ba92cebf77fd899a98be505eb73', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWYBGV0A6RBVS1NSP0', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Workshop: Control & Interaction Scheme', NULL, 'backlog', 'critical', NULL, NULL, 'D-053', '2026-02-13 21:05:22', '2026-06-12 10:23:03', NULL, '6cee19a63a5ba848bce561b550e60274', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWYBGV0A6RBVS1NSP0', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Workshop: Control & Interaction Scheme', 'Parked under Phase 5 epic per cascade refocus 2026-06-12; player control workshop runs when player work begins.', 'backlog', 'critical', NULL, NULL, 'D-053', '2026-02-13 21:05:22', '2026-06-12 10:23:03', NULL, '001e82e401ddfc49aa6d8731f8748d8a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXTV61ZRF9RZ6V1NXR', 'story', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Design discussion: insert data feeds — documenting feature systems and plumbing patterns', 'Broad design discussion to map out ALL the data feed systems the insert will eventually surface, identify common patterns, and design foundational plumbing that serves them all. This is bigger than the onboarding dossier — it is the insert as an information platform.
|
||
|
||
Participants: Tyre (architecture), Dudley (server), Stig (UI), Gestalt (systems design), Miri (worldbuilding — what feeds exist in-setting), Ozzie (player experience — what feels good to check)
|
||
|
||
The insert (D-065) is the player''s primary information device. It needs to surface a wide variety of data feeds that exist naturally in the setting. Map these out FIRST, then identify patterns, then design plumbing.
|
||
|
||
## Known and candidate feed types
|
||
|
||
**Documents/dossiers** — static or semi-static authored content. Assignment briefs, personal notes, found documents, intercepted communications. Markdown body, variable injection, triggered delivery.
|
||
|
||
**Messaging/comms** — NPC-to-player and overheard messages. Meridian messages, dead drops, intercepted transmissions. Threaded? Timed delivery? Read/unread state?
|
||
|
||
**News/ticker feeds** — station news, sector bulletins, propaganda. Already have TickerPool (#591) for the bar — how does this generalize to the insert? Weather/atmospheric feeds for planets (adds environmental flavor).
|
||
|
||
**Time systems** — local station time, central Settled Reach time, planetary day-night cycles (varying rotation periods). How does the insert display multiple time references? Which are always visible vs on-demand?
|
||
|
||
**Maps** — district layouts, marked locations, fog-of-war on map data. Progressive reveal as player explores.
|
||
|
||
**Logs/journal** — auto-generated from observations? Player-annotated? Investigation notes the detective accumulates vs cargo manifests the smuggler tracks?
|
||
|
||
**Faction/relationship status** — trust levels, known affiliations, reputation. How much is visible to the player vs hidden (D-012 information boundary)?
|
||
|
||
**Inventory/cargo** — physical items, data chips, contraband manifests.
|
||
|
||
## Questions to resolve
|
||
|
||
1. What feed types exist in the Settled Reach setting? (Miri: what does a station worker/visitor actually have on their insert?)
|
||
2. Which feeds are universal vs archetype-specific? (Detective gets case files; smuggler gets network dead drops. Both get news and time.)
|
||
3. What are the common patterns across feeds? (Delivery trigger, persistence, read state, update frequency, rendering format)
|
||
4. Server-side: single generic "insert_feeds" collection in ObserverSnapshot vs typed fields? Delta updates vs full state?
|
||
5. Client-side: plugin/renderer architecture — how does the insert UI dispatch feed types to renderers without hardcoding each one?
|
||
6. Persistence: session-persistent vs save-persistent vs ephemeral. Which feeds accumulate, which rotate, which expire?
|
||
7. Information boundary (D-012): feeds are perception-filtered. The insert only shows what the PC has access to. How does this interact with the observer snapshot?
|
||
8. Priority/notification: which feeds notify the player (new message!), which are passive (time ticks), which are urgent (warning)?
|
||
|
||
## Output
|
||
|
||
D-record (or major amendment to D-065) documenting:
|
||
- Catalog of insert feed types with properties
|
||
- Common envelope/interface pattern
|
||
- Server→client data flow architecture
|
||
- Rendering dispatch pattern
|
||
- Persistence and lifecycle model
|
||
|
||
This is a design discussion, not implementation. Produce decisions and patterns that #600 and future insert work implement against.
|
||
|
||
## Refs
|
||
D-065 (insert UI), D-012 (information boundary), D-010 (determinism), Q-055', 'backlog', 'high', NULL, NULL, 'D-065,Q-055', '2026-03-05 10:28:30', '2026-06-12 10:23:03', NULL, 'cf5fb202dd6dff99f0d8d9e5170fc22e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXTV61ZRF9RZ6V1NXR', 'story', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Design discussion: insert data feeds — documenting feature systems and plumbing patterns', 'Broad design discussion to map out ALL the data feed systems the insert will eventually surface, identify common patterns, and design foundational plumbing that serves them all. This is bigger than the onboarding dossier — it is the insert as an information platform.
|
||
|
||
Participants: Tyre (architecture), Dudley (server), Stig (UI), Gestalt (systems design), Miri (worldbuilding — what feeds exist in-setting), Ozzie (player experience — what feels good to check)
|
||
|
||
The insert (D-065) is the player''s primary information device. It needs to surface a wide variety of data feeds that exist naturally in the setting. Map these out FIRST, then identify patterns, then design plumbing.
|
||
|
||
## Known and candidate feed types
|
||
|
||
**Documents/dossiers** — static or semi-static authored content. Assignment briefs, personal notes, found documents, intercepted communications. Markdown body, variable injection, triggered delivery.
|
||
|
||
**Messaging/comms** — NPC-to-player and overheard messages. Meridian messages, dead drops, intercepted transmissions. Threaded? Timed delivery? Read/unread state?
|
||
|
||
**News/ticker feeds** — station news, sector bulletins, propaganda. Already have TickerPool (#591) for the bar — how does this generalize to the insert? Weather/atmospheric feeds for planets (adds environmental flavor).
|
||
|
||
**Time systems** — local station time, central Settled Reach time, planetary day-night cycles (varying rotation periods). How does the insert display multiple time references? Which are always visible vs on-demand?
|
||
|
||
**Maps** — district layouts, marked locations, fog-of-war on map data. Progressive reveal as player explores.
|
||
|
||
**Logs/journal** — auto-generated from observations? Player-annotated? Investigation notes the detective accumulates vs cargo manifests the smuggler tracks?
|
||
|
||
**Faction/relationship status** — trust levels, known affiliations, reputation. How much is visible to the player vs hidden (D-012 information boundary)?
|
||
|
||
**Inventory/cargo** — physical items, data chips, contraband manifests.
|
||
|
||
## Questions to resolve
|
||
|
||
1. What feed types exist in the Settled Reach setting? (Miri: what does a station worker/visitor actually have on their insert?)
|
||
2. Which feeds are universal vs archetype-specific? (Detective gets case files; smuggler gets network dead drops. Both get news and time.)
|
||
3. What are the common patterns across feeds? (Delivery trigger, persistence, read state, update frequency, rendering format)
|
||
4. Server-side: single generic "insert_feeds" collection in ObserverSnapshot vs typed fields? Delta updates vs full state?
|
||
5. Client-side: plugin/renderer architecture — how does the insert UI dispatch feed types to renderers without hardcoding each one?
|
||
6. Persistence: session-persistent vs save-persistent vs ephemeral. Which feeds accumulate, which rotate, which expire?
|
||
7. Information boundary (D-012): feeds are perception-filtered. The insert only shows what the PC has access to. How does this interact with the observer snapshot?
|
||
8. Priority/notification: which feeds notify the player (new message!), which are passive (time ticks), which are urgent (warning)?
|
||
|
||
## Output
|
||
|
||
D-record (or major amendment to D-065) documenting:
|
||
- Catalog of insert feed types with properties
|
||
- Common envelope/interface pattern
|
||
- Server→client data flow architecture
|
||
- Rendering dispatch pattern
|
||
- Persistence and lifecycle model
|
||
|
||
This is a design discussion, not implementation. Produce decisions and patterns that #600 and future insert work implement against.
|
||
|
||
## Refs
|
||
D-065 (insert UI), D-012 (information boundary), D-010 (determinism), Q-055
|
||
|
||
Parked in gameplay backlog per cascade refocus 2026-06-12; feed plumbing design resumes when gameplay systems exist to feed it.', 'backlog', 'high', NULL, NULL, 'D-065,Q-055', '2026-03-05 10:28:30', '2026-06-12 10:23:03', NULL, '19bcd44c46ca50f81b75d8e9e08e1353', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWJ60W2RFN2FQ2P3EW', 'epic', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Generator Proof-of-Life', 'Sprint 25 spike: generator must produce usable output before anything else matters. Prove auto-generated locations at scale with legible characters. Template assembly (not procedural geography) for v0.2. See workshop decisions #1, #7, #22, #23. Estimated 7 sprints to proof-of-life playtest (generated location + legible characters + tycoon bookmark from creation to Day 3) — Tyre estimate.', 'backlog', 'critical', NULL, NULL, NULL, '2026-03-05 23:11:39', '2026-06-12 10:23:03', NULL, '5c2c3dc4e338bee268b571675061df7b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWJ60W2RFN2FQ2P3EW', 'epic', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Generator Proof-of-Life', 'Sprint 25 spike: generator must produce usable output before anything else matters. Prove auto-generated locations at scale with legible characters. Template assembly (not procedural geography) for v0.2. See workshop decisions #1, #7, #22, #23. Estimated 7 sprints to proof-of-life playtest (generated location + legible characters + tycoon bookmark from creation to Day 3) — Tyre estimate.
|
||
|
||
Parked in gameplay backlog per cascade refocus 2026-06-12; template-assembly generation superseded by the T-750 cascade — proof-of-life playtest concept preserved.', 'backlog', 'critical', NULL, NULL, NULL, '2026-03-05 23:11:39', '2026-06-12 10:23:03', NULL, 'eb2c4463ff919778f8bdc5a76a8c2546', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXD5W32VCV5YZY3NX0', 'epic', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Tycoon Bookmark', 'Tycoon is the v0.2 bookmark: small business owner, existing in the Krenn System. Zero investigation content. Tycoon = aspiration not starting state. Workshop decisions #4, #19, #20. Broad economic verb vocabulary serving all careers. Auto-generated apartment reflecting wealth + cultural context. CK3-style bookmark selection flow.', 'backlog', 'high', NULL, NULL, NULL, '2026-03-05 23:11:42', '2026-06-12 10:23:03', NULL, '1830a6e517710899abeb534c6445db64', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXD5W32VCV5YZY3NX0', 'epic', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Tycoon Bookmark', 'Tycoon is the v0.2 bookmark: small business owner, existing in the Krenn System. Zero investigation content. Tycoon = aspiration not starting state. Workshop decisions #4, #19, #20. Broad economic verb vocabulary serving all careers. Auto-generated apartment reflecting wealth + cultural context. CK3-style bookmark selection flow.
|
||
|
||
Parked in gameplay backlog per cascade refocus 2026-06-12; bookmark concept preserved for post-cascade game-making.', 'backlog', 'high', NULL, NULL, NULL, '2026-03-05 23:11:42', '2026-06-12 10:23:03', NULL, '004369aee4878e3aa3d419f3f1bcd73e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXE0VWDHVQTXPVPEW0', 'epic', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Character Creation', 'CK3-style character creation: skills + bookmark selection. Full cosmetic customisation (hair, clothing, colours — workshop decision #11). Culture implicit in starting location (decision #16). No family/culture/religion sliders in creation — those are deferred. Decision #2.', 'backlog', 'high', NULL, NULL, NULL, '2026-03-05 23:11:48', '2026-06-12 10:23:03', NULL, 'a4c743376eeb5a1ba1cbed47deac12c1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXE0VWDHVQTXPVPEW0', 'epic', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Character Creation', 'CK3-style character creation: skills + bookmark selection. Full cosmetic customisation (hair, clothing, colours — workshop decision #11). Culture implicit in starting location (decision #16). No family/culture/religion sliders in creation — those are deferred. Decision #2.
|
||
|
||
Parked in gameplay backlog per cascade refocus 2026-06-12; bookmark-selection flow preserved — cosmetic customisation tracked separately under Phase 5 (T-619).', 'backlog', 'high', NULL, NULL, NULL, '2026-03-05 23:11:48', '2026-06-12 10:23:03', NULL, '57f07a5f9d963bde7eccd2fddbef96dc', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ65H50N3XJKJ3F5XM', 'epic', '06FBPPMMF7HS6FWRYAKMECTXX0', 'World Feel', 'The world is quietly responsive, not indifferent. Gradient of caring by social proximity — world doesn''t care globally but notices locally. Dual-scale consequence model: Rimworld sharp events (crises, reversals) + DF slow accumulation (reputation, debt, relationship erosion). Setting delivery via both visual and insert layers in parallel. Workshop decisions #10, #12, #13, #21.', 'backlog', 'high', NULL, NULL, NULL, '2026-03-05 23:11:59', '2026-06-12 10:23:03', NULL, '8d6818d100f2017e9bf2cb033291fa53', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ65H50N3XJKJ3F5XM', 'epic', '06FBPPMMF7HS6FWRYAKMECTXX0', 'World Feel', 'The world is quietly responsive, not indifferent. Gradient of caring by social proximity — world doesn''t care globally but notices locally. Dual-scale consequence model: Rimworld sharp events (crises, reversals) + DF slow accumulation (reputation, debt, relationship erosion). Setting delivery via both visual and insert layers in parallel. Workshop decisions #10, #12, #13, #21.
|
||
|
||
Parked in gameplay backlog per cascade refocus 2026-06-12; world-feel decisions preserved for post-cascade game-making.', 'backlog', 'high', NULL, NULL, NULL, '2026-03-05 23:11:59', '2026-06-12 10:23:03', NULL, '7271e54ba535dfdedd73d4f22a058a5a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZHHSBPQS9VB8S7D5M', 'story', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Full character customisation', 'Cosmetic customisation: hair, clothing, colours. Decision #11. Separate from skills/bookmark — aesthetic only. Question open: do creation choices trace into the generated apartment? (Q-WTF-040).', 'backlog', 'high', NULL, 'client', NULL, '2026-03-05 23:12:52', '2026-06-12 10:23:03', NULL, 'fe1f1ccdd1755cde45c229df7fc25a77', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZHHSBPQS9VB8S7D5M', 'story', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Full character customisation', 'Cosmetic customisation: hair, clothing, colours. Decision #11. Separate from skills/bookmark — aesthetic only. Question open: do creation choices trace into the generated apartment? (Q-WTF-040).
|
||
|
||
Parked under Phase 5 epic per cascade refocus 2026-06-12; character-visuals customisation resumes with player rendering (overlaps T-694).', 'backlog', 'high', NULL, 'client', NULL, '2026-03-05 23:12:52', '2026-06-12 10:23:03', NULL, '5781aff24e5ef5f6789a1d7ae171bc40', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZBZHXAK3DYTK1C19R', 'story', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Relationship formation system', 'NPC-to-NPC and NPC-to-player relationships form through: Sims-style direct interaction + Rimworld-style shared adversity. Decision #17. Relationships must be readable from the outside. Codify for systems. Decision #18: prove relationships readable before layering narrative depth.', 'backlog', 'high', NULL, 'server', NULL, '2026-03-05 23:13:08', '2026-06-12 10:23:03', NULL, '675b52e99220f082d111cec3d9ddbf5f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZBZHXAK3DYTK1C19R', 'story', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Relationship formation system', 'NPC-to-NPC and NPC-to-player relationships form through: Sims-style direct interaction + Rimworld-style shared adversity. Decision #17. Relationships must be readable from the outside. Codify for systems. Decision #18: prove relationships readable before layering narrative depth.
|
||
|
||
Parked under Phase 6 epic per cascade refocus 2026-06-12 (previous parent T-607 cancelled); relationship-formation requirement preserved for the NPC layer.', 'backlog', 'high', NULL, 'server', NULL, '2026-03-05 23:13:08', '2026-06-12 10:23:03', NULL, '5b91cc368402eedd0da8f5e0e245474b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXK4NDX3Y242QK7BC8', 'story', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Quietly responsive world', 'The world notices locally but doesn''t care globally. Gradient of caring based on social proximity. Decision #10. Primary social contacts develop responsiveness over time. Indifferent world is wrong — quietly responsive world is right. Implementation: proximity-weighted NPC attention and reaction systems.', 'backlog', 'high', NULL, 'server', NULL, '2026-03-05 23:13:22', '2026-06-12 10:23:03', NULL, 'be5e2012a0ee6dd1a07398ec2d1b261d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXK4NDX3Y242QK7BC8', 'story', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Quietly responsive world', 'The world notices locally but doesn''t care globally. Gradient of caring based on social proximity. Decision #10. Primary social contacts develop responsiveness over time. Indifferent world is wrong — quietly responsive world is right. Implementation: proximity-weighted NPC attention and reaction systems.
|
||
|
||
Parked under Phase 6 epic per cascade refocus 2026-06-12; quietly-responsive-world requirement preserved for the NPC layer.', 'backlog', 'high', NULL, 'server', NULL, '2026-03-05 23:13:22', '2026-06-12 10:23:03', NULL, 'fd6c2a9e3e2b1ca57462596be2ff799a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXJDMPQNP05JFD2P6G', 'story', '06FBPPMZNNEV052DBYYY3A897C', 'Voice pipeline: GPU acceleration (ROCm/Vulkan)', 'sr-voice has cargo features for rocm/vulkan/cuda/metal but builds CPU-only (~13 t/s). Enable after code stable. GPU would reach 50+ t/s. LIBCLANG_PATH already in Makefile.', 'backlog', 'low', NULL, 'server', NULL, '2026-03-07 18:19:29', '2026-06-12 10:23:03', NULL, '1904c59cef77c9a6db8bb047f9a8ada7', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXJDMPQNP05JFD2P6G', 'story', '06FBPPMZNNEV052DBYYY3A897C', 'Voice pipeline: GPU acceleration (ROCm/Vulkan)', 'sr-voice has cargo features for rocm/vulkan/cuda/metal but builds CPU-only (~13 t/s). Enable after code stable. GPU would reach 50+ t/s. LIBCLANG_PATH already in Makefile.
|
||
|
||
Re-homed under maintenance per cascade refocus 2026-06-12; GPU build-feature enablement is infra hygiene on the existing voice pipeline.', 'backlog', 'low', NULL, 'server', NULL, '2026-03-07 18:19:29', '2026-06-12 10:23:03', NULL, '169b8c3c22eeba4ed8e0dbf1042364bc', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW36DF5F95406ETRGR', 'story', '06FBPPMZNNEV052DBYYY3A897C', 'Server: extract platform abstraction module when second consumer appears', 'Trigger ticket: when any server module beyond voice/hardware.rs needs OS-dependent info (CPU, memory, battery, GPU), extract shared platform queries into server/src/platform.rs. Currently all OS detection lives in server/src/voice/hardware.rs (sysinfo crate, on_battery(), VRAM probes, available_parallelism). Single consumer, no duplication — no action needed until a second consumer appears. Trigger conditions: (1) a second system needs CPU/memory info independently of voice pipeline, (2) battery detection needed outside voice scaling (e.g. tick rate throttling), (3) server exposes system info over IPC (multiplayer diagnostics). Extraction is ~30 minutes: pull on_battery(), probe_current_free(), sysinfo calls into platform.rs, leave voice-specific scaling logic in hardware.rs.', 'backlog', 'low', NULL, 'server', NULL, '2026-03-13 09:49:07', '2026-06-12 10:23:03', NULL, 'd2f3dc06ebad5f9c538aa09653b33812', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW36DF5F95406ETRGR', 'story', '06FBPPMZNNEV052DBYYY3A897C', 'Server: extract platform abstraction module when second consumer appears', 'Trigger ticket: when any server module beyond voice/hardware.rs needs OS-dependent info (CPU, memory, battery, GPU), extract shared platform queries into server/src/platform.rs. Currently all OS detection lives in server/src/voice/hardware.rs (sysinfo crate, on_battery(), VRAM probes, available_parallelism). Single consumer, no duplication — no action needed until a second consumer appears. Trigger conditions: (1) a second system needs CPU/memory info independently of voice pipeline, (2) battery detection needed outside voice scaling (e.g. tick rate throttling), (3) server exposes system info over IPC (multiplayer diagnostics). Extraction is ~30 minutes: pull on_battery(), probe_current_free(), sysinfo calls into platform.rs, leave voice-specific scaling logic in hardware.rs.
|
||
|
||
Re-homed under maintenance per cascade refocus 2026-06-12; trigger conditions unchanged.', 'backlog', 'low', NULL, 'server', NULL, '2026-03-13 09:49:07', '2026-06-12 10:23:03', NULL, '7aa6eca7e7350f0992f285fa7325786a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY4CMF4W57DCQASQNW', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Mid-sprint ticket creation protocol for team agents', 'When team agents discover new work during a sprint (like #661 zone-type templates in Sprint 26), they should message the lead immediately for retroactive ticket creation rather than just doing the work uncaptured. Document this in the sprint-start skill agent spawn prompt and/or team-patterns.md.', 'backlog', 'low', NULL, 'meta', NULL, '2026-03-13 11:37:34', '2026-06-12 10:23:03', NULL, 'a40b8568dfffec237478189f140ba8a9', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY4CMF4W57DCQASQNW', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Mid-sprint ticket creation protocol for team agents', 'When team agents discover new work during a sprint (like #661 zone-type templates in Sprint 26), they should message the lead immediately for retroactive ticket creation rather than just doing the work uncaptured. Document this in the sprint-start skill agent spawn prompt and/or team-patterns.md.
|
||
|
||
Re-homed under maintenance per cascade refocus 2026-06-12; recast sprint protocol for kanban/batch mode — functional requirement preserved.', 'backlog', 'low', NULL, 'meta', NULL, '2026-03-13 11:37:34', '2026-06-12 10:23:03', NULL, '9f08d77f1d757206ac431d91820a63b8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRX1PW1RXYRBNRHVNYW', 'story', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Gate network travel planner — interactive route-finding overlay on the star map insert, showing hop paths between systems with transit time estimates and corridor information', NULL, 'backlog', 'medium', NULL, 'client', NULL, '2026-03-15 10:20:07', '2026-06-12 10:23:03', NULL, 'd5ed14ff7a71cd5357bd3cf8b127d639', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRX1PW1RXYRBNRHVNYW', 'story', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Gate network travel planner — interactive route-finding overlay on the star map insert, showing hop paths between systems with transit time estimates and corridor information', 'Parked in gameplay backlog per cascade refocus 2026-06-12; star-map travel planner preserved for when in-game travel exists.', 'backlog', 'medium', NULL, 'client', NULL, '2026-03-15 10:20:07', '2026-06-12 10:23:03', NULL, '29e604f79ca25dbe8ce14536932429c1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZDYCH1YRQNVN0B2FC', 'story', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Apartment generator logic (server)', 'Server implementation: apartment generator takes economic position (from #615 tycoon starting state) + cultural context (from #679 location-to-culture resolution) + aesthetic taste trait. Produces apartment tile layout, furniture placement, and item set. Decision D-136 (First Settled Reach moment: apartment + insert activation). Decision D-137 (generator: structural and cosmetic variety). Blocked by: #615 (tycoon starting state), #679 (culture resolution).', 'backlog', 'high', NULL, 'server', NULL, '2026-03-17 07:06:30', '2026-06-12 10:23:03', NULL, '7c945106cab77d0f2acf1814f95c4bca', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZDYCH1YRQNVN0B2FC', 'story', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Apartment generator logic (server)', 'Server implementation: apartment generator takes economic position (from #615 tycoon starting state) + cultural context (from #679 location-to-culture resolution) + aesthetic taste trait. Produces apartment tile layout, furniture placement, and item set. Decision D-136 (First Settled Reach moment: apartment + insert activation). Decision D-137 (generator: structural and cosmetic variety). Blocked by: #615 (tycoon starting state), #679 (culture resolution).
|
||
|
||
Parked under Phase 6 epic per cascade refocus 2026-06-12; interior/furniture generation is room-level detail — pairs with T-682 (parked gameplay).', 'backlog', 'high', NULL, 'server', NULL, '2026-03-17 07:06:30', '2026-06-12 10:23:03', NULL, '47edbff461c36e23bbfdaf07a48c8cad', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYXPA202KSKKJ15KZ8', 'story', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Character creation screen', 'Full character creation UI using the game UI kit and widget system — not a debug/test wrapper. This is the production character creation screen that players use at game start.
|
||
|
||
Built on the 3D CharacterVisual compositor (#693). Uses the same UI kit, widgets, and interaction patterns as the rest of the game UI.
|
||
|
||
Features:
|
||
- Body type selector (11 types)
|
||
- Head template browser (curated library)
|
||
- Hair, facial hair, eyebrow pickers with preview
|
||
- Skin tone selector (9-tone palette)
|
||
- Clothing and accessory slots
|
||
- Color customization per recolorable region
|
||
- Live 3D preview with camera orbit (frontal default per D-158, full rotation per D-155)
|
||
- Keyboard navigation (tab/arrow/enter/esc)
|
||
- Randomize button
|
||
- Standalone scene entry point (can be launched independently for artist review)
|
||
- Feeds CharacterVisualDescriptor into new game flow on confirm
|
||
|
||
Decisions: D-134 (full customization), D-146 (tile-scale heavy zoom preview), D-155 (editor rotation), D-158 (frontal camera default)
|
||
Blocked by: #693 (compositor)', 'backlog', 'high', NULL, 'client', NULL, '2026-03-17 08:21:47', '2026-06-12 10:23:03', NULL, 'ed3c0ae9f3ab466ad63d40c3192d644e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYXPA202KSKKJ15KZ8', 'story', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Character creation screen', 'Full character creation UI using the game UI kit and widget system — not a debug/test wrapper. This is the production character creation screen that players use at game start.
|
||
|
||
Built on the 3D CharacterVisual compositor (#693). Uses the same UI kit, widgets, and interaction patterns as the rest of the game UI.
|
||
|
||
Features:
|
||
- Body type selector (11 types)
|
||
- Head template browser (curated library)
|
||
- Hair, facial hair, eyebrow pickers with preview
|
||
- Skin tone selector (9-tone palette)
|
||
- Clothing and accessory slots
|
||
- Color customization per recolorable region
|
||
- Live 3D preview with camera orbit (frontal default per D-158, full rotation per D-155)
|
||
- Keyboard navigation (tab/arrow/enter/esc)
|
||
- Randomize button
|
||
- Standalone scene entry point (can be launched independently for artist review)
|
||
- Feeds CharacterVisualDescriptor into new game flow on confirm
|
||
|
||
Decisions: D-134 (full customization), D-146 (tile-scale heavy zoom preview), D-155 (editor rotation), D-158 (frontal camera default)
|
||
Blocked by: #693 (compositor)
|
||
|
||
Parked under Phase 5 epic per cascade refocus 2026-06-12; creation screen ships with player control and character rendering.', 'backlog', 'high', NULL, 'client', NULL, '2026-03-17 08:21:47', '2026-06-12 10:23:03', NULL, '687fce3729c26231a6d9635dfcbfc6ca', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWQEZ7D8AX2PRS2FWM', 'task', '06FB0TNSRXX29H5X0EB0F0GBW4', 'LOD crowd rendering research — performance-driven strategy for 400+ characters', 'Research and prototype LOD strategy for 400+ simultaneous characters on screen (crowd scenes, protests, battles).\n\nCurrent budget: 80 NPCs at full detail. This ticket defines the path to 400+.\n\nKey constraints from workshop:\n- LOD degradation is performance-driven, NOT distance/count threshold\n- Degradation is proactive (triggers on PROJECTED viewport character count, not measured frame drop — reactive causes hitching)\n- Progressive from player outward: furthest degrade first (full mesh -> simplified mesh -> billboard)\n- When paused: restore full detail on all characters\n- At billboard tier: body size tier and dominant clothing color must remain visually distinct\n- Outline baked into impostor sprite at billboard tier\n\nDeliverable: technical spec + prototype result. Does not produce shippable code.\n\nNot in Sprint 28 — backlog for when crowd-scale systems begin.', 'backlog', 'medium', NULL, 'client', NULL, '2026-03-17 17:48:12', '2026-06-12 10:23:03', NULL, 'c569b5b1c7c5896c9d0678c8efa405d3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWQEZ7D8AX2PRS2FWM', 'task', '06FB0TNSRXX29H5X0EB0F0GBW4', 'LOD crowd rendering research — performance-driven strategy for 400+ characters', 'Research and prototype LOD strategy for 400+ simultaneous characters on screen (crowd scenes, protests, battles).\n\nCurrent budget: 80 NPCs at full detail. This ticket defines the path to 400+.\n\nKey constraints from workshop:\n- LOD degradation is performance-driven, NOT distance/count threshold\n- Degradation is proactive (triggers on PROJECTED viewport character count, not measured frame drop — reactive causes hitching)\n- Progressive from player outward: furthest degrade first (full mesh -> simplified mesh -> billboard)\n- When paused: restore full detail on all characters\n- At billboard tier: body size tier and dominant clothing color must remain visually distinct\n- Outline baked into impostor sprite at billboard tier\n\nDeliverable: technical spec + prototype result. Does not produce shippable code.\n\nNot in Sprint 28 — backlog for when crowd-scale systems begin.
|
||
|
||
Parked under Phase 5 epic per cascade refocus 2026-06-12; crowd-rendering research resumes with in-world rendering work.', 'backlog', 'medium', NULL, 'client', NULL, '2026-03-17 17:48:12', '2026-06-12 10:23:03', NULL, '68e3c19b17316e74a3a77812bd20f63e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY6TPACQSYVFGDEMPR', 'story', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Scar overlay system — per-segment scar meshes or textures', 'Visual overlay system for scars on character bodies. Scars are per-segment (leveraging the 18-segment body architecture for placement). Each scar is a visual modification to a specific body segment — either a decal/texture overlay or a small mesh overlay attached to the segment. Requirements: scars placed per body segment, multiple scars per character, persist across clothing changes (visible on exposed segments), hidden under clothing via coverage system, recolorable via toon shader for skin tone matching. Depends on compositor (#704) and body segments (#707) — both done. Architecture uses per-segment addressability from D-160.', 'backlog', 'medium', NULL, 'visual', NULL, '2026-03-22 14:30:36', '2026-06-12 10:23:03', NULL, '9adb71b9124bbc8c9db1ebe65acfbe61', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY6TPACQSYVFGDEMPR', 'story', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Scar overlay system — per-segment scar meshes or textures', 'Visual overlay system for scars on character bodies. Scars are per-segment (leveraging the 18-segment body architecture for placement). Each scar is a visual modification to a specific body segment — either a decal/texture overlay or a small mesh overlay attached to the segment. Requirements: scars placed per body segment, multiple scars per character, persist across clothing changes (visible on exposed segments), hidden under clothing via coverage system, recolorable via toon shader for skin tone matching. Depends on compositor (#704) and body segments (#707) — both done. Architecture uses per-segment addressability from D-160.
|
||
|
||
Parked under Phase 5 epic per cascade refocus 2026-06-12; character-visuals leftover preserved.', 'backlog', 'medium', NULL, 'visual', NULL, '2026-03-22 14:30:36', '2026-06-12 10:23:03', NULL, '4645267811b9c4979915f196f771d988', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWS9B34T2HPJCYMGK0', 'story', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Tattoo overlay system — per-segment tattoo textures', 'Visual overlay system for tattoos on character bodies. Tattoos are per-segment texture overlays with their own recolor masks for ink color variation. Requirements: tattoos placed per body segment, multiple tattoos per character, persist across clothing changes (visible on exposed segments), hidden under clothing via coverage system, recolorable via multi-region mask for multi-color tattoos. May share implementation approach with scar system (#715). Architecture uses per-segment addressability from D-160.', 'backlog', 'medium', NULL, 'visual', NULL, '2026-03-22 14:30:42', '2026-06-12 10:23:03', NULL, 'ae7e0e08a8627d75a9949bb4ce978001', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWS9B34T2HPJCYMGK0', 'story', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Tattoo overlay system — per-segment tattoo textures', 'Visual overlay system for tattoos on character bodies. Tattoos are per-segment texture overlays with their own recolor masks for ink color variation. Requirements: tattoos placed per body segment, multiple tattoos per character, persist across clothing changes (visible on exposed segments), hidden under clothing via coverage system, recolorable via multi-region mask for multi-color tattoos. May share implementation approach with scar system (#715). Architecture uses per-segment addressability from D-160.
|
||
|
||
Parked under Phase 5 epic per cascade refocus 2026-06-12; character-visuals leftover preserved.', 'backlog', 'medium', NULL, 'visual', NULL, '2026-03-22 14:30:42', '2026-06-12 10:23:03', NULL, '16d146e23b58cc8467f6e0ca59151343', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWEDR71D90K594P7DG', 'story', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Visible injury overlay system — per-segment injury visualization', 'Visual overlay system for injuries on character bodies. Injuries are per-segment visual states showing damage (bruises, cuts, burns) and healing progression. Requirements: injuries placed per body segment, severity/type affects visual appearance, healing progression over time changes the overlay, hidden under clothing via coverage system, interacts with amputation system (injury on a removed limb is moot). Depends on compositor (#704) and body segments (#707) — both done. Architecture uses per-segment addressability from D-160 and limb removal capability.', 'backlog', 'medium', NULL, 'visual', NULL, '2026-03-22 14:30:49', '2026-06-12 10:23:03', NULL, 'acf72109f46ac3786b587751e34a7133', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWEDR71D90K594P7DG', 'story', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Visible injury overlay system — per-segment injury visualization', 'Visual overlay system for injuries on character bodies. Injuries are per-segment visual states showing damage (bruises, cuts, burns) and healing progression. Requirements: injuries placed per body segment, severity/type affects visual appearance, healing progression over time changes the overlay, hidden under clothing via coverage system, interacts with amputation system (injury on a removed limb is moot). Depends on compositor (#704) and body segments (#707) — both done. Architecture uses per-segment addressability from D-160 and limb removal capability.
|
||
|
||
Parked under Phase 5 epic per cascade refocus 2026-06-12; character-visuals leftover preserved.', 'backlog', 'medium', NULL, 'visual', NULL, '2026-03-22 14:30:49', '2026-06-12 10:23:03', NULL, '66e1c70cdf25354a92e8952bf92c32c2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY5J5AWB356FT9WK0M', 'story', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Accessory slot filtering — _get_accessory_ids_for_slot() ignores slot param', '_get_accessory_ids_for_slot(slot) accepts a slot parameter but returns all accessories unfiltered. Every accessory slot shows the full catalogue. Should filter by slot-appropriate prefix (hat_*, goggles_*, etc.) matching the clothing tab''s approach. Currently invisible with placeholder assets but will be wrong when real accessories are added.', 'backlog', 'low', 'client', NULL, NULL, '2026-03-22 16:33:07', '2026-06-12 10:23:03', NULL, 'e248cf9c02444e3ce27dcb5666040d3e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY5J5AWB356FT9WK0M', 'story', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Accessory slot filtering — _get_accessory_ids_for_slot() ignores slot param', '_get_accessory_ids_for_slot(slot) accepts a slot parameter but returns all accessories unfiltered. Every accessory slot shows the full catalogue. Should filter by slot-appropriate prefix (hat_*, goggles_*, etc.) matching the clothing tab''s approach. Currently invisible with placeholder assets but will be wrong when real accessories are added.
|
||
|
||
Parked under Phase 5 epic per cascade refocus 2026-06-12; latent creation-UI bug fixed alongside character-visuals leftovers.', 'backlog', 'low', 'client', NULL, NULL, '2026-03-22 16:33:07', '2026-06-12 10:23:03', NULL, 'b8b7a3fb5061192a31f267b490569b39', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYS8J5T5CV3EKNPJMR', 'task', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Adopt auto-sizing label pattern for dynamic text', 'Evaluate GodotFontAutoSizeLabels (https://github.com/LuisEscorza/GodotFontAutoSizeLabels) for handling text that must fit a fixed container. We will hit this with: NPC name labels, item names in grids, clothing/hair button labels, dialogue boxes, any server-generated text rendered in fixed UI elements. Adopt the pattern early (either this plugin or our own implementation) before overflow bugs accumulate.', 'backlog', 'low', NULL, 'client', NULL, '2026-03-23 17:42:32', '2026-06-12 10:23:03', NULL, '951b59ccff83e6b34252e3a5b4d750b5', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYS8J5T5CV3EKNPJMR', 'task', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Adopt auto-sizing label pattern for dynamic text', 'Evaluate GodotFontAutoSizeLabels (https://github.com/LuisEscorza/GodotFontAutoSizeLabels) for handling text that must fit a fixed container. We will hit this with: NPC name labels, item names in grids, clothing/hair button labels, dialogue boxes, any server-generated text rendered in fixed UI elements. Adopt the pattern early (either this plugin or our own implementation) before overflow bugs accumulate.
|
||
|
||
Parked under Phase 5 epic per cascade refocus 2026-06-12; adopt the pattern when gameplay UI surfaces are built.', 'backlog', 'low', NULL, 'client', NULL, '2026-03-23 17:42:32', '2026-06-12 10:23:03', NULL, 'a0fb59fc7e5fb140cc7377d2b3d0f8cd', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXJ3WZ2AQMWBNB4D2W', 'task', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Install Godot Icons Fonts addon for UI development', 'Godot Icons Fonts (https://github.com/rakugoteam/Godot-Icons-Fonts) — searchable icon font library (FontAwesome, Material Icons, etc.) directly in the Godot editor. MIT. Saves time hunting for individual icon assets during UI development. Install from asset library. Use for: HUD icons, status indicators, navigation symbols, button icons, inventory categories.', 'backlog', 'low', NULL, 'client', NULL, '2026-03-23 18:19:22', '2026-06-12 10:23:03', NULL, '52acb96e3d678b612814b021d7f2a1a8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXJ3WZ2AQMWBNB4D2W', 'task', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Install Godot Icons Fonts addon for UI development', 'Godot Icons Fonts (https://github.com/rakugoteam/Godot-Icons-Fonts) — searchable icon font library (FontAwesome, Material Icons, etc.) directly in the Godot editor. MIT. Saves time hunting for individual icon assets during UI development. Install from asset library. Use for: HUD icons, status indicators, navigation symbols, button icons, inventory categories.
|
||
|
||
Parked under Phase 5 epic per cascade refocus 2026-06-12; install when HUD/gameplay UI development resumes.', 'backlog', 'low', NULL, 'client', NULL, '2026-03-23 18:19:22', '2026-06-12 10:23:03', NULL, '3b8b8c17b1d6894cfc7f2551109d4682', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYKBBN824V9KB9NEN0', 'task', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Add resolution parameter to screenshot test config', 'Extend the character creator screenshot test config JSON with a resolution field. The system sets viewport size before capturing, enabling automated visual regression across common resolutions (1080p, 1440p, 4K, ultrawide, Steam Deck 800p). Batch script iterates the manifest body types × resolutions for full coverage. No plugin needed — just OS.window_size or viewport size override. Inspired by Project Resolution plugin (https://github.com/Danim3D/Godot-4-Plugin-Project-Resolution) but built into our existing test infrastructure.', 'backlog', 'medium', NULL, 'client', NULL, '2026-03-23 18:27:51', '2026-06-12 10:23:03', NULL, 'aecb1b1d6a5491ce4705a0ec2454d853', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYKBBN824V9KB9NEN0', 'task', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Add resolution parameter to screenshot test config', 'Extend the character creator screenshot test config JSON with a resolution field. The system sets viewport size before capturing, enabling automated visual regression across common resolutions (1080p, 1440p, 4K, ultrawide, Steam Deck 800p). Batch script iterates the manifest body types × resolutions for full coverage. No plugin needed — just OS.window_size or viewport size override. Inspired by Project Resolution plugin (https://github.com/Danim3D/Godot-4-Plugin-Project-Resolution) but built into our existing test infrastructure.
|
||
|
||
Parked under Phase 5 epic per cascade refocus 2026-06-12; functional requirement (multi-resolution visual regression) preserved — resumes with character rendering work.', 'backlog', 'medium', NULL, 'client', NULL, '2026-03-23 18:27:51', '2026-06-12 10:23:03', NULL, 'e8f991a475031b43cd083b4a1b1c995a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZGD6VYZM7BT6PC5WM', 'task', '06FBPPMMF7HS6FWRYAKMECTXX0', 'First-launch install wizard for distribution', 'Evaluate Godot4xInstallWizard (https://github.com/untamedlabs/Godot4xInstallWizard) for first-launch experience: EULA acceptance, initial settings (resolution, audio, controls), install path selection. Needed when packaging for Steam or standalone distribution. Low priority until release preparation begins.', 'backlog', 'low', NULL, 'client', NULL, '2026-03-23 18:31:35', '2026-06-12 10:23:03', NULL, '04bc75bb1b687c91751a9d7292536a12', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZGD6VYZM7BT6PC5WM', 'task', '06FBPPMMF7HS6FWRYAKMECTXX0', 'First-launch install wizard for distribution', 'Evaluate Godot4xInstallWizard (https://github.com/untamedlabs/Godot4xInstallWizard) for first-launch experience: EULA acceptance, initial settings (resolution, audio, controls), install path selection. Needed when packaging for Steam or standalone distribution. Low priority until release preparation begins.
|
||
|
||
Parked under post-cascade gameplay/release backlog per cascade refocus 2026-06-12; functional requirement preserved for release preparation.', 'backlog', 'low', NULL, 'client', NULL, '2026-03-23 18:31:35', '2026-06-12 10:23:03', NULL, 'fbaf3da1d89d8b99e87bcf7f3a44fc55', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXBTTPTBFJN0DGX2YC', 'task', '06FBPPMMF7HS6FWRYAKMECTXX0', 'License and attribution screen in settings menu', 'Add a licenses/credits screen accessible from the main menu settings. Must display all third-party licenses: Quaternius (CC0), Godot engine, any adopted plugins (MIT), font licenses, audio assets. Pattern reference: godot-licensing (https://github.com/nathanfranke/godot-licensing) — auto-collects license info. We don''t need the plugin but need the pattern: scan for LICENSE files, Godot''s built-in Engine.get_license_info(), and our own attribution list. Legal requirement for distribution.', 'backlog', 'medium', NULL, 'client', NULL, '2026-03-23 18:33:04', '2026-06-12 10:23:03', NULL, '2bd2d6790d3004cb8f03393af5ddaf99', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXBTTPTBFJN0DGX2YC', 'task', '06FBPPMMF7HS6FWRYAKMECTXX0', 'License and attribution screen in settings menu', 'Add a licenses/credits screen accessible from the main menu settings. Must display all third-party licenses: Quaternius (CC0), Godot engine, any adopted plugins (MIT), font licenses, audio assets. Pattern reference: godot-licensing (https://github.com/nathanfranke/godot-licensing) — auto-collects license info. We don''t need the plugin but need the pattern: scan for LICENSE files, Godot''s built-in Engine.get_license_info(), and our own attribution list. Legal requirement for distribution.
|
||
|
||
Parked under post-cascade gameplay/release backlog per cascade refocus 2026-06-12; legal attribution requirement preserved for release preparation.', 'backlog', 'medium', NULL, 'client', NULL, '2026-03-23 18:33:04', '2026-06-12 10:23:03', NULL, '3206a8cd8f6a79b0ce11f22da0e96e4d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY35YGQ1PGBXE4B7KM', 'task', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Konami code easter egg', 'Up up down down left right left right B A. Because reasons. https://github.com/aravikusu/konamicode — reference implementation. Trigger: unlock debug panel in release builds, or something fun.', 'backlog', 'low', NULL, 'client', NULL, '2026-03-23 18:38:37', '2026-06-12 10:23:04', NULL, 'f0543594e7aa617efff4d564ca41e7cc', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY35YGQ1PGBXE4B7KM', 'task', '06FBPPMMF7HS6FWRYAKMECTXX0', 'Konami code easter egg', 'Up up down down left right left right B A. Because reasons. https://github.com/aravikusu/konamicode — reference implementation. Trigger: unlock debug panel in release builds, or something fun.
|
||
|
||
Parked under post-cascade gameplay backlog per cascade refocus 2026-06-12; preserved, not cancelled.', 'backlog', 'low', NULL, 'client', NULL, '2026-03-23 18:38:37', '2026-06-12 10:23:04', NULL, 'fd91252b7ed5cbd0204a4d9b1cfa0a1e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWJAKQQ33BNCFZGV3W', 'task', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Minimap rendering from server exploration data', 'The minimap needs to render from server-sent exploration and visibility data. No existing Godot minimap plugin fits because our information boundary is server-authoritative. Architecture: server sends explored tile states (unexplored/explored/visible) as part of ObserverSnapshot. Client renders a top-down 2D minimap from this data — fog for unexplored, dim for explored-not-visible, lit for currently visible. Player position centered. Needs a dedicated data stream or section in the snapshot for minimap tile states. Reference: the existing 2D fog_state.gd has the rendering patterns (texture from tile data), but the 3D minimap may use a separate overhead Camera3D in a SubViewport instead.', 'backlog', 'medium', NULL, 'client', NULL, '2026-03-23 18:48:16', '2026-06-12 10:23:04', NULL, '03a0cee44b63f54f36f1298d30b696d2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWJAKQQ33BNCFZGV3W', 'task', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Minimap rendering from server exploration data', 'The minimap needs to render from server-sent exploration and visibility data. No existing Godot minimap plugin fits because our information boundary is server-authoritative. Architecture: server sends explored tile states (unexplored/explored/visible) as part of ObserverSnapshot. Client renders a top-down 2D minimap from this data — fog for unexplored, dim for explored-not-visible, lit for currently visible. Player position centered. Needs a dedicated data stream or section in the snapshot for minimap tile states. Reference: the existing 2D fog_state.gd has the rendering patterns (texture from tile data), but the 3D minimap may use a separate overhead Camera3D in a SubViewport instead.
|
||
|
||
Parked under Phase 5 epic per cascade refocus 2026-06-12; server-authoritative minimap requirement preserved — resumes with player rendering.', 'backlog', 'medium', NULL, 'client', NULL, '2026-03-23 18:48:16', '2026-06-12 10:23:04', NULL, 'f4e0d43c19fa89cdf89e91357498bfe5', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXGNK7WHD9DEGPY4BC', 'task', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Nested tooltip system for information layering', 'Implement nested/recursive tooltips for the information-dense UI. Reference: Nested-Tooltips (https://github.com/duzychri/Nested-Tooltips). Pattern: hover over text → tooltip appears → hover over a keyword in the tooltip → nested tooltip explains that keyword. Use cases: NPC names (→ disposition, role), items (→ stats → stat modifier explanations), zone names (→ zone type, danger level), factions (→ relationship, territory). This is core to the asymmetric information design — tooltips reveal what your character KNOWS, with depth proportional to familiarity. Study the plugin for the recursive hover detection pattern, implement with our diegetic UI aesthetic.', 'backlog', 'medium', NULL, 'client', NULL, '2026-03-23 18:49:04', '2026-06-12 10:23:04', NULL, 'd003693816cfa6ceb1c8f4f3332da2dc', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXGNK7WHD9DEGPY4BC', 'task', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Nested tooltip system for information layering', 'Implement nested/recursive tooltips for the information-dense UI. Reference: Nested-Tooltips (https://github.com/duzychri/Nested-Tooltips). Pattern: hover over text → tooltip appears → hover over a keyword in the tooltip → nested tooltip explains that keyword. Use cases: NPC names (→ disposition, role), items (→ stats → stat modifier explanations), zone names (→ zone type, danger level), factions (→ relationship, territory). This is core to the asymmetric information design — tooltips reveal what your character KNOWS, with depth proportional to familiarity. Study the plugin for the recursive hover detection pattern, implement with our diegetic UI aesthetic.
|
||
|
||
Parked under Phase 5 epic per cascade refocus 2026-06-12; asymmetric-information tooltip requirement preserved — resumes with gameplay UI work.', 'backlog', 'medium', NULL, 'client', NULL, '2026-03-23 18:49:04', '2026-06-12 10:23:04', NULL, 'c93be2af1a2358d4f53a341e64726ada', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXY24QTYKWPERE52X4', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Settings and input system — keybinds, save browser, cursors, controller', 'Unified design and implementation pass for player-facing settings and input: (a) Key binding remapper with save/load. (b) Save browser with thumbnails and metadata. (c) Context-sensitive cursors (examine, talk, use, attack, walk). (d) Controller/gamepad support with radial menus. Design all four together in Frame0 for visual consistency, then implement as a cohesive system. These share UI patterns (settings panels, modal dialogs, input feedback) and should not be built independently.', 'backlog', 'medium', NULL, 'client', NULL, '2026-03-23 18:53:39', '2026-06-12 10:23:04', NULL, '2d10d4586473fd67b035a7cb57d2ec47', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXY24QTYKWPERE52X4', 'epic', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Settings and input system — keybinds, save browser, cursors, controller', 'Unified design and implementation pass for player-facing settings and input: (a) Key binding remapper with save/load. (b) Save browser with thumbnails and metadata. (c) Context-sensitive cursors (examine, talk, use, attack, walk). (d) Controller/gamepad support with radial menus. Design all four together in Frame0 for visual consistency, then implement as a cohesive system. These share UI patterns (settings panels, modal dialogs, input feedback) and should not be built independently.
|
||
|
||
Parked under Phase 5 epic per cascade refocus 2026-06-12; unified settings/input design requirement preserved — resumes with player control work.', 'backlog', 'medium', NULL, 'client', NULL, '2026-03-23 18:53:39', '2026-06-12 10:23:04', NULL, 'c441081d01ef7302c48f6dc9a4c53e10', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ3GAN6QKTNJWVKPDG', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Install Poly Haven downloader addon', 'Godot Poly Haven Downloader (https://github.com/P3ntest/godot-polyhaven-downloader) — browse and download CC0 models, textures, and HDRIs from Poly Haven directly in the Godot editor. Removes friction from asset sourcing. Install when environment art work begins.', 'backlog', 'low', NULL, 'client', NULL, '2026-03-23 19:08:40', '2026-06-12 10:23:04', NULL, '9fef3041737e4c15b600a0df2f7864a8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ3GAN6QKTNJWVKPDG', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Install Poly Haven downloader addon', 'Godot Poly Haven Downloader (https://github.com/P3ntest/godot-polyhaven-downloader) — browse and download CC0 models, textures, and HDRIs from Poly Haven directly in the Godot editor. Removes friction from asset sourcing. Install when environment art work begins.
|
||
|
||
Re-parented under Phase 4 epic per cascade refocus 2026-06-12 — asset-pipeline tooling feeding the Phase-4 asset catalog.', 'backlog', 'low', NULL, 'client', NULL, '2026-03-23 19:08:40', '2026-06-12 10:23:04', NULL, '0f2d6e36be6c2e3968f73d9ae2fb74c2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY9W1MWNKMS803195C', 'task', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Selection glow effect for interactable objects', 'Soft glow border on hovered/selected objects and characters. Reference: GlowBorderEffect (https://github.com/Magodra/GlowBorderEffect). Distinct from our inverted hull outline (permanent character silhouette) — this is a context-sensitive highlight: hover over an NPC to see a soft glow indicating they''re interactable, selected items glow in inventory, quest-relevant objects pulse. Could be a simple shader (stencil + blur) or adopt the plugin. Evaluate when interaction system is built.', 'backlog', 'low', NULL, 'client', NULL, '2026-03-23 19:28:45', '2026-06-12 10:23:04', NULL, 'db589d42de20c93bfcbc22167c0b2a84', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY9W1MWNKMS803195C', 'task', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Selection glow effect for interactable objects', 'Soft glow border on hovered/selected objects and characters. Reference: GlowBorderEffect (https://github.com/Magodra/GlowBorderEffect). Distinct from our inverted hull outline (permanent character silhouette) — this is a context-sensitive highlight: hover over an NPC to see a soft glow indicating they''re interactable, selected items glow in inventory, quest-relevant objects pulse. Could be a simple shader (stencil + blur) or adopt the plugin. Evaluate when interaction system is built.
|
||
|
||
Parked under Phase 5 epic per cascade refocus 2026-06-12; interactable-highlight requirement preserved — evaluate when the interaction system is built.', 'backlog', 'low', NULL, 'client', NULL, '2026-03-23 19:28:45', '2026-06-12 10:23:04', NULL, 'bbfcec7a05f37c80dd18da9bb9678323', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWKAS60B0F9E8QHZ10', 'task', '06FB0TNSRXX29H5X0EB0F0GBW4', 'feat(ui): status/buff icon bar docked to HUD panel', 'Replace standalone stance indicator with an icon bar docked to the HUD status panel. Shows active states as small icons: stance (walk/sprint/crouch/careful), perception mode, future buffs/debuffs, implant status. Each icon color-coded per existing stance colors. Tooltip on hover shows label. Bar sits above or beside the HUD status ImplantPanel. Requires: icon set design (Araminta), bar layout component (ImplantIconBar), stance indicator refactored from panel to icon.', 'backlog', 'medium', NULL, 'client', NULL, '2026-04-05 10:28:05', '2026-06-12 10:23:04', NULL, 'd6afefbdecde3653f5a359b8686cd2b2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWKAS60B0F9E8QHZ10', 'task', '06FB0TNSRXX29H5X0EB0F0GBW4', 'feat(ui): status/buff icon bar docked to HUD panel', 'Replace standalone stance indicator with an icon bar docked to the HUD status panel. Shows active states as small icons: stance (walk/sprint/crouch/careful), perception mode, future buffs/debuffs, implant status. Each icon color-coded per existing stance colors. Tooltip on hover shows label. Bar sits above or beside the HUD status ImplantPanel. Requires: icon set design (Araminta), bar layout component (ImplantIconBar), stance indicator refactored from panel to icon.
|
||
|
||
Parked under Phase 5 epic per cascade refocus 2026-06-12; HUD status-icon requirement preserved — resumes with gameplay UI work.', 'backlog', 'medium', NULL, 'client', NULL, '2026-04-05 10:28:05', '2026-06-12 10:23:04', NULL, '7ad8abce59fdb438744317556b2f1ada', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXZSXNPA5Q55JN5K54', 'task', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Keybind document and settings keybind mapper', 'Two deliverables: (1) A keybind reference document listing all current key bindings (InputMap actions + hardcoded _unhandled_key_input keys like M/J/N/[/]). (2) A keybind mapper in the settings dialog that lets the player rebind keys at runtime. Triggered by Sprint 34 E-key conflict where economics panel was bound to a key already used by InputMap interact action.', 'backlog', 'medium', NULL, 'client', NULL, '2026-04-10 20:20:28', '2026-06-12 10:23:04', NULL, 'e64fbf417a5835eb33b3cc3226915fa6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXZSXNPA5Q55JN5K54', 'task', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Keybind document and settings keybind mapper', 'Two deliverables: (1) A keybind reference document listing all current key bindings (InputMap actions + hardcoded _unhandled_key_input keys like M/J/N/[/]). (2) A keybind mapper in the settings dialog that lets the player rebind keys at runtime. Triggered by Sprint 34 E-key conflict where economics panel was bound to a key already used by InputMap interact action.
|
||
|
||
Parked under Phase 5 epic per cascade refocus 2026-06-12; keybind documentation and remapping requirement preserved — pairs with T-735.', 'backlog', 'medium', NULL, 'client', NULL, '2026-04-10 20:20:28', '2026-06-12 10:23:04', NULL, 'fd783602a1e24f812acedefa8700c5c1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXMTJBWMXJBANMD6C4', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Unit tests for generate-star-map-data.py helpers', 'Review follow-up from PR #128 (Hoshe #17). Add unit-test coverage for compute_gdp, infer_tier_from_population, build_adjacency, parse_wiki_index in tooling/generate-star-map-data.py. Explicit boundary-condition test worth adding: compute_gdp at exactly 1T Tr (the BTr → TTr format switch). Non-blocker on the atlas landing PR but the generator is now on the pre-pr-client path, so it earns the regression coverage.', 'backlog', 'low', NULL, 'client', NULL, '2026-04-15 07:06:33', '2026-06-12 10:23:04', NULL, '5b18f343adaed70a977c125c84a993c1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXMTJBWMXJBANMD6C4', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Unit tests for generate-star-map-data.py helpers', 'Review follow-up from PR #128 (Hoshe #17). Add unit-test coverage for compute_gdp, infer_tier_from_population, build_adjacency, parse_wiki_index in tooling/generate-star-map-data.py. Explicit boundary-condition test worth adding: compute_gdp at exactly 1T Tr (the BTr → TTr format switch). Non-blocker on the atlas landing PR but the generator is now on the pre-pr-client path, so it earns the regression coverage.
|
||
|
||
Re-parented under Phase 4 epic per cascade refocus 2026-06-12 — generation-tooling test coverage (atlas star-map generator).', 'backlog', 'low', NULL, 'client', NULL, '2026-04-15 07:06:33', '2026-06-12 10:23:04', NULL, '4d9aeeb2e34f398dd75ff933247462d4', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZN95D8BBZ28Q92BQW', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Amend D-191 §8 markers schema to formalize overlay arrays', 'Review follow-up from PR #128 (blocker #3 fix). AtlasMarkerOverlay currently derives production_zones / shadow_economy / corp_presence from cities[].primary_function and cities[].commission_presence because D-191 §8''s schema (cities, roads, railroads, pois, rivers, oceans, mountain_ranges) has no dedicated arrays for production zones, shadow bands, or per-corp dots. Options: (a) amend D-191 §8 to list these explicitly and update the server generator, or (b) keep deriving from cities forever. Work with server team to pick and land the schema change so the MVP overlays read first-class data.', 'backlog', 'low', NULL, 'client', NULL, '2026-04-15 07:06:42', '2026-06-12 10:23:04', NULL, '3a94a8f8f9e6e9d269467cad79f5666d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZN95D8BBZ28Q92BQW', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Amend D-191 §8 markers schema to formalize overlay arrays', 'Review follow-up from PR #128 (blocker #3 fix). AtlasMarkerOverlay currently derives production_zones / shadow_economy / corp_presence from cities[].primary_function and cities[].commission_presence because D-191 §8''s schema (cities, roads, railroads, pois, rivers, oceans, mountain_ranges) has no dedicated arrays for production zones, shadow bands, or per-corp dots. Options: (a) amend D-191 §8 to list these explicitly and update the server generator, or (b) keep deriving from cities forever. Work with server team to pick and land the schema change so the MVP overlays read first-class data.
|
||
|
||
Re-parented under Phase 4 epic per cascade refocus 2026-06-12 — atlas markers schema is generation-output data.', 'backlog', 'low', NULL, 'client', NULL, '2026-04-15 07:06:42', '2026-06-12 10:23:04', NULL, 'ea39b95f484e0cd5115a261b64df9193', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRX6RK3GGV1A1TWQSMC', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'sr-voice release binary: multi-backend build (ROCm + CUDA + Vulkan + CPU)', 'The game will ship on multiple GPU vendors. The current sr-voice Cargo.toml has optional feature flags for metal / vulkan / cuda / rocm but default = [] — which means `cargo build --release` produces a CPU-only binary. Release binaries need to cover at minimum:
|
||
|
||
- NVIDIA: --features cuda (Windows, Linux gaming rigs)
|
||
- AMD: --features rocm (Linux) or vulkan (Windows, macOS, broader)
|
||
- Apple Silicon: --features metal (macOS)
|
||
- Fallback: CPU-only, always available
|
||
|
||
Options to cover this from the build pipeline:
|
||
|
||
A) Multiple release artifacts — sr-voice-cuda, sr-voice-rocm, sr-voice-vulkan, sr-voice-cpu — selected at game startup based on detected hardware. Biggest artifact count but best performance.
|
||
|
||
B) Single Vulkan release + CPU fallback — Vulkan compute works on NVIDIA, AMD, and Intel integrated GPUs with shipping drivers. One binary, acceptable perf on all GPUs, CPU-only binary for everyone else.
|
||
|
||
C) Dynamic feature detection at runtime — one binary with all backends compiled in, selects at load time. Largest binary, simplest distribution.
|
||
|
||
Also needs: release build pipeline (CI / cross-compilation) for each target platform, dev package installation instructions for each backend (e.g. ROCm rocm-hip-devel on Fedora is required for --features rocm to build), runtime hardware detection in the game launcher to pick the right binary.
|
||
|
||
Filed during the #833 naming pipeline work — the ROCm rebuild on the dev machine surfaced that the current Makefile target `build-sr-voice` produces CPU-only binaries regardless of the hardware present, which is fine for the dev''s #833 batch but absolutely wrong for shipped release binaries. Parent work: D-138 (Gemma 2 voice pipeline).', 'backlog', 'medium', NULL, 'server', NULL, '2026-04-15 10:57:11', '2026-06-12 10:23:04', NULL, 'ffdbfda98db560272286a4557f559773', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRX6RK3GGV1A1TWQSMC', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'sr-voice release binary: multi-backend build (ROCm + CUDA + Vulkan + CPU)', 'The game will ship on multiple GPU vendors. The current sr-voice Cargo.toml has optional feature flags for metal / vulkan / cuda / rocm but default = [] — which means `cargo build --release` produces a CPU-only binary. Release binaries need to cover at minimum:
|
||
|
||
- NVIDIA: --features cuda (Windows, Linux gaming rigs)
|
||
- AMD: --features rocm (Linux) or vulkan (Windows, macOS, broader)
|
||
- Apple Silicon: --features metal (macOS)
|
||
- Fallback: CPU-only, always available
|
||
|
||
Options to cover this from the build pipeline:
|
||
|
||
A) Multiple release artifacts — sr-voice-cuda, sr-voice-rocm, sr-voice-vulkan, sr-voice-cpu — selected at game startup based on detected hardware. Biggest artifact count but best performance.
|
||
|
||
B) Single Vulkan release + CPU fallback — Vulkan compute works on NVIDIA, AMD, and Intel integrated GPUs with shipping drivers. One binary, acceptable perf on all GPUs, CPU-only binary for everyone else.
|
||
|
||
C) Dynamic feature detection at runtime — one binary with all backends compiled in, selects at load time. Largest binary, simplest distribution.
|
||
|
||
Also needs: release build pipeline (CI / cross-compilation) for each target platform, dev package installation instructions for each backend (e.g. ROCm rocm-hip-devel on Fedora is required for --features rocm to build), runtime hardware detection in the game launcher to pick the right binary.
|
||
|
||
Filed during the #833 naming pipeline work — the ROCm rebuild on the dev machine surfaced that the current Makefile target `build-sr-voice` produces CPU-only binaries regardless of the hardware present, which is fine for the dev''s #833 batch but absolutely wrong for shipped release binaries. Parent work: D-138 (Gemma 2 voice pipeline).
|
||
|
||
Re-homed under maintenance per cascade refocus 2026-06-12 — build-pipeline infrastructure; multi-GPU release-binary requirement preserved.', 'backlog', 'medium', NULL, 'server', NULL, '2026-04-15 10:57:11', '2026-06-12 10:23:04', NULL, '57831b4b04fe0e4ea0177b5cf5215aca', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWBJ1XC9V5ZQHSXAXG', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'Rewrite P2-U01 monologue_display_visible_hidden test against current _visible array API', 'test_monologue_display_visible_hidden in test_client_p2.gd accessed mono.is_visible (a custom bool property). MonologueDisplay was refactored to use _visible: Array[Dictionary] instead. Test skipped (skip_test_) pending rewrite. New test should check _visible.size() > 0 after show_monologue, and == 0 when idle.', 'backlog', 'low', NULL, 'client', NULL, '2026-04-20 11:17:20', '2026-06-12 10:23:04', NULL, '1ce2547723d3dd385d5843f331cfd5aa', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWBJ1XC9V5ZQHSXAXG', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'Rewrite P2-U01 monologue_display_visible_hidden test against current _visible array API', 'test_monologue_display_visible_hidden in test_client_p2.gd accessed mono.is_visible (a custom bool property). MonologueDisplay was refactored to use _visible: Array[Dictionary] instead. Test skipped (skip_test_) pending rewrite. New test should check _visible.size() > 0 after show_monologue, and == 0 when idle.
|
||
|
||
Re-homed under maintenance (test debt) per cascade refocus 2026-06-12.', 'backlog', 'low', NULL, 'client', NULL, '2026-04-20 11:17:20', '2026-06-12 10:23:04', NULL, '02af47396ed1d708fa5d50b13a0e6fb9', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZGSKN39GSW39JNZDG', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Revive journal panel tests (player_knowledge, UIStrings, state colors)', 'test_journal_sprint18.gd was deleted in Sprint 37 (#870 parse-error cleanup). It contained unique tests for: GameState.player_knowledge snapshot parsing/persistence, journal_panel.tscn scene lifecycle, entry rendering from player_knowledge entities, UIStrings confidence/source keys (D-042), _state_color() for Contradicted/Stale/Active states. No other journal-specific test file exists. Spec: D-041, D-042, #264.', 'backlog', 'low', NULL, 'client', NULL, '2026-04-21 15:01:17', '2026-06-12 10:23:04', NULL, 'acafbf18f2a8fd4ef0b5ea666b394e4d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZGSKN39GSW39JNZDG', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Revive journal panel tests (player_knowledge, UIStrings, state colors)', 'test_journal_sprint18.gd was deleted in Sprint 37 (#870 parse-error cleanup). It contained unique tests for: GameState.player_knowledge snapshot parsing/persistence, journal_panel.tscn scene lifecycle, entry rendering from player_knowledge entities, UIStrings confidence/source keys (D-042), _state_color() for Contradicted/Stale/Active states. No other journal-specific test file exists. Spec: D-041, D-042, #264.
|
||
|
||
Re-homed under maintenance (test-revival debt from #870 deletions) per cascade refocus 2026-06-12.', 'backlog', 'low', NULL, 'client', NULL, '2026-04-21 15:01:17', '2026-06-12 10:23:04', NULL, 'e1cb97d054ae2bbec781509018e0e5b3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYDPBFJVAQAN7T56VR', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Revive minimap rendering tests (discovered POIs, circular overlay, insert visibility)', 'test_minimap_sprint18.gd was deleted in Sprint 37 (#870 parse-error cleanup). It contained unique tests for: minimap.tscn scene, POI rendering from GameState.discovered_pois, circular insert overlay visibility, insert_active toggle behavior. No other minimap test file exists. Spec: D-013, D-015, D-049, #151.', 'backlog', 'low', NULL, 'client', NULL, '2026-04-21 15:01:23', '2026-06-12 10:23:04', NULL, '15593bb56dde167057a4695811dee09c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYDPBFJVAQAN7T56VR', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Revive minimap rendering tests (discovered POIs, circular overlay, insert visibility)', 'test_minimap_sprint18.gd was deleted in Sprint 37 (#870 parse-error cleanup). It contained unique tests for: minimap.tscn scene, POI rendering from GameState.discovered_pois, circular insert overlay visibility, insert_active toggle behavior. No other minimap test file exists. Spec: D-013, D-015, D-049, #151.
|
||
|
||
Re-homed under maintenance (test-revival debt from #870 deletions) per cascade refocus 2026-06-12.', 'backlog', 'low', NULL, 'client', NULL, '2026-04-21 15:01:23', '2026-06-12 10:23:04', NULL, '7d0fe65f85fc02c4eac924fd91e2d0ad', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWYRBKFQ1W3S8DS21W', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Revive EntityRenderer sprite constants coverage (D-044 ENTITY_WIDTH/HEIGHT)', 'test_sprite_integration.gd was deleted in Sprint 37 (#870 parse-error cleanup). It was the sole asserter of D-044 sprite dimensions: EntityRenderer.ENTITY_WIDTH == 24 and ENTITY_HEIGHT == 32 (client/scripts/rendering/entity_renderer.gd:19-20). These values are load-bearing for tile-anchored y-sort (ENTITY_OFFSET_Y = TILE_SIZE - ENTITY_HEIGHT, line 22, D-019 tilt). Revive a focused test that asserts both constants and the derived offset — rewrite against current EntityRenderer API. Surfaced in PR #135 review (Tyre T2). Spec: D-044, D-019, D-049.', 'backlog', 'low', NULL, 'client', NULL, '2026-04-22 07:56:26', '2026-06-12 10:23:04', NULL, 'eac19435ce3c097daa1b470c1ce56edb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWYRBKFQ1W3S8DS21W', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Revive EntityRenderer sprite constants coverage (D-044 ENTITY_WIDTH/HEIGHT)', 'test_sprite_integration.gd was deleted in Sprint 37 (#870 parse-error cleanup). It was the sole asserter of D-044 sprite dimensions: EntityRenderer.ENTITY_WIDTH == 24 and ENTITY_HEIGHT == 32 (client/scripts/rendering/entity_renderer.gd:19-20). These values are load-bearing for tile-anchored y-sort (ENTITY_OFFSET_Y = TILE_SIZE - ENTITY_HEIGHT, line 22, D-019 tilt). Revive a focused test that asserts both constants and the derived offset — rewrite against current EntityRenderer API. Surfaced in PR #135 review (Tyre T2). Spec: D-044, D-019, D-049.
|
||
|
||
Re-homed under maintenance (test-revival debt from #870 deletions) per cascade refocus 2026-06-12.', 'backlog', 'low', NULL, 'client', NULL, '2026-04-22 07:56:26', '2026-06-12 10:23:04', NULL, '00b2a12967d051a228c42a3acb114654', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY05Z5JJRN1ND5ZFGC', 'story', '06FBPPMMF7HS6FWRYAKMECTXX0', 'UI timeout fallback for bookmark catalog wait (main_menu)', 'main_menu.gd:72-74 _process loop polls SimBridge.poll_snapshot while _waiting_for_catalog is true. If the server never delivers bookmark_catalog (crash, new-server bug, decode dropout), the loading screen hangs forever. #872 patched the specific TCP-batch race where catalog was overwritten in receive_bytes, but the systemic class — ''catalog never arrives'' — remains.
|
||
|
||
Add a ~10s timer on _waiting_for_catalog = true. On expiry: show ''Server did not respond. Try again.'', re-enable the menu buttons, allow the user to retry or quit. Surfaced in PR #135 review (Tyre T4).
|
||
|
||
Spec: #872 (TCP-batch race fix), #258 (main menu flow).', 'backlog', 'low', NULL, 'client', NULL, '2026-04-22 07:56:41', '2026-06-12 10:23:04', NULL, '9514a83e929bc2a6cf73028fcc706250', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY05Z5JJRN1ND5ZFGC', 'story', '06FBPPMMF7HS6FWRYAKMECTXX0', 'UI timeout fallback for bookmark catalog wait (main_menu)', 'main_menu.gd:72-74 _process loop polls SimBridge.poll_snapshot while _waiting_for_catalog is true. If the server never delivers bookmark_catalog (crash, new-server bug, decode dropout), the loading screen hangs forever. #872 patched the specific TCP-batch race where catalog was overwritten in receive_bytes, but the systemic class — ''catalog never arrives'' — remains.
|
||
|
||
Add a ~10s timer on _waiting_for_catalog = true. On expiry: show ''Server did not respond. Try again.'', re-enable the menu buttons, allow the user to retry or quit. Surfaced in PR #135 review (Tyre T4).
|
||
|
||
Spec: #872 (TCP-batch race fix), #258 (main menu flow).
|
||
|
||
Parked under post-cascade gameplay backlog per cascade refocus 2026-06-12; loading-timeout robustness requirement preserved with the bookmark flow.', 'backlog', 'low', NULL, 'client', NULL, '2026-04-22 07:56:41', '2026-06-12 10:23:04', NULL, 'dcbf33e897de752ca35ad3bd4268f24c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXT5QXNT1QST51NKZR', 'story', '06FBPPMZNNEV052DBYYY3A897C', 'Scene-flow test tier: doc + encapsulated reset helpers', 'Scene-level UI flow tests landed as a 4th tier beyond the 3 in CLAUDE.md (live Gauntlet / MessagePack replay / TestHarness mock). test_merge_path_flows_sprint37.gd is the first concrete example. Two rough edges surfaced in PR #135 review (Tyre T5, T6):
|
||
|
||
1. **Doc the tier model.** Update CLAUDE.md test tiers section to name this tier explicitly — ''scene-flow tests: load .tscn headless, simulate input via signal emit, assert terminal state''. Include when to reach for it vs MessagePack replay vs mock.
|
||
|
||
2. **Test-only reset helpers.** before_test() in test_merge_path_flows_sprint37.gd reaches into SimBridge._last_snapshot, SimBridge._outbound_buffer, MetaStack._stack. Same reach-in pattern appeared in test_anti_tedium.gd before_test (PR #135 commit bc310a3c added MetaStack._stack.clear). Expose:
|
||
- SimBridge.reset_for_test() — clears _last_snapshot, _outbound_buffer, disconnects; test-only, guarded by test_mode.
|
||
- MetaStack.reset_for_test() — clears _stack.
|
||
Replace per-test reach-ins with these helpers.
|
||
|
||
3. **Minimal public API for scene state.** Current flow tests couple to private fields (_waiting_for_catalog, _selected_bookmark_id, _loading_screen, _new_game_btn). UI refactor renames will break all 4 tests simultaneously. Consider: is_waiting_for_catalog(), has_selected_bookmark(), pressed_new_game() signal — a minimal public surface that test-and-refactor can share.
|
||
|
||
Not blocking PR #135 but the coupling will bite the next UI refactor.
|
||
|
||
Spec: #873 (merge-path tests), D-020 (IPC architecture — test harness layer).', 'backlog', 'low', NULL, 'client', NULL, '2026-04-22 07:57:10', '2026-06-12 10:23:05', NULL, 'b110da7b2a0d1b36136af9cc78f128f0', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXT5QXNT1QST51NKZR', 'story', '06FBPPMZNNEV052DBYYY3A897C', 'Scene-flow test tier: doc + encapsulated reset helpers', 'Scene-level UI flow tests landed as a 4th tier beyond the 3 in CLAUDE.md (live Gauntlet / MessagePack replay / TestHarness mock). test_merge_path_flows_sprint37.gd is the first concrete example. Two rough edges surfaced in PR #135 review (Tyre T5, T6):
|
||
|
||
1. **Doc the tier model.** Update CLAUDE.md test tiers section to name this tier explicitly — ''scene-flow tests: load .tscn headless, simulate input via signal emit, assert terminal state''. Include when to reach for it vs MessagePack replay vs mock.
|
||
|
||
2. **Test-only reset helpers.** before_test() in test_merge_path_flows_sprint37.gd reaches into SimBridge._last_snapshot, SimBridge._outbound_buffer, MetaStack._stack. Same reach-in pattern appeared in test_anti_tedium.gd before_test (PR #135 commit bc310a3c added MetaStack._stack.clear). Expose:
|
||
- SimBridge.reset_for_test() — clears _last_snapshot, _outbound_buffer, disconnects; test-only, guarded by test_mode.
|
||
- MetaStack.reset_for_test() — clears _stack.
|
||
Replace per-test reach-ins with these helpers.
|
||
|
||
3. **Minimal public API for scene state.** Current flow tests couple to private fields (_waiting_for_catalog, _selected_bookmark_id, _loading_screen, _new_game_btn). UI refactor renames will break all 4 tests simultaneously. Consider: is_waiting_for_catalog(), has_selected_bookmark(), pressed_new_game() signal — a minimal public surface that test-and-refactor can share.
|
||
|
||
Not blocking PR #135 but the coupling will bite the next UI refactor.
|
||
|
||
Spec: #873 (merge-path tests), D-020 (IPC architecture — test harness layer).
|
||
|
||
Re-homed under maintenance (test-infra hygiene) per cascade refocus 2026-06-12.', 'backlog', 'low', NULL, 'client', NULL, '2026-04-22 07:57:10', '2026-06-12 10:23:05', NULL, '910cc3678b98f58ce2fd10287c3bf8eb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW77B3T7GXT6ZASX88', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'CLAUDE.md carveout for server wiki writes driven by coverage gates', '**Follow-up to PR #137 / Hoshe review H8.**
|
||
|
||
PR #137 includes 21 file edits under `wiki/` authored by the server team (6 new corp wiki pages + 15 tag updates, shipped under #860 — "Close D-175 Phase 2 coverage gate"). `CLAUDE.md` team-boundaries policy says: *"Stay within your team''s scope. Server team modifies `server/`. Copy team modifies `wiki/`."* The wiki writes were accepted for this sprint as a pragmatic fix (and copy-team follow-up review filed as #884), but Hoshe correctly flagged the precedent concern:
|
||
|
||
> "If cross-scope writes are structurally necessary for coverage gates, process should note this explicitly rather than route as a copy-team follow-up after merge."
|
||
|
||
The server team''s Phase 2 economy coverage gate requires that every referenced commodity / system / corporation has a corresponding wiki page — otherwise the gate fails. That coupling is real and will recur. Routing it as an after-the-fact copy-team review works once; it''s not a stable process.
|
||
|
||
**Scope:**
|
||
|
||
1. Amend `CLAUDE.md` team-boundaries section to note an explicit carveout: when a server-side coverage gate requires wiki writes to close (economy coverage, asset coverage, future gates), the server team may write under `wiki/` provided:
|
||
- The writes are mechanical / gate-driven (page creation to satisfy a lookup, tag updates to satisfy a filter), not voice/lore authoring.
|
||
- A copy-team follow-up ticket is filed in the same PR body for voice/consistency review.
|
||
- The PR body explicitly lists the wiki files touched and the coverage gate that required them.
|
||
2. Decide whether the same carveout applies in reverse (copy team writing to `server/` for a gate closure — probably N/A, but worth calling out to avoid asymmetry surprises later).
|
||
3. Alternative framing to consider: instead of the carveout, extract the coverage-gate-driven file generation into a tooling script under `tooling/` that creates *stub* pages for copy to flesh out. The server team commits the stubs; copy replaces with real content. Evaluate vs. direct-write carveout; the carveout is less infrastructure but the stub pipeline is cleaner process-wise.
|
||
4. Update `.claude/rules/project-structure.md` if needed to match the CLAUDE.md change.
|
||
|
||
**Cross-reference:** PR #137, #860 (D-175 Phase 2 coverage gate), #884 (copy-team voice/lore review of the wiki writes), `CLAUDE.md` "Agent Instructions → Team boundaries" section.
|
||
|
||
**Rationale:** The boundary exists to keep voice/lore authoring in copy-team hands and prevent drift. Coverage gates create legitimate cross-scope writes that aren''t authoring. The boundary should accommodate this or provide an alternative that keeps the boundary clean.', 'backlog', 'low', NULL, 'planning', NULL, '2026-04-22 08:00:12', '2026-06-12 10:23:05', NULL, 'e9d64f2cc8b6ebcb29abdf0b569e9979', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW77B3T7GXT6ZASX88', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'CLAUDE.md carveout for server wiki writes driven by coverage gates', '**Follow-up to PR #137 / Hoshe review H8.**
|
||
|
||
PR #137 includes 21 file edits under `wiki/` authored by the server team (6 new corp wiki pages + 15 tag updates, shipped under #860 — "Close D-175 Phase 2 coverage gate"). `CLAUDE.md` team-boundaries policy says: *"Stay within your team''s scope. Server team modifies `server/`. Copy team modifies `wiki/`."* The wiki writes were accepted for this sprint as a pragmatic fix (and copy-team follow-up review filed as #884), but Hoshe correctly flagged the precedent concern:
|
||
|
||
> "If cross-scope writes are structurally necessary for coverage gates, process should note this explicitly rather than route as a copy-team follow-up after merge."
|
||
|
||
The server team''s Phase 2 economy coverage gate requires that every referenced commodity / system / corporation has a corresponding wiki page — otherwise the gate fails. That coupling is real and will recur. Routing it as an after-the-fact copy-team review works once; it''s not a stable process.
|
||
|
||
**Scope:**
|
||
|
||
1. Amend `CLAUDE.md` team-boundaries section to note an explicit carveout: when a server-side coverage gate requires wiki writes to close (economy coverage, asset coverage, future gates), the server team may write under `wiki/` provided:
|
||
- The writes are mechanical / gate-driven (page creation to satisfy a lookup, tag updates to satisfy a filter), not voice/lore authoring.
|
||
- A copy-team follow-up ticket is filed in the same PR body for voice/consistency review.
|
||
- The PR body explicitly lists the wiki files touched and the coverage gate that required them.
|
||
2. Decide whether the same carveout applies in reverse (copy team writing to `server/` for a gate closure — probably N/A, but worth calling out to avoid asymmetry surprises later).
|
||
3. Alternative framing to consider: instead of the carveout, extract the coverage-gate-driven file generation into a tooling script under `tooling/` that creates *stub* pages for copy to flesh out. The server team commits the stubs; copy replaces with real content. Evaluate vs. direct-write carveout; the carveout is less infrastructure but the stub pipeline is cleaner process-wise.
|
||
4. Update `.claude/rules/project-structure.md` if needed to match the CLAUDE.md change.
|
||
|
||
**Cross-reference:** PR #137, #860 (D-175 Phase 2 coverage gate), #884 (copy-team voice/lore review of the wiki writes), `CLAUDE.md` "Agent Instructions → Team boundaries" section.
|
||
|
||
**Rationale:** The boundary exists to keep voice/lore authoring in copy-team hands and prevent drift. Coverage gates create legitimate cross-scope writes that aren''t authoring. The boundary should accommodate this or provide an alternative that keeps the boundary clean.
|
||
|
||
Re-homed under maintenance (process/docs hygiene) per cascade refocus 2026-06-12.', 'backlog', 'low', NULL, 'planning', NULL, '2026-04-22 08:00:12', '2026-06-12 10:23:05', NULL, 'e4b38eace7ca5713b74b8e4206e6637a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZBH1C2R0DXM00C66R', 'task', '06FBPPMMF7HS6FWRYAKMECTXX0', 'D-027 criterion 4: Layer 2/3 E2E test for RoutineDeviation tell after triangle activation', 'v01_integration_playthrough.rs was deleted in #878 as archetype-dependent. Its only non-archetype coverage — D-027 criterion 4 (RoutineDeviation tell after triangle activation) — was already #[ignore]-blocked on #589 (escalate_tells_on_activation). Layer 1 tell priority is covered by tell_escalation.rs. This ticket tracks the missing Layer 2 ECS-world test: activation event → RoutineDeviation insertion, and (optionally) a Layer 3 subprocess proof once #589 lands. Non-blocking for sprint 37 merge.', 'backlog', 'low', NULL, 'server', NULL, '2026-04-22 08:06:52', '2026-06-12 10:23:05', NULL, '35fe3775c85a044230ef004c5c3ad68d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZBH1C2R0DXM00C66R', 'task', '06FBPPMMF7HS6FWRYAKMECTXX0', 'D-027 criterion 4: Layer 2/3 E2E test for RoutineDeviation tell after triangle activation', 'v01_integration_playthrough.rs was deleted in #878 as archetype-dependent. Its only non-archetype coverage — D-027 criterion 4 (RoutineDeviation tell after triangle activation) — was already #[ignore]-blocked on #589 (escalate_tells_on_activation). Layer 1 tell priority is covered by tell_escalation.rs. This ticket tracks the missing Layer 2 ECS-world test: activation event → RoutineDeviation insertion, and (optionally) a Layer 3 subprocess proof once #589 lands. Non-blocking for sprint 37 merge.
|
||
|
||
Parked under post-cascade gameplay backlog per cascade refocus 2026-06-12; D-027 criterion-4 coverage requirement preserved — picks up when tell escalation (#589) lands.', 'backlog', 'low', NULL, 'server', NULL, '2026-04-22 08:06:52', '2026-06-12 10:23:05', NULL, '818c1064298b607a49a4c1b81c8bc13c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXN360AQN3973AHS8M', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_dialogue_sprint20: 5 failures — AudioManager.get_active_dip or other API drift', '5 failing test cases in test_dialogue_sprint20.gd. The suite tests D-020 signal decoupling for dialogue_box. Likely failure: test_show_dialogue_does_not_call_audio_manager_directly compares AudioManager.get_active_dip() before/after show_dialogue — if AudioManager.get_active_dip() behavior changed or is not returning clean state, this would fail. Investigate by running the suite in isolation and reading specific assertion failures from the log. Sprint 38 triage #871.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:11:54', '2026-06-12 10:23:05', NULL, 'e148dfda5fd7150e055f2b5bde931544', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXN360AQN3973AHS8M', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_dialogue_sprint20: 5 failures — AudioManager.get_active_dip or other API drift', '5 failing test cases in test_dialogue_sprint20.gd. The suite tests D-020 signal decoupling for dialogue_box. Likely failure: test_show_dialogue_does_not_call_audio_manager_directly compares AudioManager.get_active_dip() before/after show_dialogue — if AudioManager.get_active_dip() behavior changed or is not returning clean state, this would fail. Investigate by running the suite in isolation and reading specific assertion failures from the log. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:11:54', '2026-06-12 10:23:05', NULL, '40788a6ba0cfe9aa73c10849ff2a77b2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXMVYQJV2QDHH8H7P8', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_input_roundtrip: 3 failures — server binary missing or LocalBridge API change', '3 failing test cases in test_input_roundtrip.gd. All tests check _connect_to_server() which skips if server binary not found — but 3 still fail, suggesting either: (1) server binary is present but something in LocalBridge.send_message, poll, or Protocol.encode_player_inputs changed, or (2) test environment returns false from _connect_to_server but then asserts fail. Investigate by running with --filter test_input_roundtrip and checking the log for exact assertion sites. Sprint 38 triage #871.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:11:59', '2026-06-12 10:23:05', NULL, 'be5c5f0ba84eed9f4703b19bc8a01b3e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXMVYQJV2QDHH8H7P8', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_input_roundtrip: 3 failures — server binary missing or LocalBridge API change', '3 failing test cases in test_input_roundtrip.gd. All tests check _connect_to_server() which skips if server binary not found — but 3 still fail, suggesting either: (1) server binary is present but something in LocalBridge.send_message, poll, or Protocol.encode_player_inputs changed, or (2) test environment returns false from _connect_to_server but then asserts fail. Investigate by running with --filter test_input_roundtrip and checking the log for exact assertion sites. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:11:59', '2026-06-12 10:23:05', NULL, 'dfe49e914543e46781fb2f5b462cafad', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY3TXD5HDKHFVGDG18', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_implant_app_lifecycle: 1 failure — ImplantApp or HudGroups state API', '1 failing test case in test_implant_app_lifecycle.gd. Suite tests ImplantApp._internal_app_changed, nav stack, preserves_state, and HudGroups state. after_test resets HudGroups._active_app, _active_mode, _groups — if these private fields were renamed or removed, after_test would fail and bleed state. Or a specific on_open/on_close hook fires differently. Run --filter test_implant_app_lifecycle and check specific assertion. Sprint 38 triage #871.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:12:32', '2026-06-12 10:23:05', NULL, 'd4da304caced40c2c10675937368d0c0', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY3TXD5HDKHFVGDG18', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_implant_app_lifecycle: 1 failure — ImplantApp or HudGroups state API', '1 failing test case in test_implant_app_lifecycle.gd. Suite tests ImplantApp._internal_app_changed, nav stack, preserves_state, and HudGroups state. after_test resets HudGroups._active_app, _active_mode, _groups — if these private fields were renamed or removed, after_test would fail and bleed state. Or a specific on_open/on_close hook fires differently. Run --filter test_implant_app_lifecycle and check specific assertion. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:12:32', '2026-06-12 10:23:05', NULL, 'b2dbffcf6181766c4d024b912ab6ee90', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWK87PCWGZ6GWT2TBM', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_game_state_sprint20: 1 failure — SnapshotHandler or stationary_ticks path', '1 failing test case in test_game_state_sprint20.gd. before_each resets SnapshotHandler._prev_player_position. If this static var was renamed or moved, the before_each hook would error. Alternatively a stationary_ticks path changed in SnapshotHandler. Verify SnapshotHandler still has static var _prev_player_position at that exact name. Sprint 38 triage #871.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:12:38', '2026-06-12 10:23:05', NULL, '2689f06827000dc8c864d171238dbe69', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWK87PCWGZ6GWT2TBM', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_game_state_sprint20: 1 failure — SnapshotHandler or stationary_ticks path', '1 failing test case in test_game_state_sprint20.gd. before_each resets SnapshotHandler._prev_player_position. If this static var was renamed or moved, the before_each hook would error. Alternatively a stationary_ticks path changed in SnapshotHandler. Verify SnapshotHandler still has static var _prev_player_position at that exact name. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:12:38', '2026-06-12 10:23:05', NULL, '993364218aebbbc6986cf535566b1990', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYF23MZ86S1XF1542G', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_fog_shader: 1 failure — stale VIS_PERIPHERAL or peripheral sector assertion', '1 failing test case in test_fog_shader.gd. The most likely failure is test_fog_state_forward_vs_peripheral: it asserts Forward > Peripheral visibility values, but Sprint 22 (#569) removed peripheral sector. Now all visible tiles write VIS_FORWARD regardless. The test checks the texture is non-null (not the actual byte values), so it should pass... unless the failure is in test_fog_state_exploration_persists which has a weak assertion. Run --filter test_fog_shader to identify the specific failure. Sprint 38 triage #871.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:12:45', '2026-06-12 10:23:05', NULL, '3c27c41707376c03b0ca5a0acf24035b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYF23MZ86S1XF1542G', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_fog_shader: 1 failure — stale VIS_PERIPHERAL or peripheral sector assertion', '1 failing test case in test_fog_shader.gd. The most likely failure is test_fog_state_forward_vs_peripheral: it asserts Forward > Peripheral visibility values, but Sprint 22 (#569) removed peripheral sector. Now all visible tiles write VIS_FORWARD regardless. The test checks the texture is non-null (not the actual byte values), so it should pass... unless the failure is in test_fog_state_exploration_persists which has a weak assertion. Run --filter test_fog_shader to identify the specific failure. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:12:45', '2026-06-12 10:23:05', NULL, 'bb63cf321016aa94052c0eca3ad7ec77', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZYDBRV5T9QVQAXGV0', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_e2e_connection: 1 failure — server binary path or TCP connection state', '1 failing test case in test_e2e_connection.gd. test_send_input_receive_snapshot skips if server binary not found. If it fails, either: (1) server binary exists but connection fails (port collision, timing), or (2) LocalBridge.reset() method was removed (the test calls _bridge.reset() but this may not exist on LocalBridge). Verify LocalBridge has a reset() method. Sprint 38 triage #871.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:12:51', '2026-06-12 10:23:05', NULL, '7ab8b3846917c88efeca3d50990e3d89', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZYDBRV5T9QVQAXGV0', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_e2e_connection: 1 failure — server binary path or TCP connection state', '1 failing test case in test_e2e_connection.gd. test_send_input_receive_snapshot skips if server binary not found. If it fails, either: (1) server binary exists but connection fails (port collision, timing), or (2) LocalBridge.reset() method was removed (the test calls _bridge.reset() but this may not exist on LocalBridge). Verify LocalBridge has a reset() method. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:12:51', '2026-06-12 10:23:05', NULL, 'deffb71bafcbd07b22c520943f7a846f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY9FV0S9RE42WY7SHW', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_audio_sprint13: 1 failure — AudioManager.clear_dip or API drift', '1 failing test case in test_audio_sprint13.gd. before_test calls AudioManager.clear_dip(), stop_all_loops(), set_volume() for all buses. If any of these methods were renamed or a bus constant changed, setup would fail and cascade. Or a specific dip timing assertion is stale. Run --filter test_audio_sprint13 and read the specific failure. Sprint 38 triage #871.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:12:56', '2026-06-12 10:23:05', NULL, '5cec2383dbf80f22833e696c8ed290ab', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY9FV0S9RE42WY7SHW', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_audio_sprint13: 1 failure — AudioManager.clear_dip or API drift', '1 failing test case in test_audio_sprint13.gd. before_test calls AudioManager.clear_dip(), stop_all_loops(), set_volume() for all buses. If any of these methods were renamed or a bus constant changed, setup would fail and cascade. Or a specific dip timing assertion is stale. Run --filter test_audio_sprint13 and read the specific failure. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:12:56', '2026-06-12 10:23:05', NULL, 'e163d908f7547e589b11a97343cbf93c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXCE9D9JYBZWVXMG68', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_ai_dialogue_sprint26: 1 failure — HardwareDetector autoload missing or settings_dialog API', '1 failing test case in test_ai_dialogue_sprint26.gd. The HardwareDetector tests skip if autoload not found. The GameState field tests (ai_enhanced_dialogue_enabled) look correct. The failing test is likely in the settings_dialog section: SETTINGS_DIALOG_SCENE preloaded at class level — if settings_dialog.tscn doesn''t exist or a method was renamed, class-level preload would fail. Check res://ui/settings_dialog.tscn exists and the relevant methods. Sprint 38 triage #871.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:13:02', '2026-06-12 10:23:05', NULL, 'ed7e0cd1fa885a1a9d20b79a3917f417', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXCE9D9JYBZWVXMG68', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_ai_dialogue_sprint26: 1 failure — HardwareDetector autoload missing or settings_dialog API', '1 failing test case in test_ai_dialogue_sprint26.gd. The HardwareDetector tests skip if autoload not found. The GameState field tests (ai_enhanced_dialogue_enabled) look correct. The failing test is likely in the settings_dialog section: SETTINGS_DIALOG_SCENE preloaded at class level — if settings_dialog.tscn doesn''t exist or a method was renamed, class-level preload would fail. Check res://ui/settings_dialog.tscn exists and the relevant methods. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'backlog', 'low', NULL, 'client', NULL, '2026-05-02 08:13:02', '2026-06-12 10:23:05', NULL, 'd30ab47be78dcd540d431e8ed6a8c352', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ9Q7NHVDRT6ARMCWW', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'D-210 SubBiomeVariant implementation', 'D-210 defines SubBiomeVariant for fine-grained biome classification within SettingType::Wilderness districts. Currently deferred — SettingType::Wilderness carries a plain String biome field. Implement SubBiomeVariant enum and wire it into the atlas skeleton generator when the biome taxonomy is finalized.', 'backlog', 'low', NULL, 'server', NULL, '2026-05-03 10:30:14', '2026-06-12 10:23:05', NULL, 'bfb4923b6526a378a3baf298854b4083', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ9Q7NHVDRT6ARMCWW', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'D-210 SubBiomeVariant implementation', 'D-210 defines SubBiomeVariant for fine-grained biome classification within SettingType::Wilderness districts. Currently deferred — SettingType::Wilderness carries a plain String biome field. Implement SubBiomeVariant enum and wire it into the atlas skeleton generator when the biome taxonomy is finalized.
|
||
|
||
Re-parented under Phase 4 epic per cascade refocus 2026-06-12 — biome taxonomy for the atlas/cascade generator.', 'backlog', 'low', NULL, 'server', NULL, '2026-05-03 10:30:14', '2026-06-12 10:23:05', NULL, 'a1cd9d5b72f7a9748c52d23ed948b0b6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW2ZSPJ3D9NEZ6JBW8', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Atlas data delivery — replace client-side file reads with server API calls', 'The client currently reads markers.json and star_map_data.json directly from the filesystem. This bypasses the server layer entirely — the client should request all game data through IPC calls to the Rust backend.
|
||
|
||
Implementation can be simple: the server exposes a query/proxy endpoint that reads the JSON file or runs a DB query and returns the result. The client asks, the server responds. No complex protocol needed — just the boundary enforcement that the client never reads files or DB directly.
|
||
|
||
Affects: atlas app (reach, system, planet, regional screens), economics monitor. The server-side handler can start as a thin proxy (read file, return contents) and evolve into perception-filtered queries (D-012) later.', 'backlog', 'medium', NULL, 'client', NULL, '2026-05-03 14:14:23', '2026-06-12 10:23:05', NULL, '026273cf1c27b3c46ca83df235265d72', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW2ZSPJ3D9NEZ6JBW8', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Atlas data delivery — replace client-side file reads with server API calls', 'The client currently reads markers.json and star_map_data.json directly from the filesystem. This bypasses the server layer entirely — the client should request all game data through IPC calls to the Rust backend.
|
||
|
||
Implementation can be simple: the server exposes a query/proxy endpoint that reads the JSON file or runs a DB query and returns the result. The client asks, the server responds. No complex protocol needed — just the boundary enforcement that the client never reads files or DB directly.
|
||
|
||
Affects: atlas app (reach, system, planet, regional screens), economics monitor. The server-side handler can start as a thin proxy (read file, return contents) and evolve into perception-filtered queries (D-012) later.
|
||
|
||
Re-parented under Phase 4 epic per cascade refocus 2026-06-12 — atlas data delivery underpins viewing cascade layers through the implant Atlas.', 'backlog', 'medium', NULL, 'client', NULL, '2026-05-03 14:14:23', '2026-06-12 10:23:05', NULL, 'ff64aa82b1f15c4cea86ee3268f20995', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYEM4VSX74MS4NKQ1C', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'Client test suite — pre-existing failures under bare run-godot', 'Surfaced 2026-05-24 running the full client suite (tests/run-godot, no server) during #960. NOT caused by #960 — verified: test_input_roundtrip fails identically at the pre-change baseline, and the rest are unrelated subsystems. Two categories to triage:
|
||
|
||
CATEGORY 1 — server-dependent (expected-fail under bare run-godot): test_e2e_connection (test_send_input_receive_snapshot), test_input_roundtrip (movement/interact/move_then_interact). They error with ''Nil snapshot'' / ''.tick on Nil'' because no sim server is spawned. They need the run-ipc-* harness or SR_LIVE=1. FIX OPTIONS: gate/skip these under bare run-godot (mark as requiring a server) OR have run-godot spawn the server for the e2e tier, so tests/run-godot
|
||
{"suite":"godot","total":2522,"passed":2482,"failed":40,"duration_ms":96836,"log":"/tmp/sr-run-godot.1737738.log"} is green without false negatives.
|
||
|
||
CATEGORY 2 — genuine logic failures in subsystems unrelated to current work: test_audio_sprint13 (test_d067_chime_duration_spec_is_300_to_400ms, line 547 ''Expecting true but is false''), test_fog_sprint22 (exploration_data_preserved_across_resize), test_fog_shader (visibility_texture_update_performance), test_dialogue_sprint18/20 (signal/audio-dip), test_monologue_display (queue_never_exceeds_max_depth), test_implant_app_lifecycle (on_insert_deactivated_closes_insert_app), test_ai_dialogue_sprint26 (settings_dialog warning label). Triage each: fix or remove/xfail with a reason.
|
||
|
||
Goal: a green (or explicitly-gated) bare `make test-client` so client regressions are detectable. Until then, run targeted suites (run-godot --filter <stem>).', 'backlog', 'medium', NULL, 'client', NULL, '2026-05-24 16:49:54', '2026-06-12 10:23:05', NULL, 'f0d9f237aabd31e5f8c0d43d7e626f1e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYEM4VSX74MS4NKQ1C', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'Client test suite — pre-existing failures under bare run-godot', 'Surfaced 2026-05-24 running the full client suite (tests/run-godot, no server) during #960. NOT caused by #960 — verified: test_input_roundtrip fails identically at the pre-change baseline, and the rest are unrelated subsystems. Two categories to triage:
|
||
|
||
CATEGORY 1 — server-dependent (expected-fail under bare run-godot): test_e2e_connection (test_send_input_receive_snapshot), test_input_roundtrip (movement/interact/move_then_interact). They error with ''Nil snapshot'' / ''.tick on Nil'' because no sim server is spawned. They need the run-ipc-* harness or SR_LIVE=1. FIX OPTIONS: gate/skip these under bare run-godot (mark as requiring a server) OR have run-godot spawn the server for the e2e tier, so tests/run-godot
|
||
{"suite":"godot","total":2522,"passed":2482,"failed":40,"duration_ms":96836,"log":"/tmp/sr-run-godot.1737738.log"} is green without false negatives.
|
||
|
||
CATEGORY 2 — genuine logic failures in subsystems unrelated to current work: test_audio_sprint13 (test_d067_chime_duration_spec_is_300_to_400ms, line 547 ''Expecting true but is false''), test_fog_sprint22 (exploration_data_preserved_across_resize), test_fog_shader (visibility_texture_update_performance), test_dialogue_sprint18/20 (signal/audio-dip), test_monologue_display (queue_never_exceeds_max_depth), test_implant_app_lifecycle (on_insert_deactivated_closes_insert_app), test_ai_dialogue_sprint26 (settings_dialog warning label). Triage each: fix or remove/xfail with a reason.
|
||
|
||
Goal: a green (or explicitly-gated) bare `make test-client` so client regressions are detectable. Until then, run targeted suites (run-godot --filter <stem>).
|
||
|
||
Re-homed under maintenance (test-failure debt / suite hygiene) per cascade refocus 2026-06-12.', 'backlog', 'medium', NULL, 'client', NULL, '2026-05-24 16:49:54', '2026-06-12 10:23:05', NULL, '48c6b07c7558342430ef5822e873ce5a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYYR0QJC12EMA0SV1W', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Add East-African-interior heritage token to cultural_specialization taxonomy', 'The #1016 cultural pass found two systems founded by East-African-INTERIOR peoples that the canonical 47-value heritage taxonomy has no token for, so they currently borrow ''swahili'' (a coastal value) as the nearest fit (documented inline in wiki/economics/system_specialization.toml):
|
||
|
||
- GJ 667B Kampala Gate — Baganda/Ugandan (Great Lakes interior)
|
||
- GJ 1292 Moyale — Kenyan/Ethiopian (Borana/Oromo, Horn)
|
||
|
||
(Mwangaza GJ 693 is genuinely coastal Swahili — correct, leave it.)
|
||
|
||
SCOPE: add an appropriate heritage value (or values) to the canonical taxonomy at the nationality/people granularity the taxonomy uses — candidates: a Great Lakes / interior East African token and/or a Horn-of-Africa token. Update:
|
||
1. docs/workshops/system-economic-specialization/heritage-taxonomy-draft.md (canon list + count)
|
||
2. _CULTURAL_HERITAGE in tooling/economy-db/import_economics.py
|
||
3. repin GJ 667B and GJ 1292 in system_specialization.toml to the new value(s)
|
||
4. regen-db + verify (V-SES-04) + commit
|
||
|
||
Surfaced by the PR #147 (#1016) review (Paula HIGH / Miri). Low priority — current ''swahili'' approximation is documented, not silently wrong.', 'backlog', 'low', NULL, 'server', 'D-237', '2026-06-03 08:27:09', '2026-06-12 10:23:06', NULL, 'ec06b91574202a0b7377d07afdd15cde', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYYR0QJC12EMA0SV1W', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Add East-African-interior heritage token to cultural_specialization taxonomy', 'The #1016 cultural pass found two systems founded by East-African-INTERIOR peoples that the canonical 47-value heritage taxonomy has no token for, so they currently borrow ''swahili'' (a coastal value) as the nearest fit (documented inline in wiki/economics/system_specialization.toml):
|
||
|
||
- GJ 667B Kampala Gate — Baganda/Ugandan (Great Lakes interior)
|
||
- GJ 1292 Moyale — Kenyan/Ethiopian (Borana/Oromo, Horn)
|
||
|
||
(Mwangaza GJ 693 is genuinely coastal Swahili — correct, leave it.)
|
||
|
||
SCOPE: add an appropriate heritage value (or values) to the canonical taxonomy at the nationality/people granularity the taxonomy uses — candidates: a Great Lakes / interior East African token and/or a Horn-of-Africa token. Update:
|
||
1. docs/workshops/system-economic-specialization/heritage-taxonomy-draft.md (canon list + count)
|
||
2. _CULTURAL_HERITAGE in tooling/economy-db/import_economics.py
|
||
3. repin GJ 667B and GJ 1292 in system_specialization.toml to the new value(s)
|
||
4. regen-db + verify (V-SES-04) + commit
|
||
|
||
Surfaced by the PR #147 (#1016) review (Paula HIGH / Miri). Low priority — current ''swahili'' approximation is documented, not silently wrong.
|
||
|
||
Re-parented under Phase 4 epic per cascade refocus 2026-06-12 — cultural_specialization taxonomy is a generation-input data fix (D-237).', 'backlog', 'low', NULL, 'server', 'D-237', '2026-06-03 08:27:09', '2026-06-12 10:23:06', NULL, 'e72c53971dca82a234a7129493fbfca0', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ9NXNX40J476N2EQM', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Persist deterministic cascade output (build-time bake or local cache)', 'Deferred from the #955 pair session. The Phase-4 cascade (Layers 0-5) is fully deterministic (D-010 + SeedChain) — its output (settlement placements, and eventually the full BodyWorldState) is a pure function of (heightmap, authored context, world seed), so it can be cached rather than re-derived on every cold load.
|
||
|
||
CONSTRAINT: systems.db is read-only from the server''s perspective (schema header) — the runtime server CANNOT write it. So a persistent cache is one of:
|
||
(A) Build-time whole-cascade bake into systems.db (a tool runs the Rust cascade, bakes BodyWorldState/placements; runtime reads). Matches the D-223/#951 ''cascade fills the geometry tables'' intent; staleness handled by the existing meta-stamp. Cost: committed binary artifact + re-bake on input change.
|
||
(B) Runtime local cache in a gitignored .cache/ keyed by (world_seed, schema_version, body_id), written on first derive, read after. No commit/merge issues; per-machine first-derive cost.
|
||
|
||
DESIGN DECISION NEEDED: A vs B (or both — A for shipped worlds, B for dev iteration).
|
||
|
||
WHY DEFERRED (not now): (1) every cascade layer is a PURE function, so a cache wraps it later at ZERO retrofit — determinism makes deferral free. (2) Layer-2 inputs are still churning (#1014/#982 dominant-commodity, #977 trait_selection, #956 political archetype all change placement inputs) — a bake now would be stale/constantly re-baked. (3) Bake the WHOLE cascade once it is end-to-end (post Layer 5, #959), not one layer. (4) No measured perf need yet (Layer 3 = Hungarian on a small grid).
|
||
|
||
TRIGGER: pick this up when the cascade is end-to-end (after #959) OR the Layer-2 context freezes — whichever first. The in-memory hot cache (BodyWorldState / D-203, #968) already covers ''no IO while on a system''; this ticket is only about cross-session/cold-load persistence.
|
||
|
||
Seam: run_layer3 (and each run_layerN) is pure — wrap at the run_cascade call site (a // cache seam comment marks it).', 'backlog', 'low', NULL, 'server', 'D-200', '2026-06-03 10:46:13', '2026-06-12 10:23:06', NULL, '1bf12c7eeaa86d0d9cfac470577f0419', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ9NXNX40J476N2EQM', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Persist deterministic cascade output (build-time bake or local cache)', 'Deferred from the #955 pair session. The Phase-4 cascade (Layers 0-5) is fully deterministic (D-010 + SeedChain) — its output (settlement placements, and eventually the full BodyWorldState) is a pure function of (heightmap, authored context, world seed), so it can be cached rather than re-derived on every cold load.
|
||
|
||
CONSTRAINT: systems.db is read-only from the server''s perspective (schema header) — the runtime server CANNOT write it. So a persistent cache is one of:
|
||
(A) Build-time whole-cascade bake into systems.db (a tool runs the Rust cascade, bakes BodyWorldState/placements; runtime reads). Matches the D-223/#951 ''cascade fills the geometry tables'' intent; staleness handled by the existing meta-stamp. Cost: committed binary artifact + re-bake on input change.
|
||
(B) Runtime local cache in a gitignored .cache/ keyed by (world_seed, schema_version, body_id), written on first derive, read after. No commit/merge issues; per-machine first-derive cost.
|
||
|
||
DESIGN DECISION NEEDED: A vs B (or both — A for shipped worlds, B for dev iteration).
|
||
|
||
WHY DEFERRED (not now): (1) every cascade layer is a PURE function, so a cache wraps it later at ZERO retrofit — determinism makes deferral free. (2) Layer-2 inputs are still churning (#1014/#982 dominant-commodity, #977 trait_selection, #956 political archetype all change placement inputs) — a bake now would be stale/constantly re-baked. (3) Bake the WHOLE cascade once it is end-to-end (post Layer 5, #959), not one layer. (4) No measured perf need yet (Layer 3 = Hungarian on a small grid).
|
||
|
||
TRIGGER: pick this up when the cascade is end-to-end (after #959) OR the Layer-2 context freezes — whichever first. The in-memory hot cache (BodyWorldState / D-203, #968) already covers ''no IO while on a system''; this ticket is only about cross-session/cold-load persistence.
|
||
|
||
Seam: run_layer3 (and each run_layerN) is pure — wrap at the run_cascade call site (a // cache seam comment marks it).
|
||
|
||
Re-parented under Phase 4 epic per cascade refocus 2026-06-12 — cascade-output persistence; trigger remains end-to-end cascade (post #959) or Layer-2 context freeze.', 'backlog', 'low', NULL, 'server', 'D-200', '2026-06-03 10:46:13', '2026-06-12 10:23:06', NULL, '3c1d1e516c50c02cc3064888b530ca27', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW7FZPYXXCGWBBRBEC', 'initiative', NULL, 'v0.2 Life-Sim Pivot', 'Generator-first life sim pivot following the Where''s the Fun? workshop (2026-03-05). 24 decisions locked: all NPCs generated, tycoon bookmark, culture-implicit-in-location, broad life verbs, dual-scale consequence model. Detective/smuggler framing retired. Critical path: Sprint 25 generator spike. See docs/workshops/wheres-the-fun/workshop-outcomes.md.', 'cancelled', 'critical', NULL, NULL, NULL, '2026-03-05 23:11:31', '2026-06-12 10:23:06', NULL, 'aa6302dbd4a06a68ef49847672d55a98', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW7FZPYXXCGWBBRBEC', 'initiative', NULL, 'v0.2 Life-Sim Pivot', 'Generator-first life sim pivot following the Where''s the Fun? workshop (2026-03-05). 24 decisions locked: all NPCs generated, tycoon bookmark, culture-implicit-in-location, broad life verbs, dual-scale consequence model. Detective/smuggler framing retired. Critical path: Sprint 25 generator spike. See docs/workshops/wheres-the-fun/workshop-outcomes.md.
|
||
|
||
Cancelled 2026-06-12: the v0.2 Life-Sim Pivot initiative shell — the v0.2 target is dropped (D-166, amendment 2026-06-12; D-114/D-115/D-117/D-118/D-120 superseded). Its children with surviving functional content (T-604 proof-of-life playtest concept, T-605 tycoon bookmark, T-606 creation flow, T-608 world feel) are preserved under the post-cascade gameplay parking epic T-1036.', 'cancelled', 'critical', NULL, NULL, NULL, '2026-03-05 23:11:31', '2026-06-12 10:23:06', NULL, 'f274d9d9b2b4e4d642160d2a5939e400', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXXP903QTD8Q2YWRJ8', 'story', NULL, 'One campaign or separate eras', NULL, 'cancelled', 'medium', NULL, NULL, 'Q-004', '2026-02-09 15:21:44', '2026-06-12 10:23:06', NULL, '02d52e37abbfcc5c53bc5102a7bcca63', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXXP903QTD8Q2YWRJ8', 'story', NULL, 'One campaign or separate eras', 'Cancelled 2026-06-12: administrative mirror of Q-004 (resolved); no surviving open requirement.', 'cancelled', 'medium', NULL, NULL, 'Q-004', '2026-02-09 15:21:44', '2026-06-12 10:23:06', NULL, 'b7de7f9179cf45b865a5213b4ef73f71', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZYTPACQCYNGVK5XSC', 'story', NULL, 'Prototype scale', NULL, 'cancelled', 'medium', NULL, NULL, 'Q-005', '2026-02-09 15:21:44', '2026-06-12 10:23:06', NULL, '98d983109528446550201f10d509f082', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZYTPACQCYNGVK5XSC', 'story', NULL, 'Prototype scale', 'Cancelled 2026-06-12: administrative mirror of Q-005 (resolved); no surviving open requirement.', 'cancelled', 'medium', NULL, NULL, 'Q-005', '2026-02-09 15:21:44', '2026-06-12 10:23:06', NULL, '187fa74f3477b1c151aab02f1141e09f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW3ASVAZZNYN9M59AW', 'story', NULL, 'Target platforms', NULL, 'cancelled', 'medium', NULL, NULL, 'Q-007', '2026-02-09 15:21:44', '2026-06-12 10:23:06', NULL, '4b73cb10b8de519d6ff097d1f6cffb1c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW3ASVAZZNYN9M59AW', 'story', NULL, 'Target platforms', 'Cancelled 2026-06-12: administrative mirror of Q-007 (resolved); no surviving open requirement.', 'cancelled', 'medium', NULL, NULL, 'Q-007', '2026-02-09 15:21:44', '2026-06-12 10:23:06', NULL, '858b65923473224fabb431a3fd8901bb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWJYV3ZVY7D7G3P4FW', 'story', NULL, 'Character selection roster', NULL, 'cancelled', 'medium', NULL, NULL, 'Q-011', '2026-02-09 15:21:44', '2026-06-12 10:23:06', NULL, '59062c659a8bbaafed2b1b1aa3ae7114', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWJYV3ZVY7D7G3P4FW', 'story', NULL, 'Character selection roster', 'Cancelled 2026-06-12: administrative mirror of Q-011 (resolved); no surviving open requirement.', 'cancelled', 'medium', NULL, NULL, 'Q-011', '2026-02-09 15:21:44', '2026-06-12 10:23:06', NULL, '167022f80bd2d726d24acf15ad1d2a9f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWXPRPS7G2MA786GR0', 'initiative', NULL, 'Map & Navigation', 'Implement D-010 (information boundaries), D-012 (chunk-based maps), D-013 (diegetic insert/POI navigation), D-014 revised (station district map). World structure and player navigation.', 'cancelled', 'high', NULL, NULL, 'D-010, D-012, D-013, D-014', '2026-02-10 23:14:31', '2026-06-12 10:23:06', NULL, '61398f7c2b04f52e511045b668574972', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWXPRPS7G2MA786GR0', 'initiative', NULL, 'Map & Navigation', 'Implement D-010 (information boundaries), D-012 (chunk-based maps), D-013 (diegetic insert/POI navigation), D-014 revised (station district map). World structure and player navigation.
|
||
|
||
Cancelled 2026-06-12: pre-cascade umbrella emptied by the cascade refocus — children re-homed (T-50/T-52 to Phase 4, T-49/T-51 to Phase 5).', 'cancelled', 'high', NULL, NULL, 'D-010, D-012, D-013, D-014', '2026-02-10 23:14:31', '2026-06-12 10:23:06', NULL, '95c525f21dd7543ce253a5740edc5c82', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY3XYFKDGVPQR87JHM', 'initiative', NULL, 'Content Architecture', 'Implement D-023 (three-tier content model), D-025 (social site templates), D-028 (dialogue system), D-029 (population entanglement). Template system and dialogue.', 'cancelled', 'high', NULL, NULL, 'D-023, D-025, D-028, D-029', '2026-02-10 23:14:31', '2026-06-12 10:23:06', NULL, 'd8df203786f39c6e92a9d2913e10fe92', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY3XYFKDGVPQR87JHM', 'initiative', NULL, 'Content Architecture', 'Implement D-023 (three-tier content model), D-025 (social site templates), D-028 (dialogue system), D-029 (population entanglement). Template system and dialogue.
|
||
|
||
Cancelled 2026-06-12: pre-cascade umbrella emptied by the cascade refocus — children re-homed (T-54 to Phase 4, T-55/T-56 to Phase 6, T-53 to gameplay parking T-1036).', 'cancelled', 'high', NULL, NULL, 'D-023, D-025, D-028, D-029', '2026-02-10 23:14:31', '2026-06-12 10:23:06', NULL, '0cbd1450dd90539f8c3832dcbc9d4777', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZK0EWD2NW4D2MGGV0', 'initiative', NULL, 'Testability Infrastructure', 'Build comprehensive testing framework for both Rust/bevy_ecs simulation and Godot 4 client. External test harness, minimal production code pollution. NEEDS REFINEMENT.
|
||
|
||
Cancelled 2026-06-12: pre-cascade umbrella — test-infra children re-homed under maintenance initiative T-1037; discussion child T-64 cancelled (testing approach long established).', 'backlog', 'high', NULL, NULL, NULL, '2026-02-10 23:14:31', '2026-06-12 10:23:06', NULL, 'fec9f2d05551b0cba66b78a3551a0365', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXG2Z9ZAR42SQ9GNP4', 'epic', '06FB0TNSRZK0EWD2NW4D2MGGV0', 'Testability Architecture Refinement', 'Discussion: Jeroen + Tyre + Gestalt + Hoshe + Troblum. Determine optimal testing approach for Claude Code execution. Define patterns, constraints, tooling needs.
|
||
|
||
Cancelled 2026-06-12: discussion premise fulfilled — testing approach established and documented (three-tier strategy, Gauntlet-first, D-239 harness); doc deliverables live on in T-215/T-216/T-217 under T-1037.', 'backlog', 'critical', NULL, NULL, NULL, '2026-02-10 23:17:38', '2026-06-12 10:23:06', NULL, '3e6e5ff3e35895a0ef31c0aa471eaaac', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZS8C6ZGVR5M7D3974', 'story', '06FB0TNSRXG2Z9ZAR42SQ9GNP4', 'Refinement discussion - Multi-agent', 'NEEDS REFINEMENT. Jeroen + Tyre + Gestalt + Hoshe + Troblum. Determine optimal testing approach for Claude Code. External vs integrated, patterns, constraints.', 'cancelled', 'critical', NULL, NULL, NULL, '2026-02-10 23:27:10', '2026-06-12 10:23:06', NULL, '29df606f5a3cb9358100b4f1a045ee95', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZS8C6ZGVR5M7D3974', 'story', '06FB0TNSRXG2Z9ZAR42SQ9GNP4', 'Refinement discussion - Multi-agent', 'NEEDS REFINEMENT. Jeroen + Tyre + Gestalt + Hoshe + Troblum. Determine optimal testing approach for Claude Code. External vs integrated, patterns, constraints.
|
||
|
||
Cancelled 2026-06-12: refinement-discussion artifact; testing approach since decided and documented; surviving doc work in T-215/T-216/T-217.', 'cancelled', 'critical', NULL, NULL, NULL, '2026-02-10 23:27:10', '2026-06-12 10:23:06', NULL, '135f59c8ac7fd5c181164665618c24b6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXMPF6176KB9CSBH2C', 'story', '06FB0TNSRXD5W32VCV5YZY3NX0', 'Auto-generated apartment', 'SPLIT — see #681 (server: apartment generator logic) and #682 (client: visual rendering + first-moment sequence). Original: Player starting apartment is auto-generated to reflect economic position and cultural context. Decision D-136 (First Settled Reach moment: apartment + insert activation). Decision D-126 (Groundhog Day alarm clock homage).', 'cancelled', 'high', NULL, 'server', NULL, '2026-03-05 23:12:44', '2026-06-12 10:23:06', NULL, 'bde5feed7399cfe87c04b2c282a1ad66', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXMPF6176KB9CSBH2C', 'story', '06FB0TNSRXD5W32VCV5YZY3NX0', 'Auto-generated apartment', 'SPLIT — see #681 (server: apartment generator logic) and #682 (client: visual rendering + first-moment sequence). Original: Player starting apartment is auto-generated to reflect economic position and cultural context. Decision D-136 (First Settled Reach moment: apartment + insert activation). Decision D-126 (Groundhog Day alarm clock homage).
|
||
|
||
Cancelled 2026-06-12: administrative split shell — full scope carried by T-681 (Phase 6) and T-682 (gameplay parking); no functional requirement lost.', 'cancelled', 'high', NULL, 'server', NULL, '2026-03-05 23:12:44', '2026-06-12 10:23:06', NULL, '1e10bbf0334bf20ff35499bb2e9fe499', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXAPVCJAZ0ZKGESCP4', 'initiative', NULL, 'Rendering & Perception System', 'Implement D-011 (fog of perception), D-015 (locked camera), D-016 (internal monologue), D-017 (perception modes), D-018 (3-range sound), D-019 (top-down rendering). Client-side observation systems.', 'cancelled', 'critical', NULL, NULL, 'D-011, D-015, D-016, D-017, D-018, D-019', '2026-02-10 23:14:31', '2026-06-12 10:23:06', NULL, 'e4401eadc02e74cef17b1ef213e93dfa', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXAPVCJAZ0ZKGESCP4', 'initiative', NULL, 'Rendering & Perception System', 'Implement D-011 (fog of perception), D-015 (locked camera), D-016 (internal monologue), D-017 (perception modes), D-018 (3-range sound), D-019 (top-down rendering). Client-side observation systems.
|
||
|
||
Cancelled 2026-06-12: pre-cascade umbrella emptied by the cascade refocus — perception/rendering epics re-homed under Phase 5 (T-43–T-48), T-234 observation/interaction loop preserved in gameplay parking T-1036.', 'cancelled', 'critical', NULL, NULL, 'D-011, D-015, D-016, D-017, D-018, D-019', '2026-02-10 23:14:31', '2026-06-12 10:23:06', NULL, '6101d3b9b540d1dba1e6fa1c14334255', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXXEKGTNRJ7Z6FTDRM', 'initiative', NULL, 'Engine Architecture - Godot + Rust IPC', 'Implement D-020: Godot 4 client + Rust/bevy_ecs simulation via subprocess/IPC. MessagePack protocol, ObserverSnapshot pattern, deterministic simulation.', 'done', 'critical', NULL, NULL, 'D-020', '2026-02-10 23:14:11', '2026-06-12 10:23:06', NULL, '03ca8a84bebb780a80b87e5b4ac28130', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXXEKGTNRJ7Z6FTDRM', 'initiative', NULL, 'Engine Architecture - Godot + Rust IPC', 'Implement D-020: Godot 4 client + Rust/bevy_ecs simulation via subprocess/IPC. MessagePack protocol, ObserverSnapshot pattern, deterministic simulation.
|
||
|
||
Closed 2026-06-12: engine architecture delivered (T-35–T-38 done); the one open child (T-235 game state management) re-homed under Phase 5 epic T-749. Umbrella complete.', 'done', 'critical', NULL, NULL, 'D-020', '2026-02-10 23:14:11', '2026-06-12 10:23:06', NULL, 'b481c1488565c0b7a0457c3454b3a367', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY5G9GMPV8B0RDD1JR', 'initiative', NULL, 'Fog of perception non-negotiable', NULL, 'done', 'medium', NULL, NULL, 'D-011', '2026-02-09 15:21:44', '2026-06-12 10:23:07', NULL, '72ba932e57b004c9e757e0627496adc6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY5G9GMPV8B0RDD1JR', 'initiative', NULL, 'Fog of perception non-negotiable', 'Closed 2026-06-12: decision-mirror initiative for D-011 (fog of perception non-negotiable). D-011 is confirmed and the fog/perception system is implemented (shadowcasting, vision cone, observer snapshots); the mirror served its purpose. Cleared from the perpetual review queue.', 'done', 'medium', NULL, NULL, 'D-011', '2026-02-09 15:21:44', '2026-06-12 10:23:07', NULL, '26db2495bc0c57c0411dc6ffcd123da3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZE4CSS8YR0FCEXMK8', 'initiative', NULL, 'Development Cascade — 6-phase first-things-first build order', 'The Settled Reach builds core system to core system in strict cascade order. Each phase completes before the next begins. No scoping negotiations, no v0.2 target. Established 2026-03-24 during world generation workshop. See CLAUDE.md for the full cascade table.', 'in_progress', 'critical', NULL, NULL, NULL, '2026-03-25 13:28:54', '2026-06-12 10:23:07', NULL, '77e2967b4c7c1916c90b3a1320d08716', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXG2Z9ZAR42SQ9GNP4', 'epic', '06FB0TNSRZK0EWD2NW4D2MGGV0', 'Testability Architecture Refinement', 'Discussion: Jeroen + Tyre + Gestalt + Hoshe + Troblum. Determine optimal testing approach for Claude Code execution. Define patterns, constraints, tooling needs.
|
||
|
||
Cancelled 2026-06-12: discussion premise fulfilled — testing approach established and documented (three-tier strategy, Gauntlet-first, D-239 harness); doc deliverables live on in T-215/T-216/T-217 under T-1037.', 'cancelled', 'critical', NULL, NULL, NULL, '2026-02-10 23:17:38', '2026-06-12 10:23:17', NULL, '232d6129e2016ef3d34b1968d322a881', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXG2Z9ZAR42SQ9GNP4', 'epic', '06FB0TNSRZK0EWD2NW4D2MGGV0', 'Testability Architecture Refinement', 'Discussion: Jeroen + Tyre + Gestalt + Hoshe + Troblum. Determine optimal testing approach for Claude Code execution. Define patterns, constraints, tooling needs.
|
||
|
||
Cancelled 2026-06-12: discussion premise fulfilled — testing approach established and documented (three-tier strategy, Gauntlet-first, D-239 harness); doc deliverables live on in T-215/T-216/T-217 under T-1037.
|
||
|
||
Cancelled 2026-06-12: discussion premise fulfilled — testing approach established and documented (three-tier strategy, Gauntlet-first, D-239 harness); doc deliverables live on in T-215/T-216/T-217 under T-1037.', 'cancelled', 'critical', NULL, NULL, NULL, '2026-02-10 23:17:38', '2026-06-12 10:23:17', NULL, '7d0b7fdb0c114f9307b9c392173c3b4f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZK0EWD2NW4D2MGGV0', 'initiative', NULL, 'Testability Infrastructure', 'Build comprehensive testing framework for both Rust/bevy_ecs simulation and Godot 4 client. External test harness, minimal production code pollution. NEEDS REFINEMENT.
|
||
|
||
Cancelled 2026-06-12: pre-cascade umbrella — test-infra children re-homed under maintenance initiative T-1037; discussion child T-64 cancelled (testing approach long established).', 'cancelled', 'high', NULL, NULL, NULL, '2026-02-10 23:14:31', '2026-06-12 10:23:17', NULL, '9dfd8085ccf2ad48acc1aebf61e46dc1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZK0EWD2NW4D2MGGV0', 'initiative', NULL, 'Testability Infrastructure', 'Build comprehensive testing framework for both Rust/bevy_ecs simulation and Godot 4 client. External test harness, minimal production code pollution. NEEDS REFINEMENT.
|
||
|
||
Cancelled 2026-06-12: pre-cascade umbrella — test-infra children re-homed under maintenance initiative T-1037; discussion child T-64 cancelled (testing approach long established).
|
||
|
||
Cancelled 2026-06-12: pre-cascade umbrella — test-infra children re-homed under maintenance initiative T-1037; discussion child T-64 cancelled (testing approach long established).', 'cancelled', 'high', NULL, NULL, NULL, '2026-02-10 23:14:31', '2026-06-12 10:23:17', NULL, '7df7fb4a456a62bce10e65ca10c93f60', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRX3R6G3Y7QR4FAJPNM', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Wiki to Atlas content-set consolidation (Q-107, blocked)', 'Consolidate all wiki content (pages + heightmaps + markers + architecture-flavor) into one first-class, baked Atlas/gamedata content set with a unified bake pipeline -- instead of per-feature file conventions. Resolves where authored per-body content lives (the D-232 flavor source). BLOCKED on Q-107 (open question -- the target tree structure must be decided first). The generator-facing trait_templates + atlas_body_trait_bias tables (D-232) is invariant to this, so it does NOT block the fill seam; sequence this AFTER the fill-seam work. Jeroen: ''the wiki needs to become part of the atlas content set ... not yet another hack.''
|
||
|
||
Hygiene note 2026-06-12: title says ''blocked'' but no blocker edge exists, so this surfaced in the --unblocked feed. Labelled needs-decision; genuinely gated on Q-107 (wiki→Atlas content consolidation) — resolve Q-107 before picking this up.', 'backlog', 'low', NULL, 'server', 'Q-107', '2026-05-25 19:09:10', '2026-06-12 10:23:21', NULL, 'f2c2f8265f943f2441ea521aa63b716d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ8Z6NN74YKCCRCPMR', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Generation validation pass + Phase 5 dependency gate', 'Validation pass: generated content reads correctly (settlements legible, walkable, named). Establishes the dependency gate that locks Phase 5 (player control, epic #749) behind Phase 4 completion per the cascade rule (D-166 amended 2026-05-22).
|
||
|
||
Gate trigger updated per D-166 amendment (2026-06-12): Phase 5 ramps in parallel once OUTSIDE generation produces deterministic, walkable exteriors — the gate this ticket holds is ''outsides generate deterministically and are walkable'' (validation pass: settlements legible, walkable, named), not ''all Phase-4 polish complete''. Door-boundary contracts and remaining Phase-4 detail may continue alongside early Phase-5 work.', 'backlog', 'medium', NULL, 'server', 'D-166', '2026-05-22 17:42:34', '2026-06-12 10:23:21', NULL, '4c0e71f60b98b366e6c2f7605ef4d2b1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ02F02JDDBSFMGPX0XASR', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Layer 2 — inter-settlement road/rail graph (MST + A* over terrain cost, MaintenanceAuthority, named-route identity)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.', 'backlog', 'high', NULL, 'server', 'D-211', '2026-06-12 10:23:49', '2026-06-12 10:23:49', NULL, '08588aaf4eda07347d750feb1ea23e3c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ02F02JDDBSFMGPX0XASR', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Layer 2 — inter-settlement road/rail graph (MST + A* over terrain cost, MaintenanceAuthority, named-route identity)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
Generate the inter-settlement road/rail graph at Layer 2 — the workshopped-but-never-ticketed link between settlement placement (T-955/T-956, done) and everything that consumes transport topology. No road code exists today (zero RoadGraph/road_segment hits in server/src; TerritorialStatus shipped without its road-coverage inputs).
|
||
|
||
Scope (algorithm fully decided, docs/workshops/planet-down-cascade/tyre-round1.md:274-299):
|
||
1. MST force-connect all CityPlacements (Euclidean), then secondary direct links for city pairs within 30-60% of body scale whose MST path exceeds 1.5x Euclidean.
|
||
2. Route each edge with A* over the L1 terrain-cost field (terrain_modification_cost, D-210, server/src/atlas/subbiome.rs; cost spec: water impassable, roughness>0.7 = 10.0, river corridor = 0.5, flat = 1.0 — rivers as preferred valley routes). Budget ~30ms/body (round-1-notes.md:348).
|
||
3. Assign MaintenanceAuthority per edge from endpoint relationships (5-value enum Administrative/Corporate/Communal/Trade/Abandoned — generation-cascade/workshop-outcomes.md:177, resolution :257; player-readable in road condition per ozzie-round1.md:86-92).
|
||
4. Place waypoint sub-settlement nodes at midpoints of edges > ~12 regional cells (tyre-round1.md:267-272).
|
||
5. Named-route identity assignment: post-generation join of generated edges to systems.db named highway routes via optional named_route_id FK (paula-round1.md:107,:140; round-1-notes.md:322 L2-Q3 resolution under Amendment 3).
|
||
6. RailHeadFacing second pass: settlements at high-connectivity road/rail junctions get FoundingOrientation::RailHeadFacing, overriding AdminFacing-from-Synthetic (paula-round3.md:218-236) — wire into attractor_matching.rs.
|
||
|
||
Storage: RoadGraph{nodes,edges} on BodyWorldState (round-1-notes.md:257-267), session-cached, never serialized — runtime Rust, not systems.db (the atlas_road_nodes/atlas_road_edges schema shape carries forward per tyre-round1.md:42 but lives in session memory).
|
||
|
||
Downstream consumers (do NOT scope in, but design the output for them): road_entry_directions per city (see road-entry-octants ticket; generation-cascade/round-3-notes.md:104), TerritorialStatus quantitative road-coverage thresholds (round-1-notes.md:329-338), per-economic_role hinterland fill (round-1-notes.md:324-327, BRIEF.md:279), prosperity/atlas overlays.
|
||
|
||
Cascade-first fit: this is direction step (2) — the econ layer drawn onto the world between settlements. Parent: T-750. Suggested deps: blocks the road-entry-octants ticket; references D-205 (provinces), D-210, D-211, D-212, D-213.', 'backlog', 'high', NULL, 'server', 'D-211', '2026-06-12 10:23:49', '2026-06-12 10:23:49', NULL, 'c40784a5ec08335377f6792c59db914d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ02KN9147H4Z12KJW7H1M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Thread political_archetype / arrangement_pattern / morphology_zone through the L3→L4 GenerateSkeleton dispatch', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.', 'backlog', 'high', NULL, 'server', 'D-234', '2026-06-12 10:23:49', '2026-06-12 10:23:49', NULL, '01610fdfddc224719cf3550b15b51724', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ02KN9147H4Z12KJW7H1M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Thread political_archetype / arrangement_pattern / morphology_zone through the L3→L4 GenerateSkeleton dispatch', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
Thread the remaining Layer-3 character fields through the L3->L4 GenerateSkeleton dispatch. T-1022 wired the dispatch, but build_skeleton_work_item (server/src/atlas/plugin.rs:179-212) overrides only founding_orientation (:192-193); political_archetype stays the Commission stub (city_context_reader.rs:471-474) and morphology_zone stays AlluvialPlain (:487-488) even though:
|
||
- CityPlacement already carries the real political_archetype (D-214, derived from TerritorialStatus + economic_role at attractor_matching.rs:595-602) and arrangement_pattern (D-215, city_character at :282-293) — fields :49-64;
|
||
- the covering region''s real morphology_zone (D-239 §6 frozen vocab, T-1027, region_profile.rs:180/:499) is available from snapshot.layer_region, populated in the same cascade run (cascade.rs:238-240) — map placement.position to its covering region cell.
|
||
|
||
Consequences of the stubs: skeleton_gen''s morphology gating (D-234a Topology selection) always takes the AlluvialPlain Prim-MST mesh path — fjord/delta cities get plains street networks; block_irregularity/layout-mode always sees Commission (skeleton_gen.rs:68-77). D-234''s implementation note explicitly lists this threading as the pending dependency of the (done, tested, dormant) morphology-gated street rules.
|
||
|
||
Also decide arrangement_pattern''s path: CityGenerationContext has NO arrangement_pattern field (generator.rs:1078 has political_archetype only; ArrangementPattern :442 is defined but unconsumed at L4). Either (a) add the field and have skeleton_gen consume the D-215 explicit pattern, or (b) record that L4 derives layout from archetype alone and the placement''s pattern is Atlas/UI-only. Option (a) matches the workshop intent (ozzie-round1.md:112-118 backs explicit arrangement).
|
||
|
||
Miri''s queryability requirement (tile-derivation-contract/tyre-round1.md:308-311) — morphology_zone readable at Atlas-generation time — is satisfied by reading from BodyWorldState regions, no recompute.
|
||
|
||
Acceptance: dispatch a body with a FjordWall-region coastal placement in a CorpTerritory province -> the generated quarter uses Ribbon topology and CompanyTown-class layout, not mesh+Commission. Parent: T-750. Refs: D-214, D-215, D-228, D-234, D-239 §6; T-1022 (predecessor), T-983, T-1014 (adjacent, different fields).', 'backlog', 'high', NULL, 'server', 'D-234', '2026-06-12 10:23:49', '2026-06-12 10:23:49', NULL, '5079cc1b2a704183c368b377244a8a4e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ02QTVSZ1PXTGNCN6Y8KM', 'bug', '06FB0TNSRZXCHGS16BFHSSGSV4', 'BUG: river channel centrelines anchored to the world-origin axis — channels absent in almost every chunk', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.', 'backlog', 'high', NULL, 'server', 'D-239', '2026-06-12 10:23:49', '2026-06-12 10:23:49', NULL, '14718b3824035133a5f018e209941e99', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ02QTVSZ1PXTGNCN6Y8KM', 'bug', '06FB0TNSRZXCHGS16BFHSSGSV4', 'BUG: river channel centrelines anchored to the world-origin axis — channels absent in almost every chunk', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
BUG: channel centrelines are anchored to the world-origin axis. compute_channel_state (AlluvialPlain, server/src/atlas/voxel.rs:1648-1707) and compute_meander_channel_state (MeanderReach, :1556-1595) compute perp_distance = (cross - meander_displacement).abs() (:1694, :1583) where cross is the raw world-space voxel coordinate (derive_voxel_column takes tile_x/tile_y in world metres, :328-338; cross = vx or vy at :1653-1661). The channel centreline is therefore the world x=0/y=0 axis plus-or-minus meander amplitude: only chunks within ~(channel_width/2 + amplitude + jitter) metres of the world origin axis ever contain channel water, regardless of ChunkContext.has_active_channel / channel_width_m (chunk_context.rs:103-110). in_levee_band (:1602-1633) inherits the same defect, so levees are origin-locked too. Every has_active_channel chunk elsewhere on the body silently renders dry floodplain.
|
||
|
||
Intended model (workshopped): channel positions derive from region/chunk-scale data, not world axes — D-239 §10 (one basin-direction + global meander-curve params; wavelength > 64 m seeds Region-or-higher) and tile-derivation-contract/gestalt-round1.md:152-162 (channel branch positions from a multi-seed Voronoi partition of the chunk area with D8 flow direction as attractor; meander_intensity controls deviation from the straight downslope path).
|
||
|
||
Fix, two stages:
|
||
1. Minimal correctness: derive a deterministic cross-offset channel anchor at region scale (alongside meander_phase in derive_chunk_context, chunk_context.rs:124-141 — same Region-or-higher seed path) and measure perp_distance from that anchor, so an active channel actually crosses the chunks the region says it crosses, continuously across chunk boundaries.
|
||
2. Full model: gestalt''s multi-seed Voronoi + D8-attractor branch placement when BraidedDelta sub-classification (D-239 implementation note: deferred to ChunkContext) lands.
|
||
|
||
Add a T-1031-harness believability check: a has_active_channel chunk at an arbitrary large world offset (e.g. chunk_pos (1000, -750)) contains in-channel voxels; channel position is continuous across adjacent chunk pairs. Sibling bug: landform-64m-repeat (same family, opposite direction — channels appear nowhere, landforms appear everywhere). Parent: T-750. Refs: D-239 §10, D-208 (D8), D-010; T-1029 (origin), T-1031 (harness).', 'backlog', 'high', NULL, 'server', 'D-239', '2026-06-12 10:23:49', '2026-06-12 10:23:49', NULL, 'f260380c0c57cab5233fc47a0b220461', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ02VWJGXWDYT2SMXM9DTC', 'bug', '06FB0TNSRZXCHGS16BFHSSGSV4', 'BUG: fjord/cliff/gorge/delta landforms repeat on the 64 m chunk grid (D-239 §10 violation)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.', 'backlog', 'high', NULL, 'server', 'D-239', '2026-06-12 10:23:49', '2026-06-12 10:23:49', NULL, 'be00a918d51ac4a1529097175f01dcd2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ02VWJGXWDYT2SMXM9DTC', 'bug', '06FB0TNSRZXCHGS16BFHSSGSV4', 'BUG: fjord/cliff/gorge/delta landforms repeat on the 64 m chunk grid (D-239 §10 violation)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
BUG: four morphology generators fold world coordinates into the 64 m chunk frame, so region-scale landforms repeat every chunk — violating D-239 §10 (''features with wavelength > 64 m seed from Region-or-higher, not the chunk seed''; deliberately strengthened from Block-or-higher in the adversarial verification pass, tile-derivation-contract/workshop-outcomes.md:83).
|
||
|
||
Sites (server/src/atlas/voxel.rs):
|
||
- generate_fjord_wall :594-597 — cross.rem_euclid(64)-32: a complete fjord (floor|moraine|wall cross-section) centred in EVERY chunk of a FjordWall region; a real fjord valley is one feature spanning the region.
|
||
- generate_cliff_coast :721 — seaward_coord.rem_euclid(64): the cliff face sits at intra-chunk offset 48-55 in every chunk, sawtoothing the coastline at 64 m pitch.
|
||
- generate_braided_delta :825 — cross.rem_euclid(64): the same three braid threads restart per chunk instead of anastomosing across the fan.
|
||
- generate_incised_gorge :1054-1057 — same fold: a gorge per chunk.
|
||
|
||
Fix: compute each landform''s axis/centreline in REGION-anchored coordinates — derive the feature anchor (centreline position, coast-face line) once per region from the region-scale seed path that meander_phase/basin_direction already use correctly (chunk_context.rs:124-141), then measure each voxel''s distance to that anchor in continuous world coordinates (no rem_euclid against the chunk size). This matches the workshop''s seam-freedom principle: the algorithm must see positions with no knowledge of the chunk grid (tyre-round1.md:174-176). Preserve D-239 §9 chokepoint widths (fjord floor 4-8 m, gorge floor 2-8 m — currently honoured at :607-609, :1059-1062).
|
||
|
||
Harness gap to close (T-1031 follow-up): current tests check per-chunk boundary smoothness, not feature uniqueness — add a multi-chunk assertion that a FjordWall/IncisedGorge region contains ONE valley spanning its chunks, and a CliffCoast region one continuous (warp-displaced) coast line. Sibling bug: river-channel-anchor (channels are origin-anchored and appear nowhere; landforms are chunk-folded and appear everywhere — fix both against the same region-anchor mechanism). Depends on scale-anchoring Q for the region''s physical extent, but the region-index anchor works regardless. Parent: T-750. Refs: D-239 §5/§8/§9/§10, D-010; T-1029, T-1031.', 'backlog', 'high', NULL, 'server', 'D-239', '2026-06-12 10:23:49', '2026-06-12 10:23:50', NULL, '47206289748cad953d760f41bd60fb03', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ0308CFF9WKNGBBYQ763W', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Cross-region parameter blending at chunk/voxel scale (replace single-profile walking skeleton)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.', 'backlog', 'medium', NULL, 'server', 'D-239', '2026-06-12 10:23:50', '2026-06-12 10:23:50', NULL, '2d06c86d7704f839f8e18d491d060b84', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ0308CFF9WKNGBBYQ763W', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Cross-region parameter blending at chunk/voxel scale (replace single-profile walking skeleton)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
Implement cross-region parameter blending at the chunk/voxel scale, replacing the walking-skeleton single-profile restriction (server/src/atlas/chunk_context.rs:119-123: ''in the future a blend of adjacent profiles will handle cross-region chunk seams''). Today every voxel generator reads the one covering RegionProfile''s values directly (region.elev_q at voxel.rs:614, :731, :1067-1068; channel/meander params likewise), so continuous parameters step discontinuously at every region-grid border — elevation cliffs at the region pitch, visible as a grid at Atlas/voxel scale.
|
||
|
||
Design is decided — stay inside the D-239 §7 seam policy:
|
||
- NEVER blend morphology family selection. Family seams are prevented at source (gate ordering + build-time compatibility matrix) or kept sharp (cliff-fjord, lithology faults are real geology). Tyre''s cross-family elevation-blend was explicitly resolved against (D-239 dissent line).
|
||
- DO blend continuous positional parameters: elevation, channel width, meander wavelength/phase, freeze/moisture scalars. Mechanism from tile-derivation-contract/tyre-round1.md: ChunkContext gains secondary: Option<RegionProfile> + blend_weight: u8 (255 = fully primary; :123-125), blend zone one chunk (64 m) each side of the region border (:101-102); derive_voxel resolves parameters from both profiles and integer-blends BEFORE material selection (:217-220), reusing the same warp offset so the blend seam cannot align with the chunk edge; elevation sampled bilinearly from the region grid to chunk resolution (:130, the elevation_grid sketch).
|
||
- D-010 discipline: integer blend arithmetic; the f64 path only for position math per D-239 §4.
|
||
|
||
Note: region size in metres is currently ambiguous (see the scale-anchoring Q-record) — the blend can be implemented against the region grid index regardless, but the Q should be resolved before tuning blend-zone width in metres.
|
||
|
||
Acceptance: T-1031 harness cross-region chunk pairs show no elevation step exceeding the lithology-permitted slope (D-239 §8) at region borders; family seams remain sharp; determinism golden-seed unchanged for chunks far from borders. Parent: T-750. Refs: D-239 §4/§7/§8, D-010; Q-102; T-1026/T-1028/T-1029 (predecessors).', 'backlog', 'medium', NULL, 'server', 'D-239', '2026-06-12 10:23:50', '2026-06-12 10:23:50', NULL, 'fb33e89b93753d08f1056f28a9dcf6dc', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ034DKN4ENSGX5HTYTBJG', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Derive road_entry_directions at L3 and thread through the dispatch (interim: MST-neighbor bearings + water_bearing)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.', 'backlog', 'medium', NULL, 'server', 'D-234', '2026-06-12 10:23:50', '2026-06-12 10:23:50', NULL, '4b3a52bda75e3abf6bed5fbbb566a76c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ034DKN4ENSGX5HTYTBJG', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Derive road_entry_directions at L3 and thread through the dispatch (interim: MST-neighbor bearings + water_bearing)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
Derive road_entry_directions at Layer 3 and thread them through the GenerateSkeleton dispatch. CityGenerationContext.road_entry_directions (server/src/simulation/generator.rs:1083-1084, compass octants 0=N..7=NW) is stubbed empty (city_context_reader.rs:478-479) and never overridden by the T-1022 dispatch, so derive_access_points (skeleton_gen.rs:1008-1036) never emits QuarterEdge access nodes — every quarter falls back to reservation gates or a single central BlockJunction (:1029-1034), and the D-234 arterial graph has no outward connection to the world.
|
||
|
||
Workshop contract: the field is a per-city output of the inter-settlement road graph (generation-cascade/round-3-notes.md:104 ''Layer C: Road graph (road_entry_directions per city)''; burnelli-sheldon-round4.md:308). Full-fidelity derivation therefore lands with the inter-settlement-transport ticket: octant = bearing of each connecting road edge where it crosses the city footprint radius (D-204 footprint), de-duplicated per octant, retaining per-entry quality for the consumer rule below.
|
||
|
||
Interim derivation (no road graph required, deterministic, replace-don''t-rework): derive octants at L3 from (a) bearings to the settlement''s MST-neighbor placements (positions already in BodyWorldState.placements) and (b) the founding-orientation water bearing (TerrainAnalysis::water_bearing, 8-octant integer — D-234 implementation note) for port/river settlements. Thread through build_skeleton_work_item (plugin.rs:179-212) next to the founding_orientation override.
|
||
|
||
Consumer rule to honour (already decided): the AdminFacing arrangement pattern picks its prestige edge as the edge facing the highest-quality road entry (paula-round2.md:428-433, paula-round3.md:320-322) — so the octant list should be ordered or annotated by quality once the graph exists. Player-experience intent: the approach should present the city''s FoundingOrientation face (ozzie-round1.md:96-100).
|
||
|
||
Acceptance: a dispatched settlement with >=1 neighbor produces >=1 AccessKind::QuarterEdge node on the correct octant; the BlockJunction fallback fires only for genuinely isolated settlements. Parent: T-750. Blocked-by (soft): inter-settlement-transport ticket for full fidelity. Refs: D-234, D-213, D-204; T-990 (consumer, done), T-1022 (dispatch, done).', 'backlog', 'medium', NULL, 'server', 'D-234', '2026-06-12 10:23:50', '2026-06-12 10:23:50', NULL, '6fd8ab9c614fad67a56d43d9a7d1f9bf', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ0381QWDAQABZAY7MRD8M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Cache TerrainAnalysis on Layer1Output — drop the redundant per-body drainage re-run', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.', 'backlog', 'medium', NULL, 'server', 'D-203', '2026-06-12 10:23:50', '2026-06-12 10:23:50', NULL, 'faf98efa168dfd6a6d1b5e49ff6e63e2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ0381QWDAQABZAY7MRD8M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Cache TerrainAnalysis on Layer1Output — drop the redundant per-body drainage re-run', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
Drop the redundant per-body drainage + terrain re-run in the RegionProfile cascade layer by caching TerrainAnalysis on Layer1Output. cascade.rs:213-241: run_layer1 already computes drainage and (transitively) the terrain masks, but Layer1Output (layer1.rs:28-41) stores only river_network/basins/attractors — so the RegionProfile arm re-runs drainage::analyze (:228-233) AND TerrainAnalysis::analyze (:234) on every AnalyzeBody. The in-code PERF/TODO (:219-221) cites T-1028, which is closed; T-1032 then wired the real body_params read, making this a live production cost on every analyzed body (:221-224). Drainage alone is ~50ms of the ~82ms Layer-1 subtotal (planet-down-cascade/round-1-notes.md:300-306), so the re-run roughly doubles the dominant per-body cost.
|
||
|
||
Scope (the TODO already prescribes it):
|
||
1. Carry TerrainAnalysis (features.rs:66+) on Layer1Output or a parallel field on the cascade snapshot, populated once in run_layer1.
|
||
2. Reuse it at cascade.rs:228-234 for region_profile::derive_all_regions.
|
||
3. Memory check: TerrainAnalysis holds several full-working-grid Vecs and Layer1Output rides the BodyWorldState LRU (D-203) — either store the slim subset region derivation actually reads, or drop the analysis from the cached state after the region layer runs.
|
||
4. Validate combined cost against the D-239 §10 ~45 ms/body budget in the T-1031 verification harness (the TODO''s own acceptance criterion).
|
||
|
||
Pure refactor: derivation inputs unchanged, so T-952 golden-seed outputs must be byte-identical — assert it. Also update the stale TODO text (it references a closed ticket). Parent: T-750. Refs: D-239 §10, D-203; T-1028/T-1031/T-1032 (context), T-952 (determinism gate).', 'backlog', 'medium', NULL, 'server', 'D-203', '2026-06-12 10:23:50', '2026-06-12 10:23:50', NULL, '63b7bd8220b902524fb879256990dfb1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXNWWGS3S0RFMFYQC9BWR', 'bug', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Bridge: fix TCP partial-read frame desync; drain all ready inbound frames per tick', '(description follows in first append)', 'backlog', 'high', NULL, 'server', 'D-225', '2026-06-12 10:40:58', '2026-06-12 10:40:58', NULL, '1a5d68b512ba445e1e4d8afc34106920', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXNWWGS3S0RFMFYQC9BWR', 'bug', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Bridge: fix TCP partial-read frame desync; drain all ready inbound frames per tick', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-01, S-02; citations adversarially verified).
|
||
DESYNC (S-01, high): the stream is non-blocking (tcp.rs:48-52); read_framed uses read_exact for the 4-byte prefix and payload with no partial-frame state (framing.rs:36-61); read_exact hitting WouldBlock mid-frame irrecoverably consumes bytes, and receive() maps WouldBlock to Ok(None) (tcp.rs:211) — a frame split across TCP segments permanently desyncs the stream (next read treats mid-frame bytes as a length prefix). Works today only because localhost frames arrive in single segments; BufReader is bypassed via get_mut(). Fix: persistent partial-frame accumulation buffer on TcpBridge (or blocking reader thread feeding a channel). Regression test: deliver one frame in two writes with flush+delay.
|
||
DRAIN (S-02, med): receive_bridge_inputs calls receive() exactly once per 50 ms tick (bridge/mod.rs:162, no loop; tick at main.rs:306) — an input batch + AtlasLayerRequest in one window backlogs and drains one frame per tick. Fix: loop receive() until Ok(None) with a per-tick cap. The D-225 atlas channel shares this path, so both fixes gate Atlas streaming reliability.
|
||
Extension constraint when touching this code: D-225 amendment 2026-06-12 (tagged envelope for the next inbound type).', 'backlog', 'high', NULL, 'server', 'D-225', '2026-06-12 10:40:58', '2026-06-12 10:40:58', NULL, '6ff607cfd4110152e375d51223685837', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXP19FFZEVED140S1708W', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Wire the Region→Chunk→Voxel tier into production — ChunkPos→RegionPos mapping, proxy layers, Atlas surfacing', '(description follows in first append)', 'backlog', 'high', NULL, 'server', 'D-239', '2026-06-12 10:40:58', '2026-06-12 10:40:58', NULL, 'ba71152b74fde9fbe4233090ca6c2526', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXP19FFZEVED140S1708W', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Wire the Region→Chunk→Voxel tier into production — ChunkPos→RegionPos mapping, proxy layers, Atlas surfacing', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-27 — the audit''s headline finding; citations adversarially verified).
|
||
The D-239 three-carrier chain is implemented and T-1031-harness-verified but has ZERO production call sites: BodyWorldState.regions is written (cascade.rs:100-111) and read only by tests; no function maps a ChunkPos to its covering RegionPos (ChunkPos exists only in chunk_context.rs:67); AtlasLayerResponse carries only Layer1Output (layer_proxy.rs:56-60), so the D-225 proxy cannot serve regions/chunks/voxels and the T-960 Atlas viewer cannot show the tiers that exist.
|
||
Scope: (1) ChunkPos→RegionPos mapping — REQUIRES Q-110 (scale anchoring) answered first; (2) region + voxel layers in the D-225 proxy protocol; (3) surface them in the T-960 viewer (additive overlays per D-226). Treat as the spine of remaining Phase-4 work, alongside T-959 (tile fill).
|
||
Related: Q-110 (blocker for (1)), T-959/T-987 (tile fill), T-960 (viewer), T-1042 (seam blend), T-1040/T-1041 (voxel bugs).
|
||
Audit layer map (verified produce/consume graph, 2026-06-12):
|
||
# Layer chain — actual produce/consume graph
|
||
|
||
| Stage | Module | Consumes | Produces | Production-wired? |
|
||
|---|---|---|---|---|
|
||
| L0 Heightmap | heightmap.rs (D-202) | wiki `heightmap.png` 16-bit gray + `sea_level` tEXt | `BodyHeightmap` (f32 [0,1]); downsampled to GRID 512×256 (gen_queue.rs:374-379) | yes |
|
||
| L1 Topography | layer1.rs → drainage.rs (D-208), features.rs (D-209), subbiome.rs (D-210) | heightmap | RiverNetwork, DrainageBasins (4–12), flow accumulation, TerrainAnalysis, ≤256 attractors w/ sub-biome+cost+water_bearing | yes |
|
||
| L3 Settlement | attractor_matching.rs (D-211/212/213/214/215) | attractors + CityRecords (systems.db `atlas_city_names`) + dominant_faction | CityPlacement {position, archetype, arrangement, founding_orientation} | yes |
|
||
| L4 RegionProfile | region_profile.rs (D-239 §1-§8, D-240, T-1023-1027) | seed + BodyParams (planet_class/atmosphere/hydrosphere/tectonic) + TerrainAnalysis | per-region (8×8 grid cells): slope_q/elev_q/ocean_fraction_q, temperature/moisture, precipitation/glaciation/vegetation, river_threshold, 17-zone MorphologyZone → `BodyWorldState.regions` | populated, **never read** |
|
||
| L4 QuarterSkeleton | skeleton_gen.rs + district_mix.rs + block_irregularity.rs + tile_condition.rs (D-194/196/197/199/216/217/220/229/233/234) | CityGenerationContext (D-199 read-set + stubs) | QuarterSkeleton: 4×4 blocks (512×512 tiles), zoning, reservations (park/transit-terminal base_z=-1), access points, ±45° corridors (Ribbon/HubSpoke/Mesh), BSP building footprints + BuildingPropertyTags → `BodyWorldState.quarters` | yes (L3→L4 dispatch, plugin.rs:100-131) |
|
||
| ChunkContext 64 m | chunk_context.rs (T-1028) | one RegionProfile + seed | basin_direction (seed-random), meander phase/wavelength, has_active_channel, channel_width | **no callers outside tests** |
|
||
| VoxelColumn 1 m | voxel.rs (T-1028/1029/1030) | RegionProfile + ChunkContext + domain_warp (±8 m f64→i32 cast) | D-228 axes: TerrainMaterial/FloorMaterial(None-only)/Vegetation/Water/elevation_m/SeasonalCover; 8 family generators; VoxelCache LRU 8192 | **no callers outside tests** |
|
||
| Chunk→Tile fill | gen_queue.rs:444-450 | — | `FillChunk` returns immediate no-op success | stub (T-959/T-987 backlog) |
|
||
| Client bridge | layer_proxy.rs (D-225) | cache | serves **Layer1Output only**; regions/quarters/voxels not served | yes |
|
||
|
||
# Economics → spatial placement bridge
|
||
|
||
| Economic input | Source | Spatial consumer | Status |
|
||
|---|---|---|---|
|
||
| economic_role, population, settlement_class | systems.db `atlas_city_names` (static) | attractor matching score matrix; district_mix 10×9 table; reservations; zone tags | wired |
|
||
| dominant_faction | `system_factions` | TerritorialStatus → archetype/arrangement on placement | derived, then **dropped at L3→L4 dispatch** |
|
||
| prosperity_baseline_bps | derived D-197 (role+pop+noise; terrain term = 0) | tile_condition bands, entry class, era | wired (partial) |
|
||
| world_tier ← system_economy.economic_tier | systems.db | ComplexityTier | stub `Waypoint` (T-1007 backlog) |
|
||
| dominant_bulk_class / production_ubiquity | — | roofed coverage / footprints | stub (T-982 in_progress) |
|
||
| Live econ sim (D-181 7 signals, EconStateResource) | econ_sim per (system, commodity) | **none** — IPC snapshot + debug only | no path to generation |
|
||
| Supply chains / transport → roads, rail | — | — | does not exist |
|
||
|
||
Counts: 24 atlas modules; 8/8 voxel family generators implemented; 16/17 morphology zones reachable at region scale (BraidedPlain deferred); cache: 50 bodies (D-203), 8192 voxel columns.', 'backlog', 'high', NULL, 'server', 'D-239', '2026-06-12 10:40:58', '2026-06-12 10:40:58', NULL, 'b5d7eeaea1c4bf4467ce39a2b93e4432', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXP5N42SSGW300FEDTS3M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Derive ChunkContext basin_direction from the L1 D8 thalweg; fix the false doc comment', '(description follows in first append)', 'backlog', 'medium', NULL, 'server', 'D-239', '2026-06-12 10:40:58', '2026-06-12 10:40:58', NULL, '9661de339845395e05ba0fb7fd15378a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXP5N42SSGW300FEDTS3M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Derive ChunkContext basin_direction from the L1 D8 thalweg; fix the false doc comment', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-36; citations adversarially verified).
|
||
derive_basin_direction (chunk_context.rs:211-231) branches only on ocean_fraction_q then picks a direction from seed bits in both branches; the doc comment (:201-210) falsely claims an elev_q-gradient proxy; the module contract (:12-13, :40-42) claims D8-thalweg derivation. BodyWorldState.river_network exists (body_world_state.rs:79) and is never consulted — chunk-scale water has no guarantee of flowing downhill or connecting across the 16-chunk region-seed boundary. D-239 §8 binding law: respect the D8 thalweg.
|
||
Fix: compute the covering region''s dominant D8 direction during the RegionProfile pass (DrainageResult is in scope there) and thread it into RegionProfile for derive_chunk_context to read; fix the misleading comments either way. Composes with T-1040 (channel anchor) and T-1042 (seam blend).', 'backlog', 'medium', NULL, 'server', 'D-239', '2026-06-12 10:40:58', '2026-06-12 10:40:58', NULL, 'bc9a55b06e41b82b728e748a18c814c3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPA5JGWACAGGZ3XJ24K0', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Amend D-203 to the actual cache contract — per-entry size ~5× the budget, pinning never invoked', '(description follows in first append)', 'backlog', 'low', NULL, 'server', 'D-203', '2026-06-12 10:40:58', '2026-06-12 10:40:58', NULL, '8089846a1d94dcbadb71337f03e449b1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPA5JGWACAGGZ3XJ24K0', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Amend D-203 to the actual cache contract — per-entry size ~5× the budget, pinning never invoked', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-38; low severity — citations agent-reported, spot-check at pickup).
|
||
D-203 budgets ~100KB/entry, ~5MB total, and a player-location pinning policy. Reality: BodyWorldState stores the full 512×256 f32 working raster (~524KB, gen_queue.rs:374-379 via cascade.rs:103) plus regions + quarters per body — ~26MB+ at CACHE_CAPACITY=50 (body_world_state.rs:26); .pin()/.unpin() exist but the only caller is their own unit test (body_world_state.rs:258). Capacity and LRU semantics match the decision.
|
||
Action: amend D-203 with current per-entry sizes (the bigger raster is a deliberate D-202 consequence) or store a decimated display raster; wire pinning to the player-location system when Phase-5 tracking exists (note it on T-749 scope then).', 'backlog', 'low', NULL, 'server', 'D-203', '2026-06-12 10:40:58', '2026-06-12 10:40:58', NULL, '050def8ff073db4453d3f708603b93c8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPE8FR7TGEM7X6QVPV4M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Refine T-961 into per-asset-class stories, each gated on a written brief', '(description follows in first append)', 'backlog', 'high', NULL, 'visual', NULL, '2026-06-12 10:40:58', '2026-06-12 10:40:58', NULL, '3cafbe48a73971b296864c88e3f21187', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPE8FR7TGEM7X6QVPV4M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Refine T-961 into per-asset-class stories, each gated on a written brief', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-43; citations adversarially verified).
|
||
T-961 (two-sentence description, no acceptance criteria, no brief links) is the only asset-production ticket under T-750, while the epic names eight classes; cars, barns, TVs, billboards appear in NO ticket at all (verified against the full corpus). Refine into child stories per class — station walls, rural walls, doors, floors, furniture/props, street furniture (lamp posts), signage/screens (billboards/TVs), rural structures (barns) — each gated on a one-page brief; explicitly record which classes are deferred (cars: see Q-067 audit note). Decide Q-119 (generic-parent placeholder set as first milestone) before sequencing.
|
||
Audit per-class status matrix (verified 2026-06-12):
|
||
# docs/assets/ survey (13 files + downloads/)
|
||
|
||
| File | One-line summary |
|
||
|---|---|
|
||
| README.md | Master index: audio/visual/video pipelines, status vocabulary (planned/in-progress/placeholder/final), structure that promises visual/{sprites,furniture,tilesets,icons,effects}.md |
|
||
| _templates/audio.md | Row + detailed-entry template for audio assets |
|
||
| _templates/sprite.md | Row + detailed-entry template for sprites (ID prefixes SPR/FUR/TILE/ICO/FX, status, method, directions columns) |
|
||
| _templates/video.md | Row + detailed-entry template for video |
|
||
| audio/README.md | ACTIVE production-status catalog — per-category counts table (12 assets tracked), generation tools, bus architecture |
|
||
| audio/palette.md | Sonic style bible |
|
||
| audio/ambient.md / sfx.md / ui.md | Per-category audio asset tables |
|
||
| visual/README.md | STUB — links 5 category files that do not exist, all counts 0 |
|
||
| visual/palette.md | STUB — 4 bullet decisions (D-019/D-033/D-045, "functional warmth"), defers to art-direction workshop |
|
||
| video/README.md / palette.md | Stubs |
|
||
| downloads/ | Purchased character sources (Quaternius Universal Base Characters, Modular Character Outfits FBX) — characters only |
|
||
|
||
# Per-asset-class matrix
|
||
|
||
| Class | Written brief | Style guide | Naming/res conventions | Gen path | Produced assets | Tickets |
|
||
|---|---|---|---|---|---|---|
|
||
| Walls (station) | art-direction workshop-outcomes.md §3.3 (v0.1.1 set, pre-cascade) + docs/design/placeholder-art-spec-v01.md §2.1 | visual-grammar-v01.md §1/§4.3, workshop-outcomes §1.8 era palette (partly superseded by D-235), D-235 WallMaterial vocab | renderer/README.md:80-95 (`<model>_<dir>_<res>.png`, 1024→256→64 chain) | working — renderer/models/wall_structural.tscn rendered | wall_structural ×4 dirs in client/assets/sprites/; wall_bar_green model unrendered; 2 textures | T-961 (backlog), T-988 (token vocab, backlog) |
|
||
| Walls (rural) | none found | D-235 tokens only (timber/rammed-earth etc.) | renderer/README.md (generic) | same path, unused | none | T-961 text mention only |
|
||
| Doors | placeholder-art-spec-v01.md §2.1 (procedural rects, v0.1) + workshop-outcomes §3.3 `door_sliding` | none for generated world | none for open/closed state frames | same path, unused | none | T-979/T-998 (DoorSpec — logical only), T-961 |
|
||
| Floors | placeholder-art-spec-v01.md §2.1 + workshop-outcomes §3.3 (4 floor sprites) | D-228 FloorMaterial axis (open vocab) | 64px visual tile (placeholder-art-spec §1) | same path, unused | none — client/assets/tilesets/ is .gitkeep only | T-959 (tile fill, logical), T-961 |
|
||
| Styled buildings | D-232 + D-235 + wiki/economics/architecture_trait_catalog.toml (T-1005 done, ~35 visual bundles) | D-235 material/color-register grammar — tokens only, no rendered art direction | token→fallback-parent chain (catalog header :34-44) | no model/texture path defined for building exteriors | none | T-977, T-988, T-994, T-1004 (all backlog), T-1005 (done) |
|
||
| Furniture | docs/assets/visual/furniture.md MISSING (linked); workshop-outcomes §3.3 lists 8-10 objects (pre-cascade) | era table §1.8 only | character-asset-organization.md explicitly excludes furniture ("follow Trellis spike conventions") | proven in spike | spikes/3dpipeline/models/furniture/ ×3 GLB (unpromoted); zero in client/assets | T-961, T-995 (ObjectTag vocab, backlog) |
|
||
| Items | docs/design/icon-set-v01.md (HUD/inventory icons only) | D-086 icon constraints | SVG icon_ prefix (client/assets/icons/) | n/a for icons | 13 SVGs in client/assets/icons/ | none for in-world item sprites |
|
||
| Cars/vehicles | none found | none | none | spike only | spikes/3dpipeline/models/props/vw_beetle.glb (spike) | none — Q-067 open ("driveable vs NPC traffic?") |
|
||
| Lamp posts | none found (zero repo hits) | none | none | unused | none | T-961 text mention only |
|
||
| Barns | none found (only T-750 epic text) | none | none | unused | none | none |
|
||
| TVs | none found (only T-750 epic text) | none | none | unused | none | none |
|
||
| Billboards | none found (only T-750 epic text; other hits = LOD impostors) | none | none | unused | none | none |
|
||
| Characters (reference class — the working model) | docs/architecture/character-asset-organization.md + docs/design/character-visuals-spec.md | yes | full (manifest.json, seg_ naming, body-type keys) | proven end-to-end | 1002 files in client/assets/characters/ | done |
|
||
|
||
# Generation path (verified files)
|
||
image-gen (.claude/skills/image-gen/SKILL.md + scripts/image_connector.py, Gemini) → glb-gen (SKILL.md + tooling/db/trellis_connector.py + tooling/trellis-batch.sh + Blender postprocess scripts) → sprite-gen (SKILL.md + scripts/render.sh) → renderer/ (project.godot, render_scene.tscn, render_export.gd; D-019 camera, 3-light rig, 1024/256/64 chain) → client/assets/sprites/. renderer/output/ holds only .gdignore (intermediates gitignored).
|
||
|
||
# Produced assets in client/assets (non-.import files)
|
||
audio 16 · characters 1002 · fonts 3 · icons 13 · planets 7 · sprites 9 (npc_generic ×4, wall_structural ×4, .gitkeep) · theme 1 · tilesets 1 (.gitkeep only)', 'backlog', 'high', NULL, 'visual', NULL, '2026-06-12 10:40:58', '2026-06-12 10:40:59', NULL, '759d17b938cfb9c12e8e2f9d1fae408c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPJ910NNR5T2R9F9NWQR', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Create the visual production-status catalog; fix glb-gen production path + naming conventions', '(description follows in first append)', 'backlog', 'high', NULL, 'visual', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, 'b0278edb8f6556348eb274f7d5176b17', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPJ910NNR5T2R9F9NWQR', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Create the visual production-status catalog; fix glb-gen production path + naming conventions', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-44 + S-50 task half; citations adversarially verified).
|
||
CATALOG: T-750''s deliverable includes an "asset creation catalog with production status". docs/assets/visual/README.md:14-20 links sprites.md/furniture.md/tilesets.md/icons.md/effects.md — none exist. The row template is ready (docs/assets/_templates/sprite.md:10-24, SPR/FUR/TILE/ICO/FX prefixes + status column) and the audio side shows the working model (docs/assets/audio/README.md:14-19). Instantiate the five files, seed with existing assets (wall_structural, npc_generic, 13 icons) + the T-750 class list as planned rows, and make updating them part of /sprite-gen.
|
||
GLB-GEN PATH: .claude/skills/glb-gen/SKILL.md:115 names client/assets/models/ as the production destination — the directory does not exist; proven spike GLBs sit unpromoted (and are now local-only per D-241, so promotion is also preservation). Define the production model directory + promotion convention (mirror the characters/ manifest pattern), update the SKILL.
|
||
CONVENTIONS: extend naming beyond entity/wall sprites — Godot TileSet resource organization (client/assets/tilesets/ is .gitkeep-only), door state-frame suffixes, multi-tile footprint metadata, renderer/textures/ naming keyed to D-235 tokens.', 'backlog', 'high', NULL, 'visual', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '9eea295dcbd97bccdb8034fb68993b78', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPPHC9FZ4T0GNKR615PR', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Author one-page briefs (or record formal deferral) for lamp posts, barns, TVs, billboards', '(description follows in first append)', 'backlog', 'medium', NULL, 'visual', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, 'a08ec3974c6918b655d0162592766ce4', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPPHC9FZ4T0GNKR615PR', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Author one-page briefs (or record formal deferral) for lamp posts, barns, TVs, billboards', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-46; citations adversarially verified).
|
||
Four asset classes named in T-750''s epic text have no brief, no style guidance, no convention, no ticket beyond the epic sentence, and zero produced assets — repo-wide grep for lamp posts returns zero hits in any .md/.toml/.rs/.gd. Either author one-page briefs per class (audio _templates pattern: function, era/zone placement, footprint, palette, D-235 token parent) or record deferral so the epic stops implying scope. Cars are NOT in this ticket — gated on Q-067 (see its 2026-06-12 audit note).', 'backlog', 'medium', NULL, 'visual', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '15ed194dfe50c13df32029fce912c9fb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPV39JX54HYP83RZJFDM', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Write the Phase-4 visual style bible into docs/assets/visual/palette.md', '(description follows in first append)', 'backlog', 'medium', NULL, 'visual', 'D-235', '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, 'bb2e8e7ee2652e0c73bd1e8540a87800', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPV39JX54HYP83RZJFDM', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Write the Phase-4 visual style bible into docs/assets/visual/palette.md', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-48; citations adversarially verified).
|
||
Current style guidance is: a stub (palette.md:10,23 "to be populated"), a pre-cascade workshop whose per-class guidance targets the dropped hand-made bar scene and whose era-palette model D-235 explicitly reframed (era = maintenance/wear, not a material gate — architecture.md:1705), and a third divergent style block inside the image-gen skill (SKILL.md:60-79: toon-shaded, near-white base, Invisible Inc reference). No document reconciles these for the D-235 token vocabulary the generator will request.
|
||
Write: per-token-family art direction (WallMaterial/RoofForm/FacadeRhythm/StreetSurface registers), surviving constants (D-019 camera, D-043 outline/resolution chain, D-033 tinting, "functional warmth"), explicit supersession note for the workshop §1.8 era table. Owner: Araminta (D-235 co-maintainer).', 'backlog', 'medium', NULL, 'visual', 'D-235', '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '001c313c9c1544506ced14ec030da162', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPZ0ZTM1QQXD5K972CMM', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Rewrite docs/briefings/araminta.md around the Phase-4 asset pipeline', '(description follows in first append)', 'backlog', 'medium', NULL, 'visual', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, 'b61a448bedd06f4a8f9a57bc4d86a784', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPZ0ZTM1QQXD5K972CMM', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Rewrite docs/briefings/araminta.md around the Phase-4 asset pipeline', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-49; citations adversarially verified).
|
||
The visual-art-director briefing is dated 2026-03-13 (:7): it references the retired tooling/db/ticket CLI (:14-15), frames work around the dropped v0.2 pivot (:17), cites a nonexistent /asset-gen skill (:78), and predates D-228/D-232/D-235, the trait catalog, and the whole T-750 asset scope — while D-235 names Araminta co-maintainer of the material vocabulary (architecture.md:1711) and T-995 assigns her the ObjectTag co-maintenance. Rewrite around: D-232/D-235 vocabulary co-maintenance, the production-status catalog ownership, the image-gen → glb-gen → sprite-gen toolchain (+ D-241 storage boundary), and the no-in-world-rendering-until-Phase-5 rule.', 'backlog', 'medium', NULL, 'visual', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, 'a171ca1e2722d72bcd1a92d227eca7b2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXQ3EC348VN37Q2X8JXM0', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Fill GJ-280B (Sova) through the standard wiki pipeline; resolve the canon triplication', '(description follows in first append)', 'backlog', 'high', NULL, 'content', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '361d0883192ad48fa3fa2258616cfe92', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXQ3EC348VN37Q2X8JXM0', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Fill GJ-280B (Sova) through the standard wiki pipeline; resolve the canon triplication', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-51 + S-58 rider; citations adversarially verified).
|
||
The player starting system is the only stub among 302: GJ-280B/index.md:4 stub banner, all-em-dash profile (:11-17), no bodies/ directory, no markers.json, no globe renders, no Supply Dependency/Silence Topic/Calibration Note — while 301/301 other systems are fully dressed. Phase-1 epic T-746 closed done over this gap. Sova canon is meanwhile triplicated: the wiki stub, wiki/corporations/sova-station-works.md:17-23, and docs/design/sova-station-profile.md ("canonical", 2026-02-25).
|
||
Scope: author through the standard pipeline (scaffold_bodies.py + atlas generation + prose pass), folding in docs/design/sova-station-profile.md and sova-texture-appendix.md; wiki becomes canonical; both design docs then get superseded-with-pointer markers (they were deliberately kept active in the 2026-06-12 docs sweep pending this fill). Phase-4 relevance: Sova is the Phase-5 start location — its generation inputs (heightmap, bodies, markers) must exist for the cascade.', 'backlog', 'high', NULL, 'content', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '2d549675e4487a1d478b0dd50e0f588a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXQ7P014H0PM4QWZFTWN4', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Clothing asset pipeline: base meshes × shape keys × AI retexture × region tints, Surface-Deform batch fit', '(description follows in first append)', 'backlog', 'medium', NULL, 'visual', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '143e21a295a4c4bd8619024dc1dff5c1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXQ7P014H0PM4QWZFTWN4', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Clothing asset pipeline: base meshes × shape keys × AI retexture × region tints, Surface-Deform batch fit', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-C4; gated on Q-120 — garment-token vocabulary).
|
||
The validated production recipe (Tyre research, spikes/quaternius-aesthetic/reviews/ai-clothing-pipeline-research.md:509-527, 614-628): ~30 base meshes × 4-16 shape-key variants × AI texture variation × region-mask tints ≈ 20,000 unique visuals. Trellis CANNOT make garments (sculptures, not fitted clothing; auto-rigging failed at 4-22% vertex match — VERDICT.md:115). D-162 fixes the fit model: author on reference body, offline Surface Deform per body type.
|
||
Stories on refinement: (1) base-mesh acquisition (Quaternius packs + hand-authored fill to ~30); (2) shape-key variant authoring; (3) texture-variation loop through the self-hosted stack — NOTE: the research assumed Meshy retexture credits; validating a LOCAL retexture path is an explicit sub-task, not assumed; (4) region-mask + tint conventions per Q-120 tokens; (5) Surface-Deform batch fit to the 11 body types + manifest registration (client/assets/characters/clothing/ pattern exists with the 4-item peasant set). Each garment lands as production-status catalog rows.
|
||
Related: Q-114/Q-115 (server contract), Q-121 (who wears what), the corp uniform spec ticket.', 'backlog', 'medium', NULL, 'visual', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '8da4fc9b51b06614c2c2c48ec1454893', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXQBTNGTDMYE6EHVA48PG', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Author corp uniform/dress specs: Workshift Apparel, Shetland Wool, Kalahari Leatherworks, thrds', '(description follows in first append)', 'backlog', 'low', NULL, 'content', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '1011f33d615f3b8d0c0c04649a893e36', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXQBTNGTDMYE6EHVA48PG', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Author corp uniform/dress specs: Workshift Apparel, Shetland Wool, Kalahari Leatherworks, thrds', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-C5; corp files verified to contain zero dress specification).
|
||
Four apparel corps have rich supply-chain lore and no uniform/dress specs: wiki/corporations/workshift-apparel.md (HeavyWork/FieldWork/StationWork lines; institutional contracts ≈70% revenue — the contract lore IS the uniform-assignment rule, write it as data), shetland-wool.md, kalahari-leatherworks.md, thrds.md. Add a spec section per corp page (or wardrobe-catalog stanzas per Q-120): silhouettes, palette/marks, which roles wear which line. Gameplay hook preserved: worn HeavyWork gear = exposure history (the respiratory-sensitizer scandal becomes wearable evidence — see Q-115).
|
||
Sequence after Q-120/Q-121 decide the vocabulary + canon home.', 'backlog', 'low', NULL, 'content', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, 'dfe0f8f3bda3d6f510fd60da42c65a44', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXQGAX5GT4PTTBQYGJCV4', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Triage the Phase-4 question set before T-959 starts: Q-102, Q-103, Q-105, Q-109', '(description follows in first append)', 'backlog', 'medium', NULL, 'server', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '965ad24ea067cd931bd88a8f635f0c22', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXQGAX5GT4PTTBQYGJCV4', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Triage the Phase-4 question set before T-959 starts: Q-102, Q-103, Q-105, Q-109', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-64 remainder; verified: all four open with zero linked tickets).
|
||
The remaining Phase-4 spine is T-959 (Layer 5 tile fill) → T-962 (validation + Phase-5 gate). Four open architecture questions sit directly under that work with no owners: Q-103 (tile-mutator op schema — needed before T-959 Layer 5), Q-102 (cohesion-matrix seam-free variation — needed for tile fill; relates to T-1042), Q-105 (region seasonal/clock state), Q-109 (generation-source dispatch: planet/station/mod/save). Answer or ticket each before T-959 kicks off; Q-103 and Q-102 are the most load-bearing. Also now open from the audit: Q-110 (scale anchoring — blocks the spine ticket) and Q-111 (live-econ coupling — gates T-1007/T-982 sequencing).', 'backlog', 'medium', NULL, 'server', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '60d7cdbc61138b6f06fdb7a897fd54bb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXQN3J95WE3GZJJEF3HG0', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Disposition D-179/D-183 (economics process decisions); backfill question dates going forward', '(description follows in first append)', 'backlog', 'low', NULL, NULL, 'D-179', '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, 'a0ca74f2bd30f8389075b142c65c0f84', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXQN3J95WE3GZJJEF3HG0', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Disposition D-179/D-183 (economics process decisions); backfill question dates going forward', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-68 remainder; low severity).
|
||
D-179 (Stability Acceptance Criteria) and D-183 (Iterative Economics Development Cycle) mandate ongoing verification of the econ sim but have zero linked tickets and Phase 2 is closed; whether stability criteria get re-checked when Phase-4 generation starts reading economic state (D-199 read-set, Q-111) is untracked. Decide: re-validate under Phase-4 load (ticket it under T-962) or amend both records as satisfied-at-Phase-2-close.
|
||
Also: question records mostly lack raised dates (pql decisions list --type question emits empty dates), making staleness unmeasurable — add "raised" dates to new Q records going forward (the 2026-06-12 batch Q-110..Q-122 already does this) and consider a validate rule.', 'backlog', 'low', NULL, NULL, 'D-179', '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '366029950e126d2798b8d93a6059678c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXQS7HFJJHDW5FBM609EG', 'task', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Extract character_creation.gd (2,442 lines) into camera rig / manifest loader / appearance state', '(description follows in first append)', 'backlog', 'low', NULL, 'client', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '2238ebe85b8d85048a09039110ac0991', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXQS7HFJJHDW5FBM609EG', 'task', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Extract character_creation.gd (2,442 lines) into camera rig / manifest loader / appearance state', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-23; Phase-5 surface — do NOT refactor before Phase 5 reopens it, per D-166).
|
||
client/ui/meta/screens/character_creation/character_creation.gd is 2,442 lines / 105 funcs — ~3× the next-largest production script — mixing camera control (_cam_zoom_toward_cursor, _update_camera_angle), manifest loading, and UI state in one MetaScreen. It is a meta screen (D-169 component rule does not apply) and part of the frozen character/rendering surface. Extract when Phase 5 starts.', 'backlog', 'low', NULL, 'client', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '15abdd277a9134da743e2a3c80b9a178', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXQXH3Z2VEDSV1636XW58', 'task', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Add the CharacterVisualDescriptor wire struct to bridge/types.rs + MessagePack round-trip test', '(description follows in first append)', 'backlog', 'medium', NULL, 'server', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '19a7439ceaa617785eb3f33b5201919d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXQXH3Z2VEDSV1636XW58', 'task', '06FB0TNSRXX29H5X0EB0F0GBW4', 'Add the CharacterVisualDescriptor wire struct to bridge/types.rs + MessagePack round-trip test', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-42; verified including git history).
|
||
client/scripts/rendering/character_visual_descriptor.gd:5 says its fields "must match server/src/bridge/types.rs" — NO such struct exists there and git log -S shows none ever did; VisibleEntity carries only entity_id/position/kind/visibility/relationship/observation/tell_state. The comment is aspirational.
|
||
Scope (after Q-114 decides the generation contract): mirror struct in types.rs; MessagePack round-trip test against the GD from_dict/to_dict; entity-snapshot field gated by perception (you see clothes only when you see the NPC). Quick interim action: soften the .gd comment so it stops claiming a contract that does not exist.', 'backlog', 'medium', NULL, 'server', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '750c8f04d6aafb6a88e16f3ad6df1ab6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXR27XGNCP92JN7BDQ454', 'task', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Wardrobe assignment in NPC generation — deterministic (seed, culture, role, employer, prosperity) → garment tokens', '(description follows in first append)', 'backlog', 'medium', NULL, 'server', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '49c552648add593bb6f2b76ddb5bcbd1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXR27XGNCP92JN7BDQ454', 'task', '06FB0TNSRZGGNZMAP8GDMXSCMW', 'Wardrobe assignment in NPC generation — deterministic (seed, culture, role, employer, prosperity) → garment tokens', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-C6; gated on Q-114/Q-115/Q-120).
|
||
workers/stubs.rs:86 is the declared home ("real implementation pre-generates NPC appearance, inventory, mood"); the 10-axis generation in npc/generate.rs shows the deterministic per-axis pattern to extend. Wardrobe = pure function of (entity seed, culture register, role, employer, prosperity band) → token per slot (Q-120 vocabulary) → manifest item id + tints. Assignment logic per Q-121: role picks garment family (corp institutional contracts = workforce uniforms = information), culture/system picks materials/registers, prosperity band picks condition/wear, faction/corp adds marks. Pairs with the bridge wire-struct ticket (Phase 5) and the Q-114 contract.', 'backlog', 'medium', NULL, 'server', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '6c991a1a32b8890ed41b4a031abcc8c8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXR79W28XNN1TB7HKGBP8', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Split the input.rs and dialogue.rs god-module dispatchers', '(description follows in first append)', 'backlog', 'medium', NULL, 'server', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '235773c7e91589b0cc916fed5aa0f30c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXR79W28XNN1TB7HKGBP8', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Split the input.rs and dialogue.rs god-module dispatchers', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-03; citations adversarially verified).
|
||
simulation/input.rs: 2,739 lines, imports 9 domains (bookmark, bridge::debug, knowledge, settings, economy, interaction, inventory, movement, save_io), 9× type_complexity allows (:485-1120) + 1 too_many_arguments — the dispatch hub for every player verb. simulation/dialogue.rs: 2,785 lines, 3 allows.
|
||
Extract per-domain input handlers into their owning modules behind a thin dispatch table; split dialogue into talk-selection / confrontation / response-assembly. Mechanical, no behavior change; gate with the existing determinism.rs byte-identical goldens.', 'backlog', 'medium', NULL, 'server', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '014d95390a4cafb49f668e06f6f3cd60', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRBRFW4MH5G8C0X12YGR', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Workers pool: add tests, fix panic-loss, correct the false "tested" doc claim', '(description follows in first append)', 'backlog', 'medium', NULL, 'server', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, 'becd1955a353c824f35670c0842471f3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRBRFW4MH5G8C0X12YGR', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Workers pool: add tests, fix panic-loss, correct the false "tested" doc claim', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-05; verified — zero tests exist for BackgroundWorkerPool anywhere).
|
||
workers/stubs.rs:7 claims the pool infrastructure is "real and tested" — false. pool.rs:8-13 documents that a worker-thread panic silently loses in-flight requests (TODO #843); for ModalLock consumers that means the player waits forever. SimulationPlugin spawns 4 live stub threads every session (simulation/mod.rs:85-87) for Phase-5+ functionality.
|
||
Do now: correct the doc claim; unit tests (spawn/push/poll/shutdown + worker-panic). Before any ModalLock consumer ships (Phase 5): heartbeat/re-enqueue or downgrade ModalLock to an error path. Optional: defer thread spawn until a real handler registers.', 'backlog', 'medium', NULL, 'server', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '7a1639eb9162f046e21c3f38aa46652a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRG23G1RAREVHQJ14BWC', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Server hygiene batch: exemption contracts, dead deps, generator_spike quarantine, save/load ordering, economy.rs tests', '(description follows in first append)', 'backlog', 'low', NULL, 'server', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, 'c8306d2cd939c3e989d4d6f31954e88a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRG23G1RAREVHQJ14BWC', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Server hygiene batch: exemption contracts, dead deps, generator_spike quarantine, save/load ordering, economy.rs tests', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-06, S-07, S-08, S-09, S-12; low severity — spot-check citations at pickup).
|
||
1. S-06: add the consumer contract ("every consumer must sort before state/wire use") to the three perception disallowed-types allows (shadowcast.rs:17, query.rs:11, interpretation.rs:9).
|
||
2. S-07: delete unused bytemuck (Cargo.toml:30, zero references); fix the stale rayon comment (says "not yet called"; used in atlas/gen_queue.rs:192-228).
|
||
3. S-08: delete or feature-gate bin/generator_spike.rs (1,153 lines reimplementing npc/generate.rs outside ECS, 3 TODO(integration) duplication admissions); extract the shared surname corpus copied between generate_brands/names.rs and generate_corporations/names.rs (already drifted; both feed the systems.db stamp); prune or justify the 24 allow(dead_code) in generate_corporations.
|
||
4. S-09: pin execute_save_load with a lower-bound constraint (currently only .before(compute_observer_snapshot), simulation/mod.rs:106-114 — the scheduler may legally run it before Input, changing what a save captures); note the exclusive-system exception in tick_phases.rs rules.
|
||
5. S-12: unit tests for simulation/economy.rs signal derivation (382 lines, no cfg(test); fixtures set economy_snapshot: None) — trend windowing, first-tick baseline, zero-demand stockpile edge.', 'backlog', 'low', NULL, 'server', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, 'cac03779bc12bad69a2f2de713c5e536', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRMET5CBB0ENBZGJQKX0', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Add a client-test gate to pre-push — the 63-file GDScript suite never runs automatically', '(description follows in first append)', 'backlog', 'high', NULL, 'client', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '84194a9682318e89ce9643c16afabb95', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRMET5CBB0ENBZGJQKX0', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Add a client-test gate to pre-push — the 63-file GDScript suite never runs automatically', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-13; citations adversarially verified).
|
||
The pre-push hook is the ONLY automatic correctness gate (its own comment, .config/hooks/pre-push:101-110) and there is no CI — but for client/ changes it runs only a headless parse check (:38-54). The gdUnit4 suite (tests/run-godot: 300s-capped, one-line JSON summary, agent-safe) is invoked only manually. A GDScript regression reaches main unverified, while team-patterns.md claims the gate is "deliberately comprehensive".
|
||
Fix: run tests/run-godot in pre-push when CLIENT_CHANGED > 0 — or record manual-only explicitly and fix team-patterns.md. Related decision: Q-116 (gdlint blocking). Prerequisite worth checking: T-973 (pre-existing bare-run failures, under this initiative) so the new gate starts green.', 'backlog', 'high', NULL, 'client', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '5b1d44406a1ed829b8dd23ff02f4113e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRRDGJ5GFPGHZV3WS0D0', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Wire tooling tests into a gate: make test-tooling + pre-push on tooling changes', '(description follows in first append)', 'backlog', 'medium', NULL, NULL, NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '2c8ec25fd9d236f28a4362bd3cfb0701', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRRDGJ5GFPGHZV3WS0D0', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Wire tooling tests into a gate: make test-tooling + pre-push on tooling changes', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-18; citations adversarially verified).
|
||
22,340 lines of tooling Python (including the systems.db generator) are verified only by a 4-rule ruff subset (pyproject.toml:26-31: E9/F401/F811/F821); zero pytest anywhere; the one real test (tooling/planet-gen/test_sim_determinism.py, guarding the expensive 271-body bake, exit codes 0/1/2) is wired into nothing.
|
||
Fix: make test-tooling = test_sim_determinism.py + import_economics --dry-run against the committed DB; call from pre-push when TOOLING_CHANGED > 0; widen the ruff selection.', 'backlog', 'medium', NULL, NULL, NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '32eaced9201f8ed58a608e4a056e5ebe', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRX067NBNG76MV84MDQ0', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Split the 2,617-line import_economics.py monolith; single shared generator-source registry', '(description follows in first append)', 'backlog', 'medium', NULL, NULL, NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, 'd39639902762616c3bf57562f1e233bc', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRX067NBNG76MV84MDQ0', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Split the 2,617-line import_economics.py monolith; single shared generator-source registry', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-19; citations adversarially verified).
|
||
tooling/economy-db/import_economics.py (2,617 lines, 31 top-level defs) owns schema migration, brand regeneration (shells to Rust), 16 import steps, validation, and the meta stamp. Its source-file list is hand-maintained in THREE places guarded only by comments: IMPORT_ECONOMICS_SOURCES (:81-99), GENERATOR_SOURCES (tooling/check-systems-db-stamp:48-63), and the /pr-push watch list (.claude/skills/pr-process/SKILL.md:222-243). Error handling itself is good (single transaction, rollback, distinct exit codes at :2350-2613).
|
||
Fix: extract one shared tooling/generator_sources.py imported by the script + stamp checker and read by /pr-push; then split importers/validators into modules under tooling/economy-db/; finish type hints during the split. Also fold in S-25''s connector dedup: move CONFIG_PATH/load_config/get_base_url into tooling/db/common.py (currently copy-pasted across audio/trellis/image connectors).', 'backlog', 'medium', NULL, NULL, NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '93093fc2f768f079757d4ef22bc8cdf0', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXS18RSVRHC7Y9TAX06HG', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Client hygiene batch: orphan .gd.uid files, time_display removal rider, _format_pop dedupe, skip_test_ triage', '(description follows in first append)', 'backlog', 'low', NULL, 'client', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, 'a5eb748e9057655cdb239f1ab0320cf3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXS18RSVRHC7Y9TAX06HG', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Client hygiene batch: orphan .gd.uid files, time_display removal rider, _format_pop dedupe, skip_test_ triage', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-21, S-22, S-24; low severity — spot-check citations at pickup).
|
||
1. S-21 now: delete 7 tracked orphan .gd.uid files whose scripts are gone (client/scripts/rendering/fog_renderer.gd.uid; client/ui/{bug_report_dialog,character_select,debug_console,loading_screen,main_menu,settings_dialog}.gd.uid). Phase-5 rider: remove time_display.gd/.tscn + its 199-line test (superseded by the merged HUD row per hud.gd:4 / #786) with the Phase-5 rendering pass, not before (D-166).
|
||
2. S-22: deduplicate _format_pop — byte-identical 12-line implementations in planet_screen.gd:105-116 and system_screen.gd:685-696 (plus _format_radius) into a shared atlas helper.
|
||
3. S-24: triage the 9 permanently disabled skip_test_ functions (test_sprint2_proof.gd:117,147,169; test_etalk_overlay_sprint17.gd:267-273; test_client_p2.gd:70,100,198) — re-enable, delete, or attach a T-id; convert the push_warning-then-return soft-skip pattern (test_fog_shader, test_audio_sprint13, test_monologue_display, test_input_roundtrip:54) to gdUnit4 skip reporting so missing prerequisites are visible in the JSON summary, not silently green.', 'backlog', 'low', NULL, 'client', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '11940c97f3dff188beedb2e11f43f657', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXS5YZ04F4CPPYNZS4Z2W', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Docs-drift sweep: one-generator reality, dead check-protocol target, DEVOPS hook sections, project.yaml version, stale code comments', '(description follows in first append)', 'backlog', 'medium', NULL, NULL, NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, 'e8ca3e11543d0f54b3b1df66bc9e6141', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXS5YZ04F4CPPYNZS4Z2W', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Docs-drift sweep: one-generator reality, dead check-protocol target, DEVOPS hook sections, project.yaml version, stale code comments', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-11, S-15, S-16, S-25, S-26, S-39; S-15/S-16 adversarially verified).
|
||
1. S-15: docs/DEVOPS.md:211-230 documents three generators, .claude/rules/asset-pipeline.md:22,27,36 documents two with a literal command for a file that does not exist (tooling/planet-gen/generate_atlas.py, retired #951/D-223); truth is one (import_economics — Makefile:334-352, stamp registry). Fix both + the CLAUDE.md asset-pipeline snippet.
|
||
2. S-16: delete make check-protocol (Makefile:123-130 greps constants deleted under D-192 via T-874/T-875 — empty==empty always passes); drop from build dep (:132) and help (:42).
|
||
3. S-25: rewrite DEVOPS.md hook/config sections from current sources (pre-push table omits cargo test/deny/clerk + advisory gdlint status; .config/ description never materialized; pre-commit row omits pql validate/export).
|
||
4. S-26: project.yaml says version 0.2.0 under the 0.{phase}.{n} scheme with Phase 4 active, and its description still narrates the v0.1 Sova slice — bump to 0.4.n (or document the bump trigger) + refresh description.
|
||
5. S-39: update voxel.rs module doc (:41-48) and MorphologyFamily variant comments (:256-280) still claiming 7 families are unimplemented stubs (T-1029 landed them all); fix cascade.rs:219 TODO citing closed T-1028 (now tracked by T-1044).
|
||
6. S-11: comment sweep — main.rs:126-127 claims a protocol_version handshake that D-192 removed; npc/relationships.rs:92 TODO(v0.2); chunk_streaming.rs:6,21-22 v0.3+ — rephrase version targets as phase numbers.', 'backlog', 'medium', NULL, NULL, NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '39cb0a32123855d2006c94c132aa8612', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXSA4WFXPD21YK7N8SF60', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Fix 2,131 broken heightmap.png body-page links — conditional scaffold link + regenerate', '(description follows in first append)', 'backlog', 'medium', NULL, 'content', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '9cfbd41687054da3d55865b940bb7594', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXSA4WFXPD21YK7N8SF60', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Fix 2,131 broken heightmap.png body-page links — conditional scaffold link + regenerate', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-53; counts independently reproduced by verifier).
|
||
The body-page scaffold links  for all non-gas-giant bodies (scaffold_bodies.py:94-96) but heightmaps exist for only 267 bodies (vs 2,398 reliefmap.png / 3,256 globe.png) — 2,131 of the wiki''s 2,180 broken links are this one pattern, rendered as dead images in the implant wiki view. Fix: make the link conditional in the scaffold and regenerate the Visual section of body pages (or backfill heightmaps where Phase 4 wants them anyway — they are a generation input).', 'backlog', 'medium', NULL, 'content', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, 'f18205da33c6ad487454ce1bac6afb3e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXSEC1F0RKJVH7JVPS8NW', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Wiki sweep: real link breaks, stale nav surfaces, GOVERNANCE/template reconcile, Sol legacy markers, triangles index', '(description follows in first append)', 'backlog', 'medium', NULL, 'content', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, '1aa8a8377eae25a54a831d3e3aca41d8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXSEC1F0RKJVH7JVPS8NW', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Wiki sweep: real link breaks, stale nav surfaces, GOVERNANCE/template reconcile, Sol legacy markers, triangles index', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-54, S-55, S-56, S-59; S-54/S-55/S-56 adversarially verified, S-59 agent-reported).
|
||
1. S-54 (~26 real breaks): knowledge/→concepts/ rename leftovers (3 contraband files, triangles/hub-power.md:420, authoring/monologue-guide.md ×7); pre-governance decisions/ anchors (monologue-guide.md:834-836); 9 phantom companion-system links in star-systems/catalog.md (index.md handles the same companions correctly as unlinked text); factions/cygni-b-combines.md absent (linked from stalownia-kowalski.md:111); concepts/entity-attributes.md:280 wrong relative path to an existing doc.
|
||
2. S-55: wiki/index.md:12 claims "10 fully written" vs ~301 reality; corporations/index.md links 38/155 (117 orphaned); zero nav link to economics/ (39 md + 20 TOML, the primary generator source); 25 station-level gttr-*.md orphaned from their system pages. Regenerate counts from the catalog (or let wiki_sync own them); autogenerate the corp index from frontmatter.
|
||
3. S-56: wiki/GOVERNANCE.md:39-54 prescribes a star-systems/{system}/{station}/{district} hand-authored tree that has zero instances, and _templates/star-system.md:1-18 mandates frontmatter that 0/302 system pages have — rewrite both to the generated model (wiki_sync.py: DB owns structured fields, wiki owns prose) or decide system pages should carry frontmatter and have wiki_sync emit it.
|
||
4. S-59: convert the 4 pre-D-223 geometry-bearing Sol markers.json (GJ-0 bodies, authored coordinates/populations) to names-only, moving the authored data to the Sol special-case home; add wiki/triangles/index.md or de-link it from wiki/index.md:19.
|
||
Audit wiki survey (verified 2026-06-12):
|
||
# wiki/ directory map
|
||
|
||
| Directory | Files | Format | Machine-readable (feeds DB)? | Completeness |
|
||
|---|---|---|---|---|
|
||
| star-systems/ | 3,262 md + 2,398 json + 5,921 png | md (no frontmatter on system pages; YAML frontmatter on body pages), markers.json, png | YES — body frontmatter (axial_tilt → import_economics.py:1286), markers.json city names (:1451), gttr.md → gttr_hook (populate_gttr_hook.py); system infobox/bodies tables generated FROM systems.db (wiki_sync.py) | 302 system dirs; 301 full prose (Supply Dependency 301, Silence Topic 288, Calibration Note 261); 2,625 body pages all with EMPTY Description; 302 gttr.md + 6 corridor + 24 station GTTRs; heightmap.png only 267 vs globe 3,256/reliefmap 2,398; GJ-280B = sole stub |
|
||
| economics/ | 39 md + 20 toml | TOML (source of truth) + md prose | YES — commodities.toml, production_chains.toml, currency_zones.toml, specialization_vocabulary.toml (27), system_specialization.toml (240/301 pins), architecture_trait_catalog.toml (28 templates) + bias, brands/generated_brands/tier1/tier2 | Complete for current decisions (D-173..D-182, D-232, D-237; T-1016 done); not linked from wiki/index.md |
|
||
| corporations/ | 156 md | md + YAML frontmatter | YES — frontmatter slug/title/headquarters/tags/scope → corporations + corp_presence (import_economics.py:734-790, D-182 wiki-is-truth) | 155 canonical pages ~8-16KB; index.md lists only 38 (117 orphaned from nav) |
|
||
| factions/ | 9 md | md + frontmatter | No (prose; dominant_faction comes from economics TOML) | Complete: 6 major + 1 regional + 1 local worked example, all canonical, clean index |
|
||
| technology/ | 7 md | md | No | Complete (6 entries + index) |
|
||
| contraband/ | 4 md | md + frontmatter | No | Complete (3 entries + index); stale ../knowledge/ links |
|
||
| concepts/ | 4 md | md | No | Complete (fact-catalog, entity-attributes, relationship-states); renamed from knowledge/, inbound links broken |
|
||
| authoring/ | 12 md (incl. npc-patterns/ 3) | md | No (authoring guides) | Complete; monologue-guide has 9 stale links (knowledge/, pre-governance decisions/ paths) |
|
||
| triangles/ | 1 md | md + frontmatter | No | One worked example (hub-power.md); index.md missing (broken link from wiki root) |
|
||
| cultural-groups/ | 0 (.gitkeep) | — | — | EMPTY (template exists) |
|
||
| institutions/ | 0 (.gitkeep) | — | — | EMPTY (template exists; covered under factions/) |
|
||
| lore/ | 0 (.gitkeep) | — | — | EMPTY (template exists) |
|
||
| species/ | 0 (.gitkeep) | — | — | EMPTY (template exists) |
|
||
| _templates/ | 17 md | md | — | Complete but drifted: star-system template ≠ generated reality; station/district/location/cultural-group/species/lore/institution templates have 0 instances |
|
||
| glossary.md / GOVERNANCE.md / index.md | 3 md | md | No | Glossary current (incl. TOML/DB terminology + anti-drift list); GOVERNANCE spatial hierarchy + status lifecycle stale; index.md counts stale (''10 fully written'' vs ~301) |
|
||
|
||
# Star-systems census
|
||
- Systems: 302 dirs (catalog claims 301; 220 named / 81 unnamed); 9 catalog rows link nonexistent companion dirs
|
||
- Bodies: 2,625 body pages (planets, moons, belts, oort clouds; no per-type subdirs — flat bodies/ per system)
|
||
- Stations: 0 wiki pages; rows in systems.db rendered into ''Stations & Facilities'' tables per system index + 24 station GTTR prose files
|
||
- Markers: 2,394 names-only (D-223) + 4 legacy geometry (all GJ-0/Sol)
|
||
|
||
# Generation data flow (verified)
|
||
wiki/economics/*.toml + wiki/corporations/*.md frontmatter + wiki/star-systems body frontmatter + markers.json names → tooling/economy-db/import_economics.py → server/data/systems.db (stamped, tooling/check-systems-db-stamp) → client Atlas (gttr_excerpt popups, reach_screen.gd:178) + direct runtime load of wiki globe.png (system_screen.gd:482-492). wiki_sync.py: DB owns structured fields, wiki owns prose sections.
|
||
|
||
# docs/ health snapshot
|
||
- docs/architecture/ (19): current — pql-migration.md (2026-06-06), atlas-naming-pipeline, implant-app-pattern; historical — sprint-36/37 audits, v01-yaml-content-audit, eval/risk-godot-rust-bridge (2026-03-13)
|
||
- docs/design/ (60+): ~35 files frozen at 2026-02-19→03-14, status:active but v0.1/v0.2-era (wow-moments, first-5-minutes, spatial-layout-*-v01, dueling content-structure docs); still-load-bearing: star-map.json (Topology source), gj-catalog-full.json, planetary-terrain-generation.md, cultural-diversity-audit.md (remediated, T-793 done), sova-station-profile.md (canon for the stub system)', 'backlog', 'medium', NULL, 'content', NULL, '2026-06-12 10:40:59', '2026-06-12 10:40:59', NULL, 'e969fdaff30c443687a7bba65e8863f9', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZQKSQQQ1T5Q696AAM', 'task', '06FB0TNSRWN78KNTHMER9HN7QR', 'BulkClass + ProductionUbiquity enums + D-184 bulk_class backfill + dominant-commodity lookup', 'Define BulkClass{BulkSolid|BulkLiquid|PrecisionDense|Perishable|NonPhysical} + ProductionUbiquity{Ubiquitous|Common|Specialist|MonopolySource}; back-fill D-184 bulk_class values; build-time lookup of the settlement dominant commodity from the systems.db catalog. Seed-independent.
|
||
|
||
Round-3 batch refinement (2026-05-26): also define the MorphologyZone enum here (closed set: Fjord, Canyon, Delta, AlluvialPlain, Island, MountainPass, Coastal, Lake, Sea, OpenOcean, MeanderReach, Other) -- it had no home and 954/976/1005 all need it. bulk_class is the 8->5 PROJECTION (size variants bulk/standard/compact/oversized -> BulkSolid; precision -> PrecisionDense; the 8 stay on commodities). Note: the bare enum/struct type DEFS now live in the foundational types task; 982 owns the projection + dominant-commodity DERIVATION logic (derived from highest-output location-bound production chain, D-178, not an authored role->commodity table).', 'backlog', 'medium', NULL, 'server', 'D-233', '2026-05-25 19:11:05', '2026-06-12 10:41:25', NULL, '74c5df94a1c8a5396f68734fc7681cc4', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZQKSQQQ1T5Q696AAM', 'task', '06FB0TNSRWN78KNTHMER9HN7QR', 'BulkClass + ProductionUbiquity enums + D-184 bulk_class backfill + dominant-commodity lookup', 'Define BulkClass{BulkSolid|BulkLiquid|PrecisionDense|Perishable|NonPhysical} + ProductionUbiquity{Ubiquitous|Common|Specialist|MonopolySource}; back-fill D-184 bulk_class values; build-time lookup of the settlement dominant commodity from the systems.db catalog. Seed-independent.
|
||
|
||
Round-3 batch refinement (2026-05-26): also define the MorphologyZone enum here (closed set: Fjord, Canyon, Delta, AlluvialPlain, Island, MountainPass, Coastal, Lake, Sea, OpenOcean, MeanderReach, Other) -- it had no home and 954/976/1005 all need it. bulk_class is the 8->5 PROJECTION (size variants bulk/standard/compact/oversized -> BulkSolid; precision -> PrecisionDense; the 8 stay on commodities). Note: the bare enum/struct type DEFS now live in the foundational types task; 982 owns the projection + dominant-commodity DERIVATION logic (derived from highest-output location-bound production chain, D-178, not an authored role->commodity table).
|
||
|
||
Status check 2026-06-12 (fable-ous audit S-62): flipped in_progress → backlog. Verified the enum/type half landed via T-1006 (BulkClass/ProductionUbiquity + context fields, generator.rs:1016/1039/1097-1100), but this ticket''s remaining scope — the 8→5 bulk_class projection, D-184 backfill, and the dominant-commodity DERIVATION (highest-output location-bound chain per D-178) — has zero hits in city_context_reader.rs. Nobody is actively on it; it was stale-WIP for 18 days while being T-1014''s sole live blocker. Sequencing input: Q-111 (live-econ coupling) decides whether the dominant-commodity lookup stays static build-time.', 'backlog', 'medium', NULL, 'server', 'D-233', '2026-05-25 19:11:05', '2026-06-12 10:41:25', NULL, 'fe1326ed22e42707c3b33575638db3a8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ02QTVSZ1PXTGNCN6Y8KM', 'bug', '06FB0TNSRZXCHGS16BFHSSGSV4', 'BUG: river channel centrelines anchored to the world-origin axis — channels absent in almost every chunk', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
BUG: channel centrelines are anchored to the world-origin axis. compute_channel_state (AlluvialPlain, server/src/atlas/voxel.rs:1648-1707) and compute_meander_channel_state (MeanderReach, :1556-1595) compute perp_distance = (cross - meander_displacement).abs() (:1694, :1583) where cross is the raw world-space voxel coordinate (derive_voxel_column takes tile_x/tile_y in world metres, :328-338; cross = vx or vy at :1653-1661). The channel centreline is therefore the world x=0/y=0 axis plus-or-minus meander amplitude: only chunks within ~(channel_width/2 + amplitude + jitter) metres of the world origin axis ever contain channel water, regardless of ChunkContext.has_active_channel / channel_width_m (chunk_context.rs:103-110). in_levee_band (:1602-1633) inherits the same defect, so levees are origin-locked too. Every has_active_channel chunk elsewhere on the body silently renders dry floodplain.
|
||
|
||
Intended model (workshopped): channel positions derive from region/chunk-scale data, not world axes — D-239 §10 (one basin-direction + global meander-curve params; wavelength > 64 m seeds Region-or-higher) and tile-derivation-contract/gestalt-round1.md:152-162 (channel branch positions from a multi-seed Voronoi partition of the chunk area with D8 flow direction as attractor; meander_intensity controls deviation from the straight downslope path).
|
||
|
||
Fix, two stages:
|
||
1. Minimal correctness: derive a deterministic cross-offset channel anchor at region scale (alongside meander_phase in derive_chunk_context, chunk_context.rs:124-141 — same Region-or-higher seed path) and measure perp_distance from that anchor, so an active channel actually crosses the chunks the region says it crosses, continuously across chunk boundaries.
|
||
2. Full model: gestalt''s multi-seed Voronoi + D8-attractor branch placement when BraidedDelta sub-classification (D-239 implementation note: deferred to ChunkContext) lands.
|
||
|
||
Add a T-1031-harness believability check: a has_active_channel chunk at an arbitrary large world offset (e.g. chunk_pos (1000, -750)) contains in-channel voxels; channel position is continuous across adjacent chunk pairs. Sibling bug: landform-64m-repeat (same family, opposite direction — channels appear nowhere, landforms appear everywhere). Parent: T-750. Refs: D-239 §10, D-208 (D8), D-010; T-1029 (origin), T-1031 (harness).', 'in_progress', 'high', NULL, 'server', 'D-239', '2026-06-12 10:23:49', '2026-06-12 10:56:40', NULL, '6744373fe8042356f58e89d8a889071b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXNWWGS3S0RFMFYQC9BWR', 'bug', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Bridge: fix TCP partial-read frame desync; drain all ready inbound frames per tick', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-01, S-02; citations adversarially verified).
|
||
DESYNC (S-01, high): the stream is non-blocking (tcp.rs:48-52); read_framed uses read_exact for the 4-byte prefix and payload with no partial-frame state (framing.rs:36-61); read_exact hitting WouldBlock mid-frame irrecoverably consumes bytes, and receive() maps WouldBlock to Ok(None) (tcp.rs:211) — a frame split across TCP segments permanently desyncs the stream (next read treats mid-frame bytes as a length prefix). Works today only because localhost frames arrive in single segments; BufReader is bypassed via get_mut(). Fix: persistent partial-frame accumulation buffer on TcpBridge (or blocking reader thread feeding a channel). Regression test: deliver one frame in two writes with flush+delay.
|
||
DRAIN (S-02, med): receive_bridge_inputs calls receive() exactly once per 50 ms tick (bridge/mod.rs:162, no loop; tick at main.rs:306) — an input batch + AtlasLayerRequest in one window backlogs and drains one frame per tick. Fix: loop receive() until Ok(None) with a per-tick cap. The D-225 atlas channel shares this path, so both fixes gate Atlas streaming reliability.
|
||
Extension constraint when touching this code: D-225 amendment 2026-06-12 (tagged envelope for the next inbound type).', 'in_progress', 'high', NULL, 'server', 'D-225', '2026-06-12 10:40:58', '2026-06-12 10:56:40', NULL, '94f6ede90ac014280daee68a1216466a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ02VWJGXWDYT2SMXM9DTC', 'bug', '06FB0TNSRZXCHGS16BFHSSGSV4', 'BUG: fjord/cliff/gorge/delta landforms repeat on the 64 m chunk grid (D-239 §10 violation)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
BUG: four morphology generators fold world coordinates into the 64 m chunk frame, so region-scale landforms repeat every chunk — violating D-239 §10 (''features with wavelength > 64 m seed from Region-or-higher, not the chunk seed''; deliberately strengthened from Block-or-higher in the adversarial verification pass, tile-derivation-contract/workshop-outcomes.md:83).
|
||
|
||
Sites (server/src/atlas/voxel.rs):
|
||
- generate_fjord_wall :594-597 — cross.rem_euclid(64)-32: a complete fjord (floor|moraine|wall cross-section) centred in EVERY chunk of a FjordWall region; a real fjord valley is one feature spanning the region.
|
||
- generate_cliff_coast :721 — seaward_coord.rem_euclid(64): the cliff face sits at intra-chunk offset 48-55 in every chunk, sawtoothing the coastline at 64 m pitch.
|
||
- generate_braided_delta :825 — cross.rem_euclid(64): the same three braid threads restart per chunk instead of anastomosing across the fan.
|
||
- generate_incised_gorge :1054-1057 — same fold: a gorge per chunk.
|
||
|
||
Fix: compute each landform''s axis/centreline in REGION-anchored coordinates — derive the feature anchor (centreline position, coast-face line) once per region from the region-scale seed path that meander_phase/basin_direction already use correctly (chunk_context.rs:124-141), then measure each voxel''s distance to that anchor in continuous world coordinates (no rem_euclid against the chunk size). This matches the workshop''s seam-freedom principle: the algorithm must see positions with no knowledge of the chunk grid (tyre-round1.md:174-176). Preserve D-239 §9 chokepoint widths (fjord floor 4-8 m, gorge floor 2-8 m — currently honoured at :607-609, :1059-1062).
|
||
|
||
Harness gap to close (T-1031 follow-up): current tests check per-chunk boundary smoothness, not feature uniqueness — add a multi-chunk assertion that a FjordWall/IncisedGorge region contains ONE valley spanning its chunks, and a CliffCoast region one continuous (warp-displaced) coast line. Sibling bug: river-channel-anchor (channels are origin-anchored and appear nowhere; landforms are chunk-folded and appear everywhere — fix both against the same region-anchor mechanism). Depends on scale-anchoring Q for the region''s physical extent, but the region-index anchor works regardless. Parent: T-750. Refs: D-239 §5/§8/§9/§10, D-010; T-1029, T-1031.', 'in_progress', 'high', NULL, 'server', 'D-239', '2026-06-12 10:23:49', '2026-06-12 10:56:40', NULL, 'c1189a915611efac3027617e7915776a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBQ8WGMA3552756BQAAFPMER', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Bridge: escalate persistent corrupt-stream errors to shutdown (oversized-prefix poison)', 'Follow-up from the T-1045 review (2026-06-12). The receive_bridge_inputs catch-all arm logs unknown bridge errors once per tick and retries; a protocol-violating stream is unrecoverable by design (the FrameAccumulator oversized-prefix guard deliberately re-reports InvalidData on every poll), so a corrupt stream logs at 20 Hz forever with no escalation and no client feedback. Roughly parity with pre-T-1045 behavior (garbage cascade), so not a regression — but decide and implement escalation: map InvalidData to a fatal arm in receive_bridge_inputs, or count consecutive identical-error ticks and shut down after N. See the catch-all comment in server/src/bridge/mod.rs (receive_bridge_inputs) and the poison-state comment in framing.rs. Optional rider from the same review: harden assert_split_frame_does_not_desync (server/tests/bridge_tcp.rs) with channel synchronization so the mid-frame poll is guaranteed rather than timing-likely.', 'backlog', 'low', NULL, 'server', NULL, '2026-06-12 11:41:59', '2026-06-12 11:41:59', NULL, '77ded3c2d4cf7c6c623868bdb7ff5dd5', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ02VWJGXWDYT2SMXM9DTC', 'bug', '06FB0TNSRZXCHGS16BFHSSGSV4', 'BUG: fjord/cliff/gorge/delta landforms repeat on the 64 m chunk grid (D-239 §10 violation)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
BUG: four morphology generators fold world coordinates into the 64 m chunk frame, so region-scale landforms repeat every chunk — violating D-239 §10 (''features with wavelength > 64 m seed from Region-or-higher, not the chunk seed''; deliberately strengthened from Block-or-higher in the adversarial verification pass, tile-derivation-contract/workshop-outcomes.md:83).
|
||
|
||
Sites (server/src/atlas/voxel.rs):
|
||
- generate_fjord_wall :594-597 — cross.rem_euclid(64)-32: a complete fjord (floor|moraine|wall cross-section) centred in EVERY chunk of a FjordWall region; a real fjord valley is one feature spanning the region.
|
||
- generate_cliff_coast :721 — seaward_coord.rem_euclid(64): the cliff face sits at intra-chunk offset 48-55 in every chunk, sawtoothing the coastline at 64 m pitch.
|
||
- generate_braided_delta :825 — cross.rem_euclid(64): the same three braid threads restart per chunk instead of anastomosing across the fan.
|
||
- generate_incised_gorge :1054-1057 — same fold: a gorge per chunk.
|
||
|
||
Fix: compute each landform''s axis/centreline in REGION-anchored coordinates — derive the feature anchor (centreline position, coast-face line) once per region from the region-scale seed path that meander_phase/basin_direction already use correctly (chunk_context.rs:124-141), then measure each voxel''s distance to that anchor in continuous world coordinates (no rem_euclid against the chunk size). This matches the workshop''s seam-freedom principle: the algorithm must see positions with no knowledge of the chunk grid (tyre-round1.md:174-176). Preserve D-239 §9 chokepoint widths (fjord floor 4-8 m, gorge floor 2-8 m — currently honoured at :607-609, :1059-1062).
|
||
|
||
Harness gap to close (T-1031 follow-up): current tests check per-chunk boundary smoothness, not feature uniqueness — add a multi-chunk assertion that a FjordWall/IncisedGorge region contains ONE valley spanning its chunks, and a CliffCoast region one continuous (warp-displaced) coast line. Sibling bug: river-channel-anchor (channels are origin-anchored and appear nowhere; landforms are chunk-folded and appear everywhere — fix both against the same region-anchor mechanism). Depends on scale-anchoring Q for the region''s physical extent, but the region-index anchor works regardless. Parent: T-750. Refs: D-239 §5/§8/§9/§10, D-010; T-1029, T-1031.', 'done', 'high', NULL, 'server', 'D-239', '2026-06-12 10:23:49', '2026-06-12 11:50:14', NULL, '153926bd42d88e318fae1709cc047fc3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ02QTVSZ1PXTGNCN6Y8KM', 'bug', '06FB0TNSRZXCHGS16BFHSSGSV4', 'BUG: river channel centrelines anchored to the world-origin axis — channels absent in almost every chunk', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
BUG: channel centrelines are anchored to the world-origin axis. compute_channel_state (AlluvialPlain, server/src/atlas/voxel.rs:1648-1707) and compute_meander_channel_state (MeanderReach, :1556-1595) compute perp_distance = (cross - meander_displacement).abs() (:1694, :1583) where cross is the raw world-space voxel coordinate (derive_voxel_column takes tile_x/tile_y in world metres, :328-338; cross = vx or vy at :1653-1661). The channel centreline is therefore the world x=0/y=0 axis plus-or-minus meander amplitude: only chunks within ~(channel_width/2 + amplitude + jitter) metres of the world origin axis ever contain channel water, regardless of ChunkContext.has_active_channel / channel_width_m (chunk_context.rs:103-110). in_levee_band (:1602-1633) inherits the same defect, so levees are origin-locked too. Every has_active_channel chunk elsewhere on the body silently renders dry floodplain.
|
||
|
||
Intended model (workshopped): channel positions derive from region/chunk-scale data, not world axes — D-239 §10 (one basin-direction + global meander-curve params; wavelength > 64 m seeds Region-or-higher) and tile-derivation-contract/gestalt-round1.md:152-162 (channel branch positions from a multi-seed Voronoi partition of the chunk area with D8 flow direction as attractor; meander_intensity controls deviation from the straight downslope path).
|
||
|
||
Fix, two stages:
|
||
1. Minimal correctness: derive a deterministic cross-offset channel anchor at region scale (alongside meander_phase in derive_chunk_context, chunk_context.rs:124-141 — same Region-or-higher seed path) and measure perp_distance from that anchor, so an active channel actually crosses the chunks the region says it crosses, continuously across chunk boundaries.
|
||
2. Full model: gestalt''s multi-seed Voronoi + D8-attractor branch placement when BraidedDelta sub-classification (D-239 implementation note: deferred to ChunkContext) lands.
|
||
|
||
Add a T-1031-harness believability check: a has_active_channel chunk at an arbitrary large world offset (e.g. chunk_pos (1000, -750)) contains in-channel voxels; channel position is continuous across adjacent chunk pairs. Sibling bug: landform-64m-repeat (same family, opposite direction — channels appear nowhere, landforms appear everywhere). Parent: T-750. Refs: D-239 §10, D-208 (D8), D-010; T-1029 (origin), T-1031 (harness).', 'done', 'high', NULL, 'server', 'D-239', '2026-06-12 10:23:49', '2026-06-12 11:50:14', NULL, '7358e6296911def4afa30c6e36bbe9e6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXNWWGS3S0RFMFYQC9BWR', 'bug', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Bridge: fix TCP partial-read frame desync; drain all ready inbound frames per tick', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-01, S-02; citations adversarially verified).
|
||
DESYNC (S-01, high): the stream is non-blocking (tcp.rs:48-52); read_framed uses read_exact for the 4-byte prefix and payload with no partial-frame state (framing.rs:36-61); read_exact hitting WouldBlock mid-frame irrecoverably consumes bytes, and receive() maps WouldBlock to Ok(None) (tcp.rs:211) — a frame split across TCP segments permanently desyncs the stream (next read treats mid-frame bytes as a length prefix). Works today only because localhost frames arrive in single segments; BufReader is bypassed via get_mut(). Fix: persistent partial-frame accumulation buffer on TcpBridge (or blocking reader thread feeding a channel). Regression test: deliver one frame in two writes with flush+delay.
|
||
DRAIN (S-02, med): receive_bridge_inputs calls receive() exactly once per 50 ms tick (bridge/mod.rs:162, no loop; tick at main.rs:306) — an input batch + AtlasLayerRequest in one window backlogs and drains one frame per tick. Fix: loop receive() until Ok(None) with a per-tick cap. The D-225 atlas channel shares this path, so both fixes gate Atlas streaming reliability.
|
||
Extension constraint when touching this code: D-225 amendment 2026-06-12 (tagged envelope for the next inbound type).', 'done', 'high', NULL, 'server', 'D-225', '2026-06-12 10:40:58', '2026-06-12 11:50:14', NULL, 'b873911a4635f336e9988abf7ddb2625', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ02QTVSZ1PXTGNCN6Y8KM', 'bug', '06FB0TNSRZXCHGS16BFHSSGSV4', 'BUG: river channel centrelines anchored to the world-origin axis — channels absent in almost every chunk', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
BUG: channel centrelines are anchored to the world-origin axis. compute_channel_state (AlluvialPlain, server/src/atlas/voxel.rs:1648-1707) and compute_meander_channel_state (MeanderReach, :1556-1595) compute perp_distance = (cross - meander_displacement).abs() (:1694, :1583) where cross is the raw world-space voxel coordinate (derive_voxel_column takes tile_x/tile_y in world metres, :328-338; cross = vx or vy at :1653-1661). The channel centreline is therefore the world x=0/y=0 axis plus-or-minus meander amplitude: only chunks within ~(channel_width/2 + amplitude + jitter) metres of the world origin axis ever contain channel water, regardless of ChunkContext.has_active_channel / channel_width_m (chunk_context.rs:103-110). in_levee_band (:1602-1633) inherits the same defect, so levees are origin-locked too. Every has_active_channel chunk elsewhere on the body silently renders dry floodplain.
|
||
|
||
Intended model (workshopped): channel positions derive from region/chunk-scale data, not world axes — D-239 §10 (one basin-direction + global meander-curve params; wavelength > 64 m seeds Region-or-higher) and tile-derivation-contract/gestalt-round1.md:152-162 (channel branch positions from a multi-seed Voronoi partition of the chunk area with D8 flow direction as attractor; meander_intensity controls deviation from the straight downslope path).
|
||
|
||
Fix, two stages:
|
||
1. Minimal correctness: derive a deterministic cross-offset channel anchor at region scale (alongside meander_phase in derive_chunk_context, chunk_context.rs:124-141 — same Region-or-higher seed path) and measure perp_distance from that anchor, so an active channel actually crosses the chunks the region says it crosses, continuously across chunk boundaries.
|
||
2. Full model: gestalt''s multi-seed Voronoi + D8-attractor branch placement when BraidedDelta sub-classification (D-239 implementation note: deferred to ChunkContext) lands.
|
||
|
||
Add a T-1031-harness believability check: a has_active_channel chunk at an arbitrary large world offset (e.g. chunk_pos (1000, -750)) contains in-channel voxels; channel position is continuous across adjacent chunk pairs. Sibling bug: landform-64m-repeat (same family, opposite direction — channels appear nowhere, landforms appear everywhere). Parent: T-750. Refs: D-239 §10, D-208 (D8), D-010; T-1029 (origin), T-1031 (harness).
|
||
|
||
Fixed 2026-06-12, commit 408bd39e (+ fmt fixup 993333fa). Region-anchored channel axes (channel_anchor_m) derived from the Region-or-higher seed path; perp_distance measured from the anchor, not the world origin. has_active_channel made honest in both directions (band-crossing gate, delta-belt floor). Harness: channel presence + gate honesty asserted at chunk (1000,-750), cross-boundary continuity under production chunk lookup. Golden case A now pins a genuinely in-channel Shallow voxel. Adversarially reviewed (approved; 3 minors fixed in-line). Gate: 1488 tests green.', 'done', 'high', NULL, 'server', 'D-239', '2026-06-12 10:23:49', '2026-06-12 11:50:14', NULL, '9d388b1ef84c48755de71466e0f4c3d5', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ02VWJGXWDYT2SMXM9DTC', 'bug', '06FB0TNSRZXCHGS16BFHSSGSV4', 'BUG: fjord/cliff/gorge/delta landforms repeat on the 64 m chunk grid (D-239 §10 violation)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
BUG: four morphology generators fold world coordinates into the 64 m chunk frame, so region-scale landforms repeat every chunk — violating D-239 §10 (''features with wavelength > 64 m seed from Region-or-higher, not the chunk seed''; deliberately strengthened from Block-or-higher in the adversarial verification pass, tile-derivation-contract/workshop-outcomes.md:83).
|
||
|
||
Sites (server/src/atlas/voxel.rs):
|
||
- generate_fjord_wall :594-597 — cross.rem_euclid(64)-32: a complete fjord (floor|moraine|wall cross-section) centred in EVERY chunk of a FjordWall region; a real fjord valley is one feature spanning the region.
|
||
- generate_cliff_coast :721 — seaward_coord.rem_euclid(64): the cliff face sits at intra-chunk offset 48-55 in every chunk, sawtoothing the coastline at 64 m pitch.
|
||
- generate_braided_delta :825 — cross.rem_euclid(64): the same three braid threads restart per chunk instead of anastomosing across the fan.
|
||
- generate_incised_gorge :1054-1057 — same fold: a gorge per chunk.
|
||
|
||
Fix: compute each landform''s axis/centreline in REGION-anchored coordinates — derive the feature anchor (centreline position, coast-face line) once per region from the region-scale seed path that meander_phase/basin_direction already use correctly (chunk_context.rs:124-141), then measure each voxel''s distance to that anchor in continuous world coordinates (no rem_euclid against the chunk size). This matches the workshop''s seam-freedom principle: the algorithm must see positions with no knowledge of the chunk grid (tyre-round1.md:174-176). Preserve D-239 §9 chokepoint widths (fjord floor 4-8 m, gorge floor 2-8 m — currently honoured at :607-609, :1059-1062).
|
||
|
||
Harness gap to close (T-1031 follow-up): current tests check per-chunk boundary smoothness, not feature uniqueness — add a multi-chunk assertion that a FjordWall/IncisedGorge region contains ONE valley spanning its chunks, and a CliffCoast region one continuous (warp-displaced) coast line. Sibling bug: river-channel-anchor (channels are origin-anchored and appear nowhere; landforms are chunk-folded and appear everywhere — fix both against the same region-anchor mechanism). Depends on scale-anchoring Q for the region''s physical extent, but the region-index anchor works regardless. Parent: T-750. Refs: D-239 §5/§8/§9/§10, D-010; T-1029, T-1031.
|
||
|
||
Fixed 2026-06-12, commit 408bd39e. All four rem_euclid(64) chunk-frame folds removed (fjord :594-597, cliff :721, delta :825/:865, gorge :1054-1057); landform axes anchored once per region in continuous world coords. D-239 §9 chokepoint widths preserved; two i32 wall-rise overflows on region-scale distances fixed (clamp before multiply). Harness: one-valley-per-region, one-continuous-coastline-per-region, braid-belt confinement. CliffCoast semantics deliberately changed: one coast split per region (the §10 intent), not 75% inland per chunk. L0/L1 goldens byte-identical — no upstream leak. Adversarially reviewed (approved).', 'done', 'high', NULL, 'server', 'D-239', '2026-06-12 10:23:49', '2026-06-12 11:50:14', NULL, '54193ccc0271e35ba5d9721568a099e8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXNWWGS3S0RFMFYQC9BWR', 'bug', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Bridge: fix TCP partial-read frame desync; drain all ready inbound frames per tick', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-01, S-02; citations adversarially verified).
|
||
DESYNC (S-01, high): the stream is non-blocking (tcp.rs:48-52); read_framed uses read_exact for the 4-byte prefix and payload with no partial-frame state (framing.rs:36-61); read_exact hitting WouldBlock mid-frame irrecoverably consumes bytes, and receive() maps WouldBlock to Ok(None) (tcp.rs:211) — a frame split across TCP segments permanently desyncs the stream (next read treats mid-frame bytes as a length prefix). Works today only because localhost frames arrive in single segments; BufReader is bypassed via get_mut(). Fix: persistent partial-frame accumulation buffer on TcpBridge (or blocking reader thread feeding a channel). Regression test: deliver one frame in two writes with flush+delay.
|
||
DRAIN (S-02, med): receive_bridge_inputs calls receive() exactly once per 50 ms tick (bridge/mod.rs:162, no loop; tick at main.rs:306) — an input batch + AtlasLayerRequest in one window backlogs and drains one frame per tick. Fix: loop receive() until Ok(None) with a per-tick cap. The D-225 atlas channel shares this path, so both fixes gate Atlas streaming reliability.
|
||
Extension constraint when touching this code: D-225 amendment 2026-06-12 (tagged envelope for the next inbound type).
|
||
|
||
Fixed 2026-06-12, commit 49a74e93 (+ review hardening). FrameAccumulator state machine holds partial prefix/payload across non-blocking receive() calls; drain loop with per-tick cap covers inputs + atlas requests. Review fix_required item resolved: EOF mid-frame now escalates to Disconnected (peer dead, frame can never complete) instead of per-tick Io error spam — regression test added (2 prefix bytes then drop). Minors: comment reworded; corrupt-stream escalation filed as T-1072; split-frame test hardening noted on T-1072. Gate: 1488 tests green.', 'done', 'high', NULL, 'server', 'D-225', '2026-06-12 10:40:58', '2026-06-12 11:50:14', NULL, '5f314f655cd285f4e8ad7e481e254cb6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY3TXD5HDKHFVGDG18', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_implant_app_lifecycle: 1 failure — ImplantApp or HudGroups state API', '1 failing test case in test_implant_app_lifecycle.gd. Suite tests ImplantApp._internal_app_changed, nav stack, preserves_state, and HudGroups state. after_test resets HudGroups._active_app, _active_mode, _groups — if these private fields were renamed or removed, after_test would fail and bleed state. Or a specific on_open/on_close hook fires differently. Run --filter test_implant_app_lifecycle and check specific assertion. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'in_progress', 'low', NULL, 'client', NULL, '2026-05-02 08:12:32', '2026-06-12 12:02:03', NULL, '1108dfbc854c17e0a1a07b458bd043b7', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXS5YZ04F4CPPYNZS4Z2W', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Docs-drift sweep: one-generator reality, dead check-protocol target, DEVOPS hook sections, project.yaml version, stale code comments', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-11, S-15, S-16, S-25, S-26, S-39; S-15/S-16 adversarially verified).
|
||
1. S-15: docs/DEVOPS.md:211-230 documents three generators, .claude/rules/asset-pipeline.md:22,27,36 documents two with a literal command for a file that does not exist (tooling/planet-gen/generate_atlas.py, retired #951/D-223); truth is one (import_economics — Makefile:334-352, stamp registry). Fix both + the CLAUDE.md asset-pipeline snippet.
|
||
2. S-16: delete make check-protocol (Makefile:123-130 greps constants deleted under D-192 via T-874/T-875 — empty==empty always passes); drop from build dep (:132) and help (:42).
|
||
3. S-25: rewrite DEVOPS.md hook/config sections from current sources (pre-push table omits cargo test/deny/clerk + advisory gdlint status; .config/ description never materialized; pre-commit row omits pql validate/export).
|
||
4. S-26: project.yaml says version 0.2.0 under the 0.{phase}.{n} scheme with Phase 4 active, and its description still narrates the v0.1 Sova slice — bump to 0.4.n (or document the bump trigger) + refresh description.
|
||
5. S-39: update voxel.rs module doc (:41-48) and MorphologyFamily variant comments (:256-280) still claiming 7 families are unimplemented stubs (T-1029 landed them all); fix cascade.rs:219 TODO citing closed T-1028 (now tracked by T-1044).
|
||
6. S-11: comment sweep — main.rs:126-127 claims a protocol_version handshake that D-192 removed; npc/relationships.rs:92 TODO(v0.2); chunk_streaming.rs:6,21-22 v0.3+ — rephrase version targets as phase numbers.', 'in_progress', 'medium', NULL, NULL, NULL, '2026-06-12 10:40:59', '2026-06-12 12:02:03', NULL, '1a233ede23af3311ea9bdfd18ebc312c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXS18RSVRHC7Y9TAX06HG', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Client hygiene batch: orphan .gd.uid files, time_display removal rider, _format_pop dedupe, skip_test_ triage', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-21, S-22, S-24; low severity — spot-check citations at pickup).
|
||
1. S-21 now: delete 7 tracked orphan .gd.uid files whose scripts are gone (client/scripts/rendering/fog_renderer.gd.uid; client/ui/{bug_report_dialog,character_select,debug_console,loading_screen,main_menu,settings_dialog}.gd.uid). Phase-5 rider: remove time_display.gd/.tscn + its 199-line test (superseded by the merged HUD row per hud.gd:4 / #786) with the Phase-5 rendering pass, not before (D-166).
|
||
2. S-22: deduplicate _format_pop — byte-identical 12-line implementations in planet_screen.gd:105-116 and system_screen.gd:685-696 (plus _format_radius) into a shared atlas helper.
|
||
3. S-24: triage the 9 permanently disabled skip_test_ functions (test_sprint2_proof.gd:117,147,169; test_etalk_overlay_sprint17.gd:267-273; test_client_p2.gd:70,100,198) — re-enable, delete, or attach a T-id; convert the push_warning-then-return soft-skip pattern (test_fog_shader, test_audio_sprint13, test_monologue_display, test_input_roundtrip:54) to gdUnit4 skip reporting so missing prerequisites are visible in the JSON summary, not silently green.', 'in_progress', 'low', NULL, 'client', NULL, '2026-06-12 10:40:59', '2026-06-12 12:02:03', NULL, '1a26321a1ab62ad9a15398ef27e4f2fd', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXN360AQN3973AHS8M', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_dialogue_sprint20: 5 failures — AudioManager.get_active_dip or other API drift', '5 failing test cases in test_dialogue_sprint20.gd. The suite tests D-020 signal decoupling for dialogue_box. Likely failure: test_show_dialogue_does_not_call_audio_manager_directly compares AudioManager.get_active_dip() before/after show_dialogue — if AudioManager.get_active_dip() behavior changed or is not returning clean state, this would fail. Investigate by running the suite in isolation and reading specific assertion failures from the log. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'in_progress', 'low', NULL, 'client', NULL, '2026-05-02 08:11:54', '2026-06-12 12:02:03', NULL, '1ca6eb573c01be2f53a2a6afc6c76c85', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXCE9D9JYBZWVXMG68', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_ai_dialogue_sprint26: 1 failure — HardwareDetector autoload missing or settings_dialog API', '1 failing test case in test_ai_dialogue_sprint26.gd. The HardwareDetector tests skip if autoload not found. The GameState field tests (ai_enhanced_dialogue_enabled) look correct. The failing test is likely in the settings_dialog section: SETTINGS_DIALOG_SCENE preloaded at class level — if settings_dialog.tscn doesn''t exist or a method was renamed, class-level preload would fail. Check res://ui/settings_dialog.tscn exists and the relevant methods. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'in_progress', 'low', NULL, 'client', NULL, '2026-05-02 08:13:02', '2026-06-12 12:02:03', NULL, '451dd5fd4a11eb2ce1c400f24331ea28', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYF23MZ86S1XF1542G', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_fog_shader: 1 failure — stale VIS_PERIPHERAL or peripheral sector assertion', '1 failing test case in test_fog_shader.gd. The most likely failure is test_fog_state_forward_vs_peripheral: it asserts Forward > Peripheral visibility values, but Sprint 22 (#569) removed peripheral sector. Now all visible tiles write VIS_FORWARD regardless. The test checks the texture is non-null (not the actual byte values), so it should pass... unless the failure is in test_fog_state_exploration_persists which has a weak assertion. Run --filter test_fog_shader to identify the specific failure. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'in_progress', 'low', NULL, 'client', NULL, '2026-05-02 08:12:45', '2026-06-12 12:02:03', NULL, '50fdf7d80f80cd66756b9ad34314fc6e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXSEC1F0RKJVH7JVPS8NW', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Wiki sweep: real link breaks, stale nav surfaces, GOVERNANCE/template reconcile, Sol legacy markers, triangles index', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-54, S-55, S-56, S-59; S-54/S-55/S-56 adversarially verified, S-59 agent-reported).
|
||
1. S-54 (~26 real breaks): knowledge/→concepts/ rename leftovers (3 contraband files, triangles/hub-power.md:420, authoring/monologue-guide.md ×7); pre-governance decisions/ anchors (monologue-guide.md:834-836); 9 phantom companion-system links in star-systems/catalog.md (index.md handles the same companions correctly as unlinked text); factions/cygni-b-combines.md absent (linked from stalownia-kowalski.md:111); concepts/entity-attributes.md:280 wrong relative path to an existing doc.
|
||
2. S-55: wiki/index.md:12 claims "10 fully written" vs ~301 reality; corporations/index.md links 38/155 (117 orphaned); zero nav link to economics/ (39 md + 20 TOML, the primary generator source); 25 station-level gttr-*.md orphaned from their system pages. Regenerate counts from the catalog (or let wiki_sync own them); autogenerate the corp index from frontmatter.
|
||
3. S-56: wiki/GOVERNANCE.md:39-54 prescribes a star-systems/{system}/{station}/{district} hand-authored tree that has zero instances, and _templates/star-system.md:1-18 mandates frontmatter that 0/302 system pages have — rewrite both to the generated model (wiki_sync.py: DB owns structured fields, wiki owns prose) or decide system pages should carry frontmatter and have wiki_sync emit it.
|
||
4. S-59: convert the 4 pre-D-223 geometry-bearing Sol markers.json (GJ-0 bodies, authored coordinates/populations) to names-only, moving the authored data to the Sol special-case home; add wiki/triangles/index.md or de-link it from wiki/index.md:19.
|
||
Audit wiki survey (verified 2026-06-12):
|
||
# wiki/ directory map
|
||
|
||
| Directory | Files | Format | Machine-readable (feeds DB)? | Completeness |
|
||
|---|---|---|---|---|
|
||
| star-systems/ | 3,262 md + 2,398 json + 5,921 png | md (no frontmatter on system pages; YAML frontmatter on body pages), markers.json, png | YES — body frontmatter (axial_tilt → import_economics.py:1286), markers.json city names (:1451), gttr.md → gttr_hook (populate_gttr_hook.py); system infobox/bodies tables generated FROM systems.db (wiki_sync.py) | 302 system dirs; 301 full prose (Supply Dependency 301, Silence Topic 288, Calibration Note 261); 2,625 body pages all with EMPTY Description; 302 gttr.md + 6 corridor + 24 station GTTRs; heightmap.png only 267 vs globe 3,256/reliefmap 2,398; GJ-280B = sole stub |
|
||
| economics/ | 39 md + 20 toml | TOML (source of truth) + md prose | YES — commodities.toml, production_chains.toml, currency_zones.toml, specialization_vocabulary.toml (27), system_specialization.toml (240/301 pins), architecture_trait_catalog.toml (28 templates) + bias, brands/generated_brands/tier1/tier2 | Complete for current decisions (D-173..D-182, D-232, D-237; T-1016 done); not linked from wiki/index.md |
|
||
| corporations/ | 156 md | md + YAML frontmatter | YES — frontmatter slug/title/headquarters/tags/scope → corporations + corp_presence (import_economics.py:734-790, D-182 wiki-is-truth) | 155 canonical pages ~8-16KB; index.md lists only 38 (117 orphaned from nav) |
|
||
| factions/ | 9 md | md + frontmatter | No (prose; dominant_faction comes from economics TOML) | Complete: 6 major + 1 regional + 1 local worked example, all canonical, clean index |
|
||
| technology/ | 7 md | md | No | Complete (6 entries + index) |
|
||
| contraband/ | 4 md | md + frontmatter | No | Complete (3 entries + index); stale ../knowledge/ links |
|
||
| concepts/ | 4 md | md | No | Complete (fact-catalog, entity-attributes, relationship-states); renamed from knowledge/, inbound links broken |
|
||
| authoring/ | 12 md (incl. npc-patterns/ 3) | md | No (authoring guides) | Complete; monologue-guide has 9 stale links (knowledge/, pre-governance decisions/ paths) |
|
||
| triangles/ | 1 md | md + frontmatter | No | One worked example (hub-power.md); index.md missing (broken link from wiki root) |
|
||
| cultural-groups/ | 0 (.gitkeep) | — | — | EMPTY (template exists) |
|
||
| institutions/ | 0 (.gitkeep) | — | — | EMPTY (template exists; covered under factions/) |
|
||
| lore/ | 0 (.gitkeep) | — | — | EMPTY (template exists) |
|
||
| species/ | 0 (.gitkeep) | — | — | EMPTY (template exists) |
|
||
| _templates/ | 17 md | md | — | Complete but drifted: star-system template ≠ generated reality; station/district/location/cultural-group/species/lore/institution templates have 0 instances |
|
||
| glossary.md / GOVERNANCE.md / index.md | 3 md | md | No | Glossary current (incl. TOML/DB terminology + anti-drift list); GOVERNANCE spatial hierarchy + status lifecycle stale; index.md counts stale (''10 fully written'' vs ~301) |
|
||
|
||
# Star-systems census
|
||
- Systems: 302 dirs (catalog claims 301; 220 named / 81 unnamed); 9 catalog rows link nonexistent companion dirs
|
||
- Bodies: 2,625 body pages (planets, moons, belts, oort clouds; no per-type subdirs — flat bodies/ per system)
|
||
- Stations: 0 wiki pages; rows in systems.db rendered into ''Stations & Facilities'' tables per system index + 24 station GTTR prose files
|
||
- Markers: 2,394 names-only (D-223) + 4 legacy geometry (all GJ-0/Sol)
|
||
|
||
# Generation data flow (verified)
|
||
wiki/economics/*.toml + wiki/corporations/*.md frontmatter + wiki/star-systems body frontmatter + markers.json names → tooling/economy-db/import_economics.py → server/data/systems.db (stamped, tooling/check-systems-db-stamp) → client Atlas (gttr_excerpt popups, reach_screen.gd:178) + direct runtime load of wiki globe.png (system_screen.gd:482-492). wiki_sync.py: DB owns structured fields, wiki owns prose sections.
|
||
|
||
# docs/ health snapshot
|
||
- docs/architecture/ (19): current — pql-migration.md (2026-06-06), atlas-naming-pipeline, implant-app-pattern; historical — sprint-36/37 audits, v01-yaml-content-audit, eval/risk-godot-rust-bridge (2026-03-13)
|
||
- docs/design/ (60+): ~35 files frozen at 2026-02-19→03-14, status:active but v0.1/v0.2-era (wow-moments, first-5-minutes, spatial-layout-*-v01, dueling content-structure docs); still-load-bearing: star-map.json (Topology source), gj-catalog-full.json, planetary-terrain-generation.md, cultural-diversity-audit.md (remediated, T-793 done), sova-station-profile.md (canon for the stub system)', 'in_progress', 'medium', NULL, 'content', NULL, '2026-06-12 10:40:59', '2026-06-12 12:02:03', NULL, '626d75380801ac5c7e413b14b01a46c1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY9FV0S9RE42WY7SHW', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_audio_sprint13: 1 failure — AudioManager.clear_dip or API drift', '1 failing test case in test_audio_sprint13.gd. before_test calls AudioManager.clear_dip(), stop_all_loops(), set_volume() for all buses. If any of these methods were renamed or a bus constant changed, setup would fail and cascade. Or a specific dip timing assertion is stale. Run --filter test_audio_sprint13 and read the specific failure. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'in_progress', 'low', NULL, 'client', NULL, '2026-05-02 08:12:56', '2026-06-12 12:02:03', NULL, '63931d00ac6e6bdd529d0c4399790138', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRBRFW4MH5G8C0X12YGR', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Workers pool: add tests, fix panic-loss, correct the false "tested" doc claim', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-05; verified — zero tests exist for BackgroundWorkerPool anywhere).
|
||
workers/stubs.rs:7 claims the pool infrastructure is "real and tested" — false. pool.rs:8-13 documents that a worker-thread panic silently loses in-flight requests (TODO #843); for ModalLock consumers that means the player waits forever. SimulationPlugin spawns 4 live stub threads every session (simulation/mod.rs:85-87) for Phase-5+ functionality.
|
||
Do now: correct the doc claim; unit tests (spawn/push/poll/shutdown + worker-panic). Before any ModalLock consumer ships (Phase 5): heartbeat/re-enqueue or downgrade ModalLock to an error path. Optional: defer thread spawn until a real handler registers.', 'in_progress', 'medium', NULL, 'server', NULL, '2026-06-12 10:40:59', '2026-06-12 12:02:03', NULL, '7fa711e5c4e77c895f44a9a00c091719', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRG23G1RAREVHQJ14BWC', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Server hygiene batch: exemption contracts, dead deps, generator_spike quarantine, save/load ordering, economy.rs tests', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-06, S-07, S-08, S-09, S-12; low severity — spot-check citations at pickup).
|
||
1. S-06: add the consumer contract ("every consumer must sort before state/wire use") to the three perception disallowed-types allows (shadowcast.rs:17, query.rs:11, interpretation.rs:9).
|
||
2. S-07: delete unused bytemuck (Cargo.toml:30, zero references); fix the stale rayon comment (says "not yet called"; used in atlas/gen_queue.rs:192-228).
|
||
3. S-08: delete or feature-gate bin/generator_spike.rs (1,153 lines reimplementing npc/generate.rs outside ECS, 3 TODO(integration) duplication admissions); extract the shared surname corpus copied between generate_brands/names.rs and generate_corporations/names.rs (already drifted; both feed the systems.db stamp); prune or justify the 24 allow(dead_code) in generate_corporations.
|
||
4. S-09: pin execute_save_load with a lower-bound constraint (currently only .before(compute_observer_snapshot), simulation/mod.rs:106-114 — the scheduler may legally run it before Input, changing what a save captures); note the exclusive-system exception in tick_phases.rs rules.
|
||
5. S-12: unit tests for simulation/economy.rs signal derivation (382 lines, no cfg(test); fixtures set economy_snapshot: None) — trend windowing, first-tick baseline, zero-demand stockpile edge.', 'in_progress', 'low', NULL, 'server', NULL, '2026-06-12 10:40:59', '2026-06-12 12:02:03', NULL, '8999c1bf5577cdfb4d7ff8320f72024b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZYDBRV5T9QVQAXGV0', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_e2e_connection: 1 failure — server binary path or TCP connection state', '1 failing test case in test_e2e_connection.gd. test_send_input_receive_snapshot skips if server binary not found. If it fails, either: (1) server binary exists but connection fails (port collision, timing), or (2) LocalBridge.reset() method was removed (the test calls _bridge.reset() but this may not exist on LocalBridge). Verify LocalBridge has a reset() method. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'in_progress', 'low', NULL, 'client', NULL, '2026-05-02 08:12:51', '2026-06-12 12:02:03', NULL, '9981659bf076dde1fe66f5ab6e47e461', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYEM4VSX74MS4NKQ1C', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'Client test suite — pre-existing failures under bare run-godot', 'Surfaced 2026-05-24 running the full client suite (tests/run-godot, no server) during #960. NOT caused by #960 — verified: test_input_roundtrip fails identically at the pre-change baseline, and the rest are unrelated subsystems. Two categories to triage:
|
||
|
||
CATEGORY 1 — server-dependent (expected-fail under bare run-godot): test_e2e_connection (test_send_input_receive_snapshot), test_input_roundtrip (movement/interact/move_then_interact). They error with ''Nil snapshot'' / ''.tick on Nil'' because no sim server is spawned. They need the run-ipc-* harness or SR_LIVE=1. FIX OPTIONS: gate/skip these under bare run-godot (mark as requiring a server) OR have run-godot spawn the server for the e2e tier, so tests/run-godot
|
||
{"suite":"godot","total":2522,"passed":2482,"failed":40,"duration_ms":96836,"log":"/tmp/sr-run-godot.1737738.log"} is green without false negatives.
|
||
|
||
CATEGORY 2 — genuine logic failures in subsystems unrelated to current work: test_audio_sprint13 (test_d067_chime_duration_spec_is_300_to_400ms, line 547 ''Expecting true but is false''), test_fog_sprint22 (exploration_data_preserved_across_resize), test_fog_shader (visibility_texture_update_performance), test_dialogue_sprint18/20 (signal/audio-dip), test_monologue_display (queue_never_exceeds_max_depth), test_implant_app_lifecycle (on_insert_deactivated_closes_insert_app), test_ai_dialogue_sprint26 (settings_dialog warning label). Triage each: fix or remove/xfail with a reason.
|
||
|
||
Goal: a green (or explicitly-gated) bare `make test-client` so client regressions are detectable. Until then, run targeted suites (run-godot --filter <stem>).
|
||
|
||
Re-homed under maintenance (test-failure debt / suite hygiene) per cascade refocus 2026-06-12.', 'in_progress', 'medium', NULL, 'client', NULL, '2026-05-24 16:49:54', '2026-06-12 12:02:03', NULL, 'a534447428c3a4f0eebc5b38053250cb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWK87PCWGZ6GWT2TBM', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_game_state_sprint20: 1 failure — SnapshotHandler or stationary_ticks path', '1 failing test case in test_game_state_sprint20.gd. before_each resets SnapshotHandler._prev_player_position. If this static var was renamed or moved, the before_each hook would error. Alternatively a stationary_ticks path changed in SnapshotHandler. Verify SnapshotHandler still has static var _prev_player_position at that exact name. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'in_progress', 'low', NULL, 'client', NULL, '2026-05-02 08:12:38', '2026-06-12 12:02:03', NULL, 'b5bf0ac7b0e764bae1e17c69fd77f5ad', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRRDGJ5GFPGHZV3WS0D0', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Wire tooling tests into a gate: make test-tooling + pre-push on tooling changes', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-18; citations adversarially verified).
|
||
22,340 lines of tooling Python (including the systems.db generator) are verified only by a 4-rule ruff subset (pyproject.toml:26-31: E9/F401/F811/F821); zero pytest anywhere; the one real test (tooling/planet-gen/test_sim_determinism.py, guarding the expensive 271-body bake, exit codes 0/1/2) is wired into nothing.
|
||
Fix: make test-tooling = test_sim_determinism.py + import_economics --dry-run against the committed DB; call from pre-push when TOOLING_CHANGED > 0; widen the ruff selection.', 'in_progress', 'medium', NULL, NULL, NULL, '2026-06-12 10:40:59', '2026-06-12 12:02:03', NULL, 'c1ce9016e14e93003263e30033e95d1a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWBJ1XC9V5ZQHSXAXG', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'Rewrite P2-U01 monologue_display_visible_hidden test against current _visible array API', 'test_monologue_display_visible_hidden in test_client_p2.gd accessed mono.is_visible (a custom bool property). MonologueDisplay was refactored to use _visible: Array[Dictionary] instead. Test skipped (skip_test_) pending rewrite. New test should check _visible.size() > 0 after show_monologue, and == 0 when idle.
|
||
|
||
Re-homed under maintenance (test debt) per cascade refocus 2026-06-12.', 'in_progress', 'low', NULL, 'client', NULL, '2026-04-20 11:17:20', '2026-06-12 12:02:03', NULL, 'e0f58b478b902e102815af03c820a0fe', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXSA4WFXPD21YK7N8SF60', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Fix 2,131 broken heightmap.png body-page links — conditional scaffold link + regenerate', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-53; counts independently reproduced by verifier).
|
||
The body-page scaffold links  for all non-gas-giant bodies (scaffold_bodies.py:94-96) but heightmaps exist for only 267 bodies (vs 2,398 reliefmap.png / 3,256 globe.png) — 2,131 of the wiki''s 2,180 broken links are this one pattern, rendered as dead images in the implant wiki view. Fix: make the link conditional in the scaffold and regenerate the Visual section of body pages (or backfill heightmaps where Phase 4 wants them anyway — they are a generation input).', 'in_progress', 'medium', NULL, 'content', NULL, '2026-06-12 10:40:59', '2026-06-12 12:02:03', NULL, 'e52392e8a10513975b5bb0279ffcc98c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXMVYQJV2QDHH8H7P8', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_input_roundtrip: 3 failures — server binary missing or LocalBridge API change', '3 failing test cases in test_input_roundtrip.gd. All tests check _connect_to_server() which skips if server binary not found — but 3 still fail, suggesting either: (1) server binary is present but something in LocalBridge.send_message, poll, or Protocol.encode_player_inputs changed, or (2) test environment returns false from _connect_to_server but then asserts fail. Investigate by running with --filter test_input_roundtrip and checking the log for exact assertion sites. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'in_progress', 'low', NULL, 'client', NULL, '2026-05-02 08:11:59', '2026-06-12 12:02:03', NULL, 'f437e0c45508a6e8a8761cde942648a5', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBRCMEKT72S0Q6NE68JH7EXC', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Sol markers → D-223 names-only, migrated together with the Atlas legacy-geometry read path', 'Split from T-1071 (2026-06-12): converting the 4 legacy geometry-bearing GJ-0 markers.json (GJ0d, GJ0d-1, GJ0e, GJ0f-2) to the D-223 names-only schema is SAFE for generation (import_economics.py:1452 skips GJ 0 explicitly; all authored coordinates/populations verified present name-by-name in tooling/planet-gen/sol_markers/*.json + sol_name_fixes.py FIXES) but REGRESSES the client: atlas_viewer.gd:433 still loads markers.json per the legacy D-191 §8 geometry schema, so Sol bodies lose their city/river/mountain Atlas overlays. The conversion was implemented, verified, and then deliberately reverted to preserve working overlays. Land both halves together: (1) point the Sol overlay read at the proper Sol home (sol_markers/ or a baked path — Q-107 consolidation may decide this), (2) convert the 4 files, (3) also fix the residual debt: sol_import.py still WRITES legacy-schema markers and an unconditional heightmap link in its own _write_index_md, and import_economics.py:1485 carries a now-misleading comment about preserved geometry markers (editing it stales the systems.db stamp — bundle with a regen).', 'backlog', 'low', NULL, 'client', NULL, '2026-06-12 14:18:10', '2026-06-12 14:18:10', NULL, '78e79b505b63901bf719649afc634080', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY3TXD5HDKHFVGDG18', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_implant_app_lifecycle: 1 failure — ImplantApp or HudGroups state API', '1 failing test case in test_implant_app_lifecycle.gd. Suite tests ImplantApp._internal_app_changed, nav stack, preserves_state, and HudGroups state. after_test resets HudGroups._active_app, _active_mode, _groups — if these private fields were renamed or removed, after_test would fail and bleed state. Or a specific on_open/on_close hook fires differently. Run --filter test_implant_app_lifecycle and check specific assertion. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'done', 'low', NULL, 'client', NULL, '2026-05-02 08:12:32', '2026-06-12 14:24:13', NULL, '0948ff140a69ce9d955178f925d4bfa6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRRDGJ5GFPGHZV3WS0D0', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Wire tooling tests into a gate: make test-tooling + pre-push on tooling changes', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-18; citations adversarially verified).
|
||
22,340 lines of tooling Python (including the systems.db generator) are verified only by a 4-rule ruff subset (pyproject.toml:26-31: E9/F401/F811/F821); zero pytest anywhere; the one real test (tooling/planet-gen/test_sim_determinism.py, guarding the expensive 271-body bake, exit codes 0/1/2) is wired into nothing.
|
||
Fix: make test-tooling = test_sim_determinism.py + import_economics --dry-run against the committed DB; call from pre-push when TOOLING_CHANGED > 0; widen the ruff selection.', 'done', 'medium', NULL, NULL, NULL, '2026-06-12 10:40:59', '2026-06-12 14:24:13', NULL, '1d82c2adab154cc4d390fd6e428ebea9', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWK87PCWGZ6GWT2TBM', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_game_state_sprint20: 1 failure — SnapshotHandler or stationary_ticks path', '1 failing test case in test_game_state_sprint20.gd. before_each resets SnapshotHandler._prev_player_position. If this static var was renamed or moved, the before_each hook would error. Alternatively a stationary_ticks path changed in SnapshotHandler. Verify SnapshotHandler still has static var _prev_player_position at that exact name. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'done', 'low', NULL, 'client', NULL, '2026-05-02 08:12:38', '2026-06-12 14:24:13', NULL, '3e0fe7ac0f42fbbe6fef466c5ad63c9c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXCE9D9JYBZWVXMG68', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_ai_dialogue_sprint26: 1 failure — HardwareDetector autoload missing or settings_dialog API', '1 failing test case in test_ai_dialogue_sprint26.gd. The HardwareDetector tests skip if autoload not found. The GameState field tests (ai_enhanced_dialogue_enabled) look correct. The failing test is likely in the settings_dialog section: SETTINGS_DIALOG_SCENE preloaded at class level — if settings_dialog.tscn doesn''t exist or a method was renamed, class-level preload would fail. Check res://ui/settings_dialog.tscn exists and the relevant methods. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'done', 'low', NULL, 'client', NULL, '2026-05-02 08:13:02', '2026-06-12 14:24:13', NULL, '40073cb9ac939fee03085888f9de1a15', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRBRFW4MH5G8C0X12YGR', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Workers pool: add tests, fix panic-loss, correct the false "tested" doc claim', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-05; verified — zero tests exist for BackgroundWorkerPool anywhere).
|
||
workers/stubs.rs:7 claims the pool infrastructure is "real and tested" — false. pool.rs:8-13 documents that a worker-thread panic silently loses in-flight requests (TODO #843); for ModalLock consumers that means the player waits forever. SimulationPlugin spawns 4 live stub threads every session (simulation/mod.rs:85-87) for Phase-5+ functionality.
|
||
Do now: correct the doc claim; unit tests (spawn/push/poll/shutdown + worker-panic). Before any ModalLock consumer ships (Phase 5): heartbeat/re-enqueue or downgrade ModalLock to an error path. Optional: defer thread spawn until a real handler registers.', 'done', 'medium', NULL, 'server', NULL, '2026-06-12 10:40:59', '2026-06-12 14:24:13', NULL, '421cda003bf656ccaf5eb3314ce20e5f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXS5YZ04F4CPPYNZS4Z2W', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Docs-drift sweep: one-generator reality, dead check-protocol target, DEVOPS hook sections, project.yaml version, stale code comments', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-11, S-15, S-16, S-25, S-26, S-39; S-15/S-16 adversarially verified).
|
||
1. S-15: docs/DEVOPS.md:211-230 documents three generators, .claude/rules/asset-pipeline.md:22,27,36 documents two with a literal command for a file that does not exist (tooling/planet-gen/generate_atlas.py, retired #951/D-223); truth is one (import_economics — Makefile:334-352, stamp registry). Fix both + the CLAUDE.md asset-pipeline snippet.
|
||
2. S-16: delete make check-protocol (Makefile:123-130 greps constants deleted under D-192 via T-874/T-875 — empty==empty always passes); drop from build dep (:132) and help (:42).
|
||
3. S-25: rewrite DEVOPS.md hook/config sections from current sources (pre-push table omits cargo test/deny/clerk + advisory gdlint status; .config/ description never materialized; pre-commit row omits pql validate/export).
|
||
4. S-26: project.yaml says version 0.2.0 under the 0.{phase}.{n} scheme with Phase 4 active, and its description still narrates the v0.1 Sova slice — bump to 0.4.n (or document the bump trigger) + refresh description.
|
||
5. S-39: update voxel.rs module doc (:41-48) and MorphologyFamily variant comments (:256-280) still claiming 7 families are unimplemented stubs (T-1029 landed them all); fix cascade.rs:219 TODO citing closed T-1028 (now tracked by T-1044).
|
||
6. S-11: comment sweep — main.rs:126-127 claims a protocol_version handshake that D-192 removed; npc/relationships.rs:92 TODO(v0.2); chunk_streaming.rs:6,21-22 v0.3+ — rephrase version targets as phase numbers.', 'done', 'medium', NULL, NULL, NULL, '2026-06-12 10:40:59', '2026-06-12 14:24:13', NULL, '4548675a40046129ac1e777897cf048c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY9FV0S9RE42WY7SHW', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_audio_sprint13: 1 failure — AudioManager.clear_dip or API drift', '1 failing test case in test_audio_sprint13.gd. before_test calls AudioManager.clear_dip(), stop_all_loops(), set_volume() for all buses. If any of these methods were renamed or a bus constant changed, setup would fail and cascade. Or a specific dip timing assertion is stale. Run --filter test_audio_sprint13 and read the specific failure. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'done', 'low', NULL, 'client', NULL, '2026-05-02 08:12:56', '2026-06-12 14:24:13', NULL, '58bb6cfac08544d0a96eaae91c406d08', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYF23MZ86S1XF1542G', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_fog_shader: 1 failure — stale VIS_PERIPHERAL or peripheral sector assertion', '1 failing test case in test_fog_shader.gd. The most likely failure is test_fog_state_forward_vs_peripheral: it asserts Forward > Peripheral visibility values, but Sprint 22 (#569) removed peripheral sector. Now all visible tiles write VIS_FORWARD regardless. The test checks the texture is non-null (not the actual byte values), so it should pass... unless the failure is in test_fog_state_exploration_persists which has a weak assertion. Run --filter test_fog_shader to identify the specific failure. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'done', 'low', NULL, 'client', NULL, '2026-05-02 08:12:45', '2026-06-12 14:24:13', NULL, '5eeeb091debddf431862f81740099d6c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXN360AQN3973AHS8M', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_dialogue_sprint20: 5 failures — AudioManager.get_active_dip or other API drift', '5 failing test cases in test_dialogue_sprint20.gd. The suite tests D-020 signal decoupling for dialogue_box. Likely failure: test_show_dialogue_does_not_call_audio_manager_directly compares AudioManager.get_active_dip() before/after show_dialogue — if AudioManager.get_active_dip() behavior changed or is not returning clean state, this would fail. Investigate by running the suite in isolation and reading specific assertion failures from the log. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'done', 'low', NULL, 'client', NULL, '2026-05-02 08:11:54', '2026-06-12 14:24:13', NULL, '685c10050d6fe1d0ecb1a28704329b78', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXSA4WFXPD21YK7N8SF60', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Fix 2,131 broken heightmap.png body-page links — conditional scaffold link + regenerate', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-53; counts independently reproduced by verifier).
|
||
The body-page scaffold links  for all non-gas-giant bodies (scaffold_bodies.py:94-96) but heightmaps exist for only 267 bodies (vs 2,398 reliefmap.png / 3,256 globe.png) — 2,131 of the wiki''s 2,180 broken links are this one pattern, rendered as dead images in the implant wiki view. Fix: make the link conditional in the scaffold and regenerate the Visual section of body pages (or backfill heightmaps where Phase 4 wants them anyway — they are a generation input).', 'done', 'medium', NULL, 'content', NULL, '2026-06-12 10:40:59', '2026-06-12 14:24:13', NULL, '6a30b027e23ed98f9d7e0ccd9b664723', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWBJ1XC9V5ZQHSXAXG', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'Rewrite P2-U01 monologue_display_visible_hidden test against current _visible array API', 'test_monologue_display_visible_hidden in test_client_p2.gd accessed mono.is_visible (a custom bool property). MonologueDisplay was refactored to use _visible: Array[Dictionary] instead. Test skipped (skip_test_) pending rewrite. New test should check _visible.size() > 0 after show_monologue, and == 0 when idle.
|
||
|
||
Re-homed under maintenance (test debt) per cascade refocus 2026-06-12.', 'done', 'low', NULL, 'client', NULL, '2026-04-20 11:17:20', '2026-06-12 14:24:13', NULL, '6a59644e3381f650c86065fe1b1acdac', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXS18RSVRHC7Y9TAX06HG', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Client hygiene batch: orphan .gd.uid files, time_display removal rider, _format_pop dedupe, skip_test_ triage', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-21, S-22, S-24; low severity — spot-check citations at pickup).
|
||
1. S-21 now: delete 7 tracked orphan .gd.uid files whose scripts are gone (client/scripts/rendering/fog_renderer.gd.uid; client/ui/{bug_report_dialog,character_select,debug_console,loading_screen,main_menu,settings_dialog}.gd.uid). Phase-5 rider: remove time_display.gd/.tscn + its 199-line test (superseded by the merged HUD row per hud.gd:4 / #786) with the Phase-5 rendering pass, not before (D-166).
|
||
2. S-22: deduplicate _format_pop — byte-identical 12-line implementations in planet_screen.gd:105-116 and system_screen.gd:685-696 (plus _format_radius) into a shared atlas helper.
|
||
3. S-24: triage the 9 permanently disabled skip_test_ functions (test_sprint2_proof.gd:117,147,169; test_etalk_overlay_sprint17.gd:267-273; test_client_p2.gd:70,100,198) — re-enable, delete, or attach a T-id; convert the push_warning-then-return soft-skip pattern (test_fog_shader, test_audio_sprint13, test_monologue_display, test_input_roundtrip:54) to gdUnit4 skip reporting so missing prerequisites are visible in the JSON summary, not silently green.', 'done', 'low', NULL, 'client', NULL, '2026-06-12 10:40:59', '2026-06-12 14:24:13', NULL, '73d265bc988be13a8f9e8966046da0b3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRG23G1RAREVHQJ14BWC', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Server hygiene batch: exemption contracts, dead deps, generator_spike quarantine, save/load ordering, economy.rs tests', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-06, S-07, S-08, S-09, S-12; low severity — spot-check citations at pickup).
|
||
1. S-06: add the consumer contract ("every consumer must sort before state/wire use") to the three perception disallowed-types allows (shadowcast.rs:17, query.rs:11, interpretation.rs:9).
|
||
2. S-07: delete unused bytemuck (Cargo.toml:30, zero references); fix the stale rayon comment (says "not yet called"; used in atlas/gen_queue.rs:192-228).
|
||
3. S-08: delete or feature-gate bin/generator_spike.rs (1,153 lines reimplementing npc/generate.rs outside ECS, 3 TODO(integration) duplication admissions); extract the shared surname corpus copied between generate_brands/names.rs and generate_corporations/names.rs (already drifted; both feed the systems.db stamp); prune or justify the 24 allow(dead_code) in generate_corporations.
|
||
4. S-09: pin execute_save_load with a lower-bound constraint (currently only .before(compute_observer_snapshot), simulation/mod.rs:106-114 — the scheduler may legally run it before Input, changing what a save captures); note the exclusive-system exception in tick_phases.rs rules.
|
||
5. S-12: unit tests for simulation/economy.rs signal derivation (382 lines, no cfg(test); fixtures set economy_snapshot: None) — trend windowing, first-tick baseline, zero-demand stockpile edge.', 'done', 'low', NULL, 'server', NULL, '2026-06-12 10:40:59', '2026-06-12 14:24:13', NULL, '8e130e0192f8605fdb3e8275fa381bb9', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXMVYQJV2QDHH8H7P8', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_input_roundtrip: 3 failures — server binary missing or LocalBridge API change', '3 failing test cases in test_input_roundtrip.gd. All tests check _connect_to_server() which skips if server binary not found — but 3 still fail, suggesting either: (1) server binary is present but something in LocalBridge.send_message, poll, or Protocol.encode_player_inputs changed, or (2) test environment returns false from _connect_to_server but then asserts fail. Investigate by running with --filter test_input_roundtrip and checking the log for exact assertion sites. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'done', 'low', NULL, 'client', NULL, '2026-05-02 08:11:59', '2026-06-12 14:24:13', NULL, 'cce44aef574862d52ade93a9c79a742a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYEM4VSX74MS4NKQ1C', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'Client test suite — pre-existing failures under bare run-godot', 'Surfaced 2026-05-24 running the full client suite (tests/run-godot, no server) during #960. NOT caused by #960 — verified: test_input_roundtrip fails identically at the pre-change baseline, and the rest are unrelated subsystems. Two categories to triage:
|
||
|
||
CATEGORY 1 — server-dependent (expected-fail under bare run-godot): test_e2e_connection (test_send_input_receive_snapshot), test_input_roundtrip (movement/interact/move_then_interact). They error with ''Nil snapshot'' / ''.tick on Nil'' because no sim server is spawned. They need the run-ipc-* harness or SR_LIVE=1. FIX OPTIONS: gate/skip these under bare run-godot (mark as requiring a server) OR have run-godot spawn the server for the e2e tier, so tests/run-godot
|
||
{"suite":"godot","total":2522,"passed":2482,"failed":40,"duration_ms":96836,"log":"/tmp/sr-run-godot.1737738.log"} is green without false negatives.
|
||
|
||
CATEGORY 2 — genuine logic failures in subsystems unrelated to current work: test_audio_sprint13 (test_d067_chime_duration_spec_is_300_to_400ms, line 547 ''Expecting true but is false''), test_fog_sprint22 (exploration_data_preserved_across_resize), test_fog_shader (visibility_texture_update_performance), test_dialogue_sprint18/20 (signal/audio-dip), test_monologue_display (queue_never_exceeds_max_depth), test_implant_app_lifecycle (on_insert_deactivated_closes_insert_app), test_ai_dialogue_sprint26 (settings_dialog warning label). Triage each: fix or remove/xfail with a reason.
|
||
|
||
Goal: a green (or explicitly-gated) bare `make test-client` so client regressions are detectable. Until then, run targeted suites (run-godot --filter <stem>).
|
||
|
||
Re-homed under maintenance (test-failure debt / suite hygiene) per cascade refocus 2026-06-12.', 'done', 'medium', NULL, 'client', NULL, '2026-05-24 16:49:54', '2026-06-12 14:24:13', NULL, 'cf14f5c5f7a5fc560570f960550eb38f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZYDBRV5T9QVQAXGV0', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_e2e_connection: 1 failure — server binary path or TCP connection state', '1 failing test case in test_e2e_connection.gd. test_send_input_receive_snapshot skips if server binary not found. If it fails, either: (1) server binary exists but connection fails (port collision, timing), or (2) LocalBridge.reset() method was removed (the test calls _bridge.reset() but this may not exist on LocalBridge). Verify LocalBridge has a reset() method. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.', 'done', 'low', NULL, 'client', NULL, '2026-05-02 08:12:51', '2026-06-12 14:24:13', NULL, 'd89fc4e5d05c47ae07446c602f85434a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXSEC1F0RKJVH7JVPS8NW', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Wiki sweep: real link breaks, stale nav surfaces, GOVERNANCE/template reconcile, Sol legacy markers, triangles index', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-54, S-55, S-56, S-59; S-54/S-55/S-56 adversarially verified, S-59 agent-reported).
|
||
1. S-54 (~26 real breaks): knowledge/→concepts/ rename leftovers (3 contraband files, triangles/hub-power.md:420, authoring/monologue-guide.md ×7); pre-governance decisions/ anchors (monologue-guide.md:834-836); 9 phantom companion-system links in star-systems/catalog.md (index.md handles the same companions correctly as unlinked text); factions/cygni-b-combines.md absent (linked from stalownia-kowalski.md:111); concepts/entity-attributes.md:280 wrong relative path to an existing doc.
|
||
2. S-55: wiki/index.md:12 claims "10 fully written" vs ~301 reality; corporations/index.md links 38/155 (117 orphaned); zero nav link to economics/ (39 md + 20 TOML, the primary generator source); 25 station-level gttr-*.md orphaned from their system pages. Regenerate counts from the catalog (or let wiki_sync own them); autogenerate the corp index from frontmatter.
|
||
3. S-56: wiki/GOVERNANCE.md:39-54 prescribes a star-systems/{system}/{station}/{district} hand-authored tree that has zero instances, and _templates/star-system.md:1-18 mandates frontmatter that 0/302 system pages have — rewrite both to the generated model (wiki_sync.py: DB owns structured fields, wiki owns prose) or decide system pages should carry frontmatter and have wiki_sync emit it.
|
||
4. S-59: convert the 4 pre-D-223 geometry-bearing Sol markers.json (GJ-0 bodies, authored coordinates/populations) to names-only, moving the authored data to the Sol special-case home; add wiki/triangles/index.md or de-link it from wiki/index.md:19.
|
||
Audit wiki survey (verified 2026-06-12):
|
||
# wiki/ directory map
|
||
|
||
| Directory | Files | Format | Machine-readable (feeds DB)? | Completeness |
|
||
|---|---|---|---|---|
|
||
| star-systems/ | 3,262 md + 2,398 json + 5,921 png | md (no frontmatter on system pages; YAML frontmatter on body pages), markers.json, png | YES — body frontmatter (axial_tilt → import_economics.py:1286), markers.json city names (:1451), gttr.md → gttr_hook (populate_gttr_hook.py); system infobox/bodies tables generated FROM systems.db (wiki_sync.py) | 302 system dirs; 301 full prose (Supply Dependency 301, Silence Topic 288, Calibration Note 261); 2,625 body pages all with EMPTY Description; 302 gttr.md + 6 corridor + 24 station GTTRs; heightmap.png only 267 vs globe 3,256/reliefmap 2,398; GJ-280B = sole stub |
|
||
| economics/ | 39 md + 20 toml | TOML (source of truth) + md prose | YES — commodities.toml, production_chains.toml, currency_zones.toml, specialization_vocabulary.toml (27), system_specialization.toml (240/301 pins), architecture_trait_catalog.toml (28 templates) + bias, brands/generated_brands/tier1/tier2 | Complete for current decisions (D-173..D-182, D-232, D-237; T-1016 done); not linked from wiki/index.md |
|
||
| corporations/ | 156 md | md + YAML frontmatter | YES — frontmatter slug/title/headquarters/tags/scope → corporations + corp_presence (import_economics.py:734-790, D-182 wiki-is-truth) | 155 canonical pages ~8-16KB; index.md lists only 38 (117 orphaned from nav) |
|
||
| factions/ | 9 md | md + frontmatter | No (prose; dominant_faction comes from economics TOML) | Complete: 6 major + 1 regional + 1 local worked example, all canonical, clean index |
|
||
| technology/ | 7 md | md | No | Complete (6 entries + index) |
|
||
| contraband/ | 4 md | md + frontmatter | No | Complete (3 entries + index); stale ../knowledge/ links |
|
||
| concepts/ | 4 md | md | No | Complete (fact-catalog, entity-attributes, relationship-states); renamed from knowledge/, inbound links broken |
|
||
| authoring/ | 12 md (incl. npc-patterns/ 3) | md | No (authoring guides) | Complete; monologue-guide has 9 stale links (knowledge/, pre-governance decisions/ paths) |
|
||
| triangles/ | 1 md | md + frontmatter | No | One worked example (hub-power.md); index.md missing (broken link from wiki root) |
|
||
| cultural-groups/ | 0 (.gitkeep) | — | — | EMPTY (template exists) |
|
||
| institutions/ | 0 (.gitkeep) | — | — | EMPTY (template exists; covered under factions/) |
|
||
| lore/ | 0 (.gitkeep) | — | — | EMPTY (template exists) |
|
||
| species/ | 0 (.gitkeep) | — | — | EMPTY (template exists) |
|
||
| _templates/ | 17 md | md | — | Complete but drifted: star-system template ≠ generated reality; station/district/location/cultural-group/species/lore/institution templates have 0 instances |
|
||
| glossary.md / GOVERNANCE.md / index.md | 3 md | md | No | Glossary current (incl. TOML/DB terminology + anti-drift list); GOVERNANCE spatial hierarchy + status lifecycle stale; index.md counts stale (''10 fully written'' vs ~301) |
|
||
|
||
# Star-systems census
|
||
- Systems: 302 dirs (catalog claims 301; 220 named / 81 unnamed); 9 catalog rows link nonexistent companion dirs
|
||
- Bodies: 2,625 body pages (planets, moons, belts, oort clouds; no per-type subdirs — flat bodies/ per system)
|
||
- Stations: 0 wiki pages; rows in systems.db rendered into ''Stations & Facilities'' tables per system index + 24 station GTTR prose files
|
||
- Markers: 2,394 names-only (D-223) + 4 legacy geometry (all GJ-0/Sol)
|
||
|
||
# Generation data flow (verified)
|
||
wiki/economics/*.toml + wiki/corporations/*.md frontmatter + wiki/star-systems body frontmatter + markers.json names → tooling/economy-db/import_economics.py → server/data/systems.db (stamped, tooling/check-systems-db-stamp) → client Atlas (gttr_excerpt popups, reach_screen.gd:178) + direct runtime load of wiki globe.png (system_screen.gd:482-492). wiki_sync.py: DB owns structured fields, wiki owns prose sections.
|
||
|
||
# docs/ health snapshot
|
||
- docs/architecture/ (19): current — pql-migration.md (2026-06-06), atlas-naming-pipeline, implant-app-pattern; historical — sprint-36/37 audits, v01-yaml-content-audit, eval/risk-godot-rust-bridge (2026-03-13)
|
||
- docs/design/ (60+): ~35 files frozen at 2026-02-19→03-14, status:active but v0.1/v0.2-era (wow-moments, first-5-minutes, spatial-layout-*-v01, dueling content-structure docs); still-load-bearing: star-map.json (Topology source), gj-catalog-full.json, planetary-terrain-generation.md, cultural-diversity-audit.md (remediated, T-793 done), sova-station-profile.md (canon for the stub system)', 'done', 'medium', NULL, 'content', NULL, '2026-06-12 10:40:59', '2026-06-12 14:24:13', NULL, 'dc2d82615d6192211a5a2966d2ed31af', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRMET5CBB0ENBZGJQKX0', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Add a client-test gate to pre-push — the 63-file GDScript suite never runs automatically', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-13; citations adversarially verified).
|
||
The pre-push hook is the ONLY automatic correctness gate (its own comment, .config/hooks/pre-push:101-110) and there is no CI — but for client/ changes it runs only a headless parse check (:38-54). The gdUnit4 suite (tests/run-godot: 300s-capped, one-line JSON summary, agent-safe) is invoked only manually. A GDScript regression reaches main unverified, while team-patterns.md claims the gate is "deliberately comprehensive".
|
||
Fix: run tests/run-godot in pre-push when CLIENT_CHANGED > 0 — or record manual-only explicitly and fix team-patterns.md. Related decision: Q-116 (gdlint blocking). Prerequisite worth checking: T-973 (pre-existing bare-run failures, under this initiative) so the new gate starts green.', 'done', 'high', NULL, 'client', NULL, '2026-06-12 10:40:59', '2026-06-12 14:24:13', NULL, 'efbf589cb639a0051ce67141c64f8b23', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYEM4VSX74MS4NKQ1C', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'Client test suite — pre-existing failures under bare run-godot', 'Surfaced 2026-05-24 running the full client suite (tests/run-godot, no server) during #960. NOT caused by #960 — verified: test_input_roundtrip fails identically at the pre-change baseline, and the rest are unrelated subsystems. Two categories to triage:
|
||
|
||
CATEGORY 1 — server-dependent (expected-fail under bare run-godot): test_e2e_connection (test_send_input_receive_snapshot), test_input_roundtrip (movement/interact/move_then_interact). They error with ''Nil snapshot'' / ''.tick on Nil'' because no sim server is spawned. They need the run-ipc-* harness or SR_LIVE=1. FIX OPTIONS: gate/skip these under bare run-godot (mark as requiring a server) OR have run-godot spawn the server for the e2e tier, so tests/run-godot
|
||
{"suite":"godot","total":2522,"passed":2482,"failed":40,"duration_ms":96836,"log":"/tmp/sr-run-godot.1737738.log"} is green without false negatives.
|
||
|
||
CATEGORY 2 — genuine logic failures in subsystems unrelated to current work: test_audio_sprint13 (test_d067_chime_duration_spec_is_300_to_400ms, line 547 ''Expecting true but is false''), test_fog_sprint22 (exploration_data_preserved_across_resize), test_fog_shader (visibility_texture_update_performance), test_dialogue_sprint18/20 (signal/audio-dip), test_monologue_display (queue_never_exceeds_max_depth), test_implant_app_lifecycle (on_insert_deactivated_closes_insert_app), test_ai_dialogue_sprint26 (settings_dialog warning label). Triage each: fix or remove/xfail with a reason.
|
||
|
||
Goal: a green (or explicitly-gated) bare `make test-client` so client regressions are detectable. Until then, run targeted suites (run-godot --filter <stem>).
|
||
|
||
Re-homed under maintenance (test-failure debt / suite hygiene) per cascade refocus 2026-06-12.
|
||
|
||
Closed 2026-06-12 (commit c64231e8e): bare tests/run-godot fully green — 1264 cases/20 failures → 1268/0, independently re-verified by the lead (2536/2536, exit 0). Two production bugs found and fixed during triage (hud_groups freed-instance crash; fog_state D-059 decay loss across resize). The push gate now runs the suite (T-1065).', 'done', 'medium', NULL, 'client', NULL, '2026-05-24 16:49:54', '2026-06-12 14:24:13', NULL, '5cae4085d79e53d34fa914d3f0e7fa98', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXN360AQN3973AHS8M', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_dialogue_sprint20: 5 failures — AudioManager.get_active_dip or other API drift', '5 failing test cases in test_dialogue_sprint20.gd. The suite tests D-020 signal decoupling for dialogue_box. Likely failure: test_show_dialogue_does_not_call_audio_manager_directly compares AudioManager.get_active_dip() before/after show_dialogue — if AudioManager.get_active_dip() behavior changed or is not returning clean state, this would fail. Investigate by running the suite in isolation and reading specific assertion failures from the log. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.
|
||
|
||
Closed: production was correct — 5 tests captured lambda locals by value (GDScript) so signal flags never propagated; rewritten with array captures asserting exact emission counts + payloads (stronger). Commit c64231e8e.', 'done', 'low', NULL, 'client', NULL, '2026-05-02 08:11:54', '2026-06-12 14:24:13', NULL, 'd33925296302cc2da96933ba65c1e490', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXMVYQJV2QDHH8H7P8', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_input_roundtrip: 3 failures — server binary missing or LocalBridge API change', '3 failing test cases in test_input_roundtrip.gd. All tests check _connect_to_server() which skips if server binary not found — but 3 still fail, suggesting either: (1) server binary is present but something in LocalBridge.send_message, poll, or Protocol.encode_player_inputs changed, or (2) test environment returns false from _connect_to_server but then asserts fail. Investigate by running with --filter test_input_roundtrip and checking the log for exact assertion sites. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.
|
||
|
||
Closed: protocol drift (#555 handshake + #175 StartupMessage, then 20tps streamed snapshots); tests now do the real exchange and wait on deterministic positions. Genuinely runs against the live binary. Commit c64231e8e.', 'done', 'low', NULL, 'client', NULL, '2026-05-02 08:11:59', '2026-06-12 14:24:13', NULL, '7aa3f6ad70d133d223ff979b8026570b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY3TXD5HDKHFVGDG18', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_implant_app_lifecycle: 1 failure — ImplantApp or HudGroups state API', '1 failing test case in test_implant_app_lifecycle.gd. Suite tests ImplantApp._internal_app_changed, nav stack, preserves_state, and HudGroups state. after_test resets HudGroups._active_app, _active_mode, _groups — if these private fields were renamed or removed, after_test would fail and bleed state. Or a specific on_open/on_close hook fires differently. Run --filter test_implant_app_lifecycle and check specific assertion. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.
|
||
|
||
Closed: real production bug — hud_groups._set_group_z typed loop var errors on freed instances before the guard runs; prune-then-iterate fix (self-pruning registry). Commit c64231e8e.', 'done', 'low', NULL, 'client', NULL, '2026-05-02 08:12:32', '2026-06-12 14:24:13', NULL, '190990cad19d2308e6ba801bfe58c901', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWK87PCWGZ6GWT2TBM', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_game_state_sprint20: 1 failure — SnapshotHandler or stationary_ticks path', '1 failing test case in test_game_state_sprint20.gd. before_each resets SnapshotHandler._prev_player_position. If this static var was renamed or moved, the before_each hook would error. Alternatively a stationary_ticks path changed in SnapshotHandler. Verify SnapshotHandler still has static var _prev_player_position at that exact name. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.
|
||
|
||
Closed: no repro — already fixed on main by 702fed592 (before_each → before_test hook name); verified 9/9 in baseline. No change needed.', 'done', 'low', NULL, 'client', NULL, '2026-05-02 08:12:38', '2026-06-12 14:24:13', NULL, 'e02247ba88e17bad5762d30abacf1046', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYF23MZ86S1XF1542G', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_fog_shader: 1 failure — stale VIS_PERIPHERAL or peripheral sector assertion', '1 failing test case in test_fog_shader.gd. The most likely failure is test_fog_state_forward_vs_peripheral: it asserts Forward > Peripheral visibility values, but Sprint 22 (#569) removed peripheral sector. Now all visible tiles write VIS_FORWARD regardless. The test checks the texture is non-null (not the actual byte values), so it should pass... unless the failure is in test_fog_state_exploration_persists which has a weak assertion. Run --filter test_fog_shader to identify the specific failure. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.
|
||
|
||
Closed: failing case was the perf test measuring the first call (includes the one-off grow-only resize); now warms up and measures steady state against the same 0.5ms budget. Stale Peripheral vocabulary removed. Commit c64231e8e.', 'done', 'low', NULL, 'client', NULL, '2026-05-02 08:12:45', '2026-06-12 14:24:13', NULL, 'ba24b7a9d5531069ecbfc42d56fbbbb2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZYDBRV5T9QVQAXGV0', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_e2e_connection: 1 failure — server binary path or TCP connection state', '1 failing test case in test_e2e_connection.gd. test_send_input_receive_snapshot skips if server binary not found. If it fails, either: (1) server binary exists but connection fails (port collision, timing), or (2) LocalBridge.reset() method was removed (the test calls _bridge.reset() but this may not exist on LocalBridge). Verify LocalBridge has a reset() method. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.
|
||
|
||
Closed: same protocol drift as T-929; handshake added, binary-absence is a real skip. LocalBridge.reset() suspicion was wrong. Commit c64231e8e.', 'done', 'low', NULL, 'client', NULL, '2026-05-02 08:12:51', '2026-06-12 14:24:13', NULL, 'cdbecae3a8cf391768c63bdf52cee076', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRY9FV0S9RE42WY7SHW', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_audio_sprint13: 1 failure — AudioManager.clear_dip or API drift', '1 failing test case in test_audio_sprint13.gd. before_test calls AudioManager.clear_dip(), stop_all_loops(), set_volume() for all buses. If any of these methods were renamed or a bus constant changed, setup would fail and cascade. Or a specific dip timing assertion is stale. Run --filter test_audio_sprint13 and read the specific failure. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.
|
||
|
||
Closed: clear_dip was fine; the chime test asserted D-067 prose (300-400ms) against the deliberately shipped 800ms asset (#327, ui.md UI-005). Test pins the catalog; D-067 amended 2026-06-12 with the 800ms reality. Commit c64231e8e.', 'done', 'low', NULL, 'client', NULL, '2026-05-02 08:12:56', '2026-06-12 14:24:13', NULL, '8169d7f755c8212091f806f66c3412c0', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXCE9D9JYBZWVXMG68', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'test_ai_dialogue_sprint26: 1 failure — HardwareDetector autoload missing or settings_dialog API', '1 failing test case in test_ai_dialogue_sprint26.gd. The HardwareDetector tests skip if autoload not found. The GameState field tests (ai_enhanced_dialogue_enabled) look correct. The failing test is likely in the settings_dialog section: SETTINGS_DIALOG_SCENE preloaded at class level — if settings_dialog.tscn doesn''t exist or a method was renamed, class-level preload would fail. Check res://ui/settings_dialog.tscn exists and the relevant methods. Sprint 38 triage #871.
|
||
|
||
Re-homed under maintenance from done umbrella T-871 per cascade refocus 2026-06-12.
|
||
|
||
Closed: MetaScreen migration (f24d08f75) moved UI build to on_open(); tests now open the dialog first; vacuous null-label pass eliminated. Commit c64231e8e.', 'done', 'low', NULL, 'client', NULL, '2026-05-02 08:13:02', '2026-06-12 14:24:13', NULL, 'af9bf10870202ff86c14fca1e1fda302', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWBJ1XC9V5ZQHSXAXG', 'bug', '06FBPPMZNNEV052DBYYY3A897C', 'Rewrite P2-U01 monologue_display_visible_hidden test against current _visible array API', 'test_monologue_display_visible_hidden in test_client_p2.gd accessed mono.is_visible (a custom bool property). MonologueDisplay was refactored to use _visible: Array[Dictionary] instead. Test skipped (skip_test_) pending rewrite. New test should check _visible.size() > 0 after show_monologue, and == 0 when idle.
|
||
|
||
Re-homed under maintenance (test debt) per cascade refocus 2026-06-12.
|
||
|
||
Closed: P2-U01 rewritten against the _visible array API + rendered-text assert (stronger than spec); re-enabled. Commit c64231e8e.', 'done', 'low', NULL, 'client', NULL, '2026-04-20 11:17:20', '2026-06-12 14:24:13', NULL, '0be8808e187f4eadce7f345b43bb84e7', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXS18RSVRHC7Y9TAX06HG', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Client hygiene batch: orphan .gd.uid files, time_display removal rider, _format_pop dedupe, skip_test_ triage', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-21, S-22, S-24; low severity — spot-check citations at pickup).
|
||
1. S-21 now: delete 7 tracked orphan .gd.uid files whose scripts are gone (client/scripts/rendering/fog_renderer.gd.uid; client/ui/{bug_report_dialog,character_select,debug_console,loading_screen,main_menu,settings_dialog}.gd.uid). Phase-5 rider: remove time_display.gd/.tscn + its 199-line test (superseded by the merged HUD row per hud.gd:4 / #786) with the Phase-5 rendering pass, not before (D-166).
|
||
2. S-22: deduplicate _format_pop — byte-identical 12-line implementations in planet_screen.gd:105-116 and system_screen.gd:685-696 (plus _format_radius) into a shared atlas helper.
|
||
3. S-24: triage the 9 permanently disabled skip_test_ functions (test_sprint2_proof.gd:117,147,169; test_etalk_overlay_sprint17.gd:267-273; test_client_p2.gd:70,100,198) — re-enable, delete, or attach a T-id; convert the push_warning-then-return soft-skip pattern (test_fog_shader, test_audio_sprint13, test_monologue_display, test_input_roundtrip:54) to gdUnit4 skip reporting so missing prerequisites are visible in the JSON summary, not silently green.
|
||
|
||
Closed: 7 orphan uids deleted; _format_pop/_format_radius deduped into atlas_format.gd (preload, headless-safe); skip_test triage — 3 sprint2 proofs revived (corner_reveal had passed from the wrong tile; NPC blocking documented), 5 dead stubs deleted, soft-skips converted to do_skip. time_display untouched per the Phase-5 rider. Commit c64231e8e.', 'done', 'low', NULL, 'client', NULL, '2026-06-12 10:40:59', '2026-06-12 14:24:13', NULL, 'a4c713b6c290062636d25fef0826215f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRBRFW4MH5G8C0X12YGR', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Workers pool: add tests, fix panic-loss, correct the false "tested" doc claim', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-05; verified — zero tests exist for BackgroundWorkerPool anywhere).
|
||
workers/stubs.rs:7 claims the pool infrastructure is "real and tested" — false. pool.rs:8-13 documents that a worker-thread panic silently loses in-flight requests (TODO #843); for ModalLock consumers that means the player waits forever. SimulationPlugin spawns 4 live stub threads every session (simulation/mod.rs:85-87) for Phase-5+ functionality.
|
||
Do now: correct the doc claim; unit tests (spawn/push/poll/shutdown + worker-panic). Before any ModalLock consumer ships (Phase 5): heartbeat/re-enqueue or downgrade ModalLock to an error path. Optional: defer thread spawn until a real handler registers.
|
||
|
||
Closed (commit 0bd895fca): false tested claim corrected; 5 pool tests incl. two panic tests; catch_unwind keeps worker threads alive on handler panic (small-fix clause) — in-flight loss remains the documented #843 limitation, pinned by test. Heartbeat/re-enqueue stays future work.', 'done', 'medium', NULL, 'server', NULL, '2026-06-12 10:40:59', '2026-06-12 14:24:13', NULL, '89bf7f1ffb9f7037e21c25b695295b72', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRG23G1RAREVHQJ14BWC', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Server hygiene batch: exemption contracts, dead deps, generator_spike quarantine, save/load ordering, economy.rs tests', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-06, S-07, S-08, S-09, S-12; low severity — spot-check citations at pickup).
|
||
1. S-06: add the consumer contract ("every consumer must sort before state/wire use") to the three perception disallowed-types allows (shadowcast.rs:17, query.rs:11, interpretation.rs:9).
|
||
2. S-07: delete unused bytemuck (Cargo.toml:30, zero references); fix the stale rayon comment (says "not yet called"; used in atlas/gen_queue.rs:192-228).
|
||
3. S-08: delete or feature-gate bin/generator_spike.rs (1,153 lines reimplementing npc/generate.rs outside ECS, 3 TODO(integration) duplication admissions); extract the shared surname corpus copied between generate_brands/names.rs and generate_corporations/names.rs (already drifted; both feed the systems.db stamp); prune or justify the 24 allow(dead_code) in generate_corporations.
|
||
4. S-09: pin execute_save_load with a lower-bound constraint (currently only .before(compute_observer_snapshot), simulation/mod.rs:106-114 — the scheduler may legally run it before Input, changing what a save captures); note the exclusive-system exception in tick_phases.rs rules.
|
||
5. S-12: unit tests for simulation/economy.rs signal derivation (382 lines, no cfg(test); fixtures set economy_snapshot: None) — trend windowing, first-tick baseline, zero-demand stockpile edge.
|
||
|
||
Closed (commit 0bd895fca): all 5 items. Notable: surname corpora were element-identical (audit drift claim wrong) — dedup verified byte-identical output; generator_spike feature-gated (kept, reversible); the 22 allow(dead_code) documented as serde schema enforcement rather than pruned; save pinned .after(Storyteller); 11 economy signal tests on the new Simulation::from_economy. Stamp refreshed via regen-db (eadbc5b24).', 'done', 'low', NULL, 'server', NULL, '2026-06-12 10:40:59', '2026-06-12 14:24:14', NULL, 'cd2623b4c501079e3630ec97501d238b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRRDGJ5GFPGHZV3WS0D0', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Wire tooling tests into a gate: make test-tooling + pre-push on tooling changes', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-18; citations adversarially verified).
|
||
22,340 lines of tooling Python (including the systems.db generator) are verified only by a 4-rule ruff subset (pyproject.toml:26-31: E9/F401/F811/F821); zero pytest anywhere; the one real test (tooling/planet-gen/test_sim_determinism.py, guarding the expensive 271-body bake, exit codes 0/1/2) is wired into nothing.
|
||
Fix: make test-tooling = test_sim_determinism.py + import_economics --dry-run against the committed DB; call from pre-push when TOOLING_CHANGED > 0; widen the ruff selection.
|
||
|
||
Closed (commit 346d87df7): make test-tooling (determinism guard + dry-run, exit-2 warn semantics) wired into pre-push on TOOLING_CHANGED; ruff widened to E4/E7/E9/F/W with 90 auto-fixes and 3 documented ignores (E402/E702/F841).', 'done', 'medium', NULL, NULL, NULL, '2026-06-12 10:40:59', '2026-06-12 14:24:14', NULL, '93088a593d8f0569b8281c98669f7c4f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXS5YZ04F4CPPYNZS4Z2W', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Docs-drift sweep: one-generator reality, dead check-protocol target, DEVOPS hook sections, project.yaml version, stale code comments', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-11, S-15, S-16, S-25, S-26, S-39; S-15/S-16 adversarially verified).
|
||
1. S-15: docs/DEVOPS.md:211-230 documents three generators, .claude/rules/asset-pipeline.md:22,27,36 documents two with a literal command for a file that does not exist (tooling/planet-gen/generate_atlas.py, retired #951/D-223); truth is one (import_economics — Makefile:334-352, stamp registry). Fix both + the CLAUDE.md asset-pipeline snippet.
|
||
2. S-16: delete make check-protocol (Makefile:123-130 greps constants deleted under D-192 via T-874/T-875 — empty==empty always passes); drop from build dep (:132) and help (:42).
|
||
3. S-25: rewrite DEVOPS.md hook/config sections from current sources (pre-push table omits cargo test/deny/clerk + advisory gdlint status; .config/ description never materialized; pre-commit row omits pql validate/export).
|
||
4. S-26: project.yaml says version 0.2.0 under the 0.{phase}.{n} scheme with Phase 4 active, and its description still narrates the v0.1 Sova slice — bump to 0.4.n (or document the bump trigger) + refresh description.
|
||
5. S-39: update voxel.rs module doc (:41-48) and MorphologyFamily variant comments (:256-280) still claiming 7 families are unimplemented stubs (T-1029 landed them all); fix cascade.rs:219 TODO citing closed T-1028 (now tracked by T-1044).
|
||
6. S-11: comment sweep — main.rs:126-127 claims a protocol_version handshake that D-192 removed; npc/relationships.rs:92 TODO(v0.2); chunk_streaming.rs:6,21-22 v0.3+ — rephrase version targets as phase numbers.
|
||
|
||
Closed (commit 346d87df7): all 6 drift items — one-generator docs, check-protocol deleted, DEVOPS hook sections from source, project.yaml 0.4.0 + description, voxel/cascade/main/relationships/chunk_streaming comment fixes.', 'done', 'medium', NULL, NULL, NULL, '2026-06-12 10:40:59', '2026-06-12 14:24:14', NULL, '59a9ceb2670b62c55edb079fcf586531', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXSA4WFXPD21YK7N8SF60', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Fix 2,131 broken heightmap.png body-page links — conditional scaffold link + regenerate', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-53; counts independently reproduced by verifier).
|
||
The body-page scaffold links  for all non-gas-giant bodies (scaffold_bodies.py:94-96) but heightmaps exist for only 267 bodies (vs 2,398 reliefmap.png / 3,256 globe.png) — 2,131 of the wiki''s 2,180 broken links are this one pattern, rendered as dead images in the implant wiki view. Fix: make the link conditional in the scaffold and regenerate the Visual section of body pages (or backfill heightmaps where Phase 4 wants them anyway — they are a generation input).
|
||
|
||
Closed (commit b4919c659): scaffold link conditional on the bake criteria; 2,131 dead image lines surgically removed (267 with the file kept). Broken links 2,180 → 49 from this ticket alone.', 'done', 'medium', NULL, 'content', NULL, '2026-06-12 10:40:59', '2026-06-12 14:24:14', NULL, 'a20d47cfe2a9fc5ff09b8bc8039491d3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXSEC1F0RKJVH7JVPS8NW', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Wiki sweep: real link breaks, stale nav surfaces, GOVERNANCE/template reconcile, Sol legacy markers, triangles index', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-54, S-55, S-56, S-59; S-54/S-55/S-56 adversarially verified, S-59 agent-reported).
|
||
1. S-54 (~26 real breaks): knowledge/→concepts/ rename leftovers (3 contraband files, triangles/hub-power.md:420, authoring/monologue-guide.md ×7); pre-governance decisions/ anchors (monologue-guide.md:834-836); 9 phantom companion-system links in star-systems/catalog.md (index.md handles the same companions correctly as unlinked text); factions/cygni-b-combines.md absent (linked from stalownia-kowalski.md:111); concepts/entity-attributes.md:280 wrong relative path to an existing doc.
|
||
2. S-55: wiki/index.md:12 claims "10 fully written" vs ~301 reality; corporations/index.md links 38/155 (117 orphaned); zero nav link to economics/ (39 md + 20 TOML, the primary generator source); 25 station-level gttr-*.md orphaned from their system pages. Regenerate counts from the catalog (or let wiki_sync own them); autogenerate the corp index from frontmatter.
|
||
3. S-56: wiki/GOVERNANCE.md:39-54 prescribes a star-systems/{system}/{station}/{district} hand-authored tree that has zero instances, and _templates/star-system.md:1-18 mandates frontmatter that 0/302 system pages have — rewrite both to the generated model (wiki_sync.py: DB owns structured fields, wiki owns prose) or decide system pages should carry frontmatter and have wiki_sync emit it.
|
||
4. S-59: convert the 4 pre-D-223 geometry-bearing Sol markers.json (GJ-0 bodies, authored coordinates/populations) to names-only, moving the authored data to the Sol special-case home; add wiki/triangles/index.md or de-link it from wiki/index.md:19.
|
||
Audit wiki survey (verified 2026-06-12):
|
||
# wiki/ directory map
|
||
|
||
| Directory | Files | Format | Machine-readable (feeds DB)? | Completeness |
|
||
|---|---|---|---|---|
|
||
| star-systems/ | 3,262 md + 2,398 json + 5,921 png | md (no frontmatter on system pages; YAML frontmatter on body pages), markers.json, png | YES — body frontmatter (axial_tilt → import_economics.py:1286), markers.json city names (:1451), gttr.md → gttr_hook (populate_gttr_hook.py); system infobox/bodies tables generated FROM systems.db (wiki_sync.py) | 302 system dirs; 301 full prose (Supply Dependency 301, Silence Topic 288, Calibration Note 261); 2,625 body pages all with EMPTY Description; 302 gttr.md + 6 corridor + 24 station GTTRs; heightmap.png only 267 vs globe 3,256/reliefmap 2,398; GJ-280B = sole stub |
|
||
| economics/ | 39 md + 20 toml | TOML (source of truth) + md prose | YES — commodities.toml, production_chains.toml, currency_zones.toml, specialization_vocabulary.toml (27), system_specialization.toml (240/301 pins), architecture_trait_catalog.toml (28 templates) + bias, brands/generated_brands/tier1/tier2 | Complete for current decisions (D-173..D-182, D-232, D-237; T-1016 done); not linked from wiki/index.md |
|
||
| corporations/ | 156 md | md + YAML frontmatter | YES — frontmatter slug/title/headquarters/tags/scope → corporations + corp_presence (import_economics.py:734-790, D-182 wiki-is-truth) | 155 canonical pages ~8-16KB; index.md lists only 38 (117 orphaned from nav) |
|
||
| factions/ | 9 md | md + frontmatter | No (prose; dominant_faction comes from economics TOML) | Complete: 6 major + 1 regional + 1 local worked example, all canonical, clean index |
|
||
| technology/ | 7 md | md | No | Complete (6 entries + index) |
|
||
| contraband/ | 4 md | md + frontmatter | No | Complete (3 entries + index); stale ../knowledge/ links |
|
||
| concepts/ | 4 md | md | No | Complete (fact-catalog, entity-attributes, relationship-states); renamed from knowledge/, inbound links broken |
|
||
| authoring/ | 12 md (incl. npc-patterns/ 3) | md | No (authoring guides) | Complete; monologue-guide has 9 stale links (knowledge/, pre-governance decisions/ paths) |
|
||
| triangles/ | 1 md | md + frontmatter | No | One worked example (hub-power.md); index.md missing (broken link from wiki root) |
|
||
| cultural-groups/ | 0 (.gitkeep) | — | — | EMPTY (template exists) |
|
||
| institutions/ | 0 (.gitkeep) | — | — | EMPTY (template exists; covered under factions/) |
|
||
| lore/ | 0 (.gitkeep) | — | — | EMPTY (template exists) |
|
||
| species/ | 0 (.gitkeep) | — | — | EMPTY (template exists) |
|
||
| _templates/ | 17 md | md | — | Complete but drifted: star-system template ≠ generated reality; station/district/location/cultural-group/species/lore/institution templates have 0 instances |
|
||
| glossary.md / GOVERNANCE.md / index.md | 3 md | md | No | Glossary current (incl. TOML/DB terminology + anti-drift list); GOVERNANCE spatial hierarchy + status lifecycle stale; index.md counts stale (''10 fully written'' vs ~301) |
|
||
|
||
# Star-systems census
|
||
- Systems: 302 dirs (catalog claims 301; 220 named / 81 unnamed); 9 catalog rows link nonexistent companion dirs
|
||
- Bodies: 2,625 body pages (planets, moons, belts, oort clouds; no per-type subdirs — flat bodies/ per system)
|
||
- Stations: 0 wiki pages; rows in systems.db rendered into ''Stations & Facilities'' tables per system index + 24 station GTTR prose files
|
||
- Markers: 2,394 names-only (D-223) + 4 legacy geometry (all GJ-0/Sol)
|
||
|
||
# Generation data flow (verified)
|
||
wiki/economics/*.toml + wiki/corporations/*.md frontmatter + wiki/star-systems body frontmatter + markers.json names → tooling/economy-db/import_economics.py → server/data/systems.db (stamped, tooling/check-systems-db-stamp) → client Atlas (gttr_excerpt popups, reach_screen.gd:178) + direct runtime load of wiki globe.png (system_screen.gd:482-492). wiki_sync.py: DB owns structured fields, wiki owns prose sections.
|
||
|
||
# docs/ health snapshot
|
||
- docs/architecture/ (19): current — pql-migration.md (2026-06-06), atlas-naming-pipeline, implant-app-pattern; historical — sprint-36/37 audits, v01-yaml-content-audit, eval/risk-godot-rust-bridge (2026-03-13)
|
||
- docs/design/ (60+): ~35 files frozen at 2026-02-19→03-14, status:active but v0.1/v0.2-era (wow-moments, first-5-minutes, spatial-layout-*-v01, dueling content-structure docs); still-load-bearing: star-map.json (Topology source), gj-catalog-full.json, planetary-terrain-generation.md, cultural-diversity-audit.md (remediated, T-793 done), sova-station-profile.md (canon for the stub system)
|
||
|
||
Closed (commit b4919c659): 26 link breaks fixed, nav refreshed (index counts, Economics section, corp index regenerated from frontmatter, 25 station GTTRs linked), GOVERNANCE.md + star-system template rewritten to the generated model, triangles/index.md added. Sol markers part SPLIT to T-1073: conversion verified safe for generation but atlas_viewer.gd:433 still renders the legacy geometry — reverted to preserve Sol Atlas overlays; land with the client read-path migration. Residual: 25 intentional _templates placeholders remain.', 'done', 'medium', NULL, 'content', NULL, '2026-06-12 10:40:59', '2026-06-12 14:24:14', NULL, '87c6c991d95b23f7b783a18f423ffd40', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRMET5CBB0ENBZGJQKX0', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Add a client-test gate to pre-push — the 63-file GDScript suite never runs automatically', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-13; citations adversarially verified).
|
||
The pre-push hook is the ONLY automatic correctness gate (its own comment, .config/hooks/pre-push:101-110) and there is no CI — but for client/ changes it runs only a headless parse check (:38-54). The gdUnit4 suite (tests/run-godot: 300s-capped, one-line JSON summary, agent-safe) is invoked only manually. A GDScript regression reaches main unverified, while team-patterns.md claims the gate is "deliberately comprehensive".
|
||
Fix: run tests/run-godot in pre-push when CLIENT_CHANGED > 0 — or record manual-only explicitly and fix team-patterns.md. Related decision: Q-116 (gdlint blocking). Prerequisite worth checking: T-973 (pre-existing bare-run failures, under this initiative) so the new gate starts green.
|
||
|
||
Closed: pre-push now runs tests/run-godot (blocking) when CLIENT_CHANGED > 0 — added after T-973 made the suite green and the lead independently re-verified (2536/2536). team-patterns.md gate description updated. ~100s added to client-touching pushes; e2e suites self-skip without the server binary.', 'done', 'high', NULL, 'client', NULL, '2026-06-12 10:40:59', '2026-06-12 14:24:14', NULL, '1764112ab2704e7782054150a9435eb4', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXR79W28XNN1TB7HKGBP8', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Split the input.rs and dialogue.rs god-module dispatchers', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-03; citations adversarially verified).
|
||
simulation/input.rs: 2,739 lines, imports 9 domains (bookmark, bridge::debug, knowledge, settings, economy, interaction, inventory, movement, save_io), 9× type_complexity allows (:485-1120) + 1 too_many_arguments — the dispatch hub for every player verb. simulation/dialogue.rs: 2,785 lines, 3 allows.
|
||
Extract per-domain input handlers into their owning modules behind a thin dispatch table; split dialogue into talk-selection / confrontation / response-assembly. Mechanical, no behavior change; gate with the existing determinism.rs byte-identical goldens.', 'in_progress', 'medium', NULL, 'server', NULL, '2026-06-12 10:40:59', '2026-06-12 14:39:13', NULL, 'dfb062e89b351f48cb18a684ce5a9531', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXR79W28XNN1TB7HKGBP8', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Split the input.rs and dialogue.rs god-module dispatchers', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-03; citations adversarially verified).
|
||
simulation/input.rs: 2,739 lines, imports 9 domains (bookmark, bridge::debug, knowledge, settings, economy, interaction, inventory, movement, save_io), 9× type_complexity allows (:485-1120) + 1 too_many_arguments — the dispatch hub for every player verb. simulation/dialogue.rs: 2,785 lines, 3 allows.
|
||
Extract per-domain input handlers into their owning modules behind a thin dispatch table; split dialogue into talk-selection / confrontation / response-assembly. Mechanical, no behavior change; gate with the existing determinism.rs byte-identical goldens.', 'done', 'medium', NULL, 'server', NULL, '2026-06-12 10:40:59', '2026-06-12 15:08:41', NULL, '164208c6d48b52df2b61e105518725c2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXR79W28XNN1TB7HKGBP8', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Split the input.rs and dialogue.rs god-module dispatchers', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-03; citations adversarially verified).
|
||
simulation/input.rs: 2,739 lines, imports 9 domains (bookmark, bridge::debug, knowledge, settings, economy, interaction, inventory, movement, save_io), 9× type_complexity allows (:485-1120) + 1 too_many_arguments — the dispatch hub for every player verb. simulation/dialogue.rs: 2,785 lines, 3 allows.
|
||
Extract per-domain input handlers into their owning modules behind a thin dispatch table; split dialogue into talk-selection / confrontation / response-assembly. Mechanical, no behavior change; gate with the existing determinism.rs byte-identical goldens.
|
||
|
||
Closed 2026-06-12, commit 257d979ae. input.rs 2,739→858 (thin dispatch; 9 type_complexity allows dissolved via PlayerInputQuery alias); dialogue.rs → dialogue/{mod,selection,response,confrontation} with public paths preserved. Documented seam call: process_walk_away sits with confrontation (shared D-064/D-063 world-response shape). Zero behavior change proven: determinism + golden_suite byte-identical, 1,504 lib tests unchanged, 23+53 tests moved with subjects, scheduling registrations untouched. Full gate green on push.', 'done', 'medium', NULL, 'server', NULL, '2026-06-12 10:40:59', '2026-06-12 15:08:41', NULL, '5a2a8338136b821745012637f22608ec', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRX067NBNG76MV84MDQ0', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Split the 2,617-line import_economics.py monolith; single shared generator-source registry', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-19; citations adversarially verified).
|
||
tooling/economy-db/import_economics.py (2,617 lines, 31 top-level defs) owns schema migration, brand regeneration (shells to Rust), 16 import steps, validation, and the meta stamp. Its source-file list is hand-maintained in THREE places guarded only by comments: IMPORT_ECONOMICS_SOURCES (:81-99), GENERATOR_SOURCES (tooling/check-systems-db-stamp:48-63), and the /pr-push watch list (.claude/skills/pr-process/SKILL.md:222-243). Error handling itself is good (single transaction, rollback, distinct exit codes at :2350-2613).
|
||
Fix: extract one shared tooling/generator_sources.py imported by the script + stamp checker and read by /pr-push; then split importers/validators into modules under tooling/economy-db/; finish type hints during the split. Also fold in S-25''s connector dedup: move CONFIG_PATH/load_config/get_base_url into tooling/db/common.py (currently copy-pasted across audio/trellis/image connectors).', 'in_progress', 'medium', NULL, NULL, NULL, '2026-06-12 10:40:59', '2026-06-12 17:47:35', NULL, '46bb09b660cefbc43f3bcfb0dfcb894e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRX067NBNG76MV84MDQ0', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Split the 2,617-line import_economics.py monolith; single shared generator-source registry', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-19; citations adversarially verified).
|
||
tooling/economy-db/import_economics.py (2,617 lines, 31 top-level defs) owns schema migration, brand regeneration (shells to Rust), 16 import steps, validation, and the meta stamp. Its source-file list is hand-maintained in THREE places guarded only by comments: IMPORT_ECONOMICS_SOURCES (:81-99), GENERATOR_SOURCES (tooling/check-systems-db-stamp:48-63), and the /pr-push watch list (.claude/skills/pr-process/SKILL.md:222-243). Error handling itself is good (single transaction, rollback, distinct exit codes at :2350-2613).
|
||
Fix: extract one shared tooling/generator_sources.py imported by the script + stamp checker and read by /pr-push; then split importers/validators into modules under tooling/economy-db/; finish type hints during the split. Also fold in S-25''s connector dedup: move CONFIG_PATH/load_config/get_base_url into tooling/db/common.py (currently copy-pasted across audio/trellis/image connectors).', 'done', 'medium', NULL, NULL, NULL, '2026-06-12 10:40:59', '2026-06-12 18:15:04', NULL, '29a8fbb2c1e838d8619554799a5bd4f3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXRX067NBNG76MV84MDQ0', 'task', '06FBPPMZNNEV052DBYYY3A897C', 'Split the 2,617-line import_economics.py monolith; single shared generator-source registry', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-19; citations adversarially verified).
|
||
tooling/economy-db/import_economics.py (2,617 lines, 31 top-level defs) owns schema migration, brand regeneration (shells to Rust), 16 import steps, validation, and the meta stamp. Its source-file list is hand-maintained in THREE places guarded only by comments: IMPORT_ECONOMICS_SOURCES (:81-99), GENERATOR_SOURCES (tooling/check-systems-db-stamp:48-63), and the /pr-push watch list (.claude/skills/pr-process/SKILL.md:222-243). Error handling itself is good (single transaction, rollback, distinct exit codes at :2350-2613).
|
||
Fix: extract one shared tooling/generator_sources.py imported by the script + stamp checker and read by /pr-push; then split importers/validators into modules under tooling/economy-db/; finish type hints during the split. Also fold in S-25''s connector dedup: move CONFIG_PATH/load_config/get_base_url into tooling/db/common.py (currently copy-pasted across audio/trellis/image connectors).
|
||
|
||
Closed 2026-06-12, commits 4f73624ef + 3c3fd0d0d (DB stamp regen). import_economics.py 2,620→309 (thin orchestrator, exact CLI/transaction/exit-code contract); 13 modules under tooling/economy-db/economy_import/; tooling/generator_sources.py is the single registry (self-stamping, fail-closed module globbing) consumed by the importer, check-systems-db-stamp, and the pr-process watch list via --list. Connector config helpers centralized in tooling/db/common.py. Byte-identical proof: empty full-import dump diff (107,843 lines / 37 tables), dry-run parity, brands TOML sha unchanged. Gate green incl. test-tooling + stamp check on the regenerated DB.', 'done', 'medium', NULL, NULL, NULL, '2026-06-12 10:40:59', '2026-06-12 18:15:04', NULL, 'e41a21e215fc14cfd3471d1a7d01a960', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ02F02JDDBSFMGPX0XASR', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Layer 2 — inter-settlement road/rail graph (MST + A* over terrain cost, MaintenanceAuthority, named-route identity)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
Generate the inter-settlement road/rail graph at Layer 2 — the workshopped-but-never-ticketed link between settlement placement (T-955/T-956, done) and everything that consumes transport topology. No road code exists today (zero RoadGraph/road_segment hits in server/src; TerritorialStatus shipped without its road-coverage inputs).
|
||
|
||
Scope (algorithm fully decided, docs/workshops/planet-down-cascade/tyre-round1.md:274-299):
|
||
1. MST force-connect all CityPlacements (Euclidean), then secondary direct links for city pairs within 30-60% of body scale whose MST path exceeds 1.5x Euclidean.
|
||
2. Route each edge with A* over the L1 terrain-cost field (terrain_modification_cost, D-210, server/src/atlas/subbiome.rs; cost spec: water impassable, roughness>0.7 = 10.0, river corridor = 0.5, flat = 1.0 — rivers as preferred valley routes). Budget ~30ms/body (round-1-notes.md:348).
|
||
3. Assign MaintenanceAuthority per edge from endpoint relationships (5-value enum Administrative/Corporate/Communal/Trade/Abandoned — generation-cascade/workshop-outcomes.md:177, resolution :257; player-readable in road condition per ozzie-round1.md:86-92).
|
||
4. Place waypoint sub-settlement nodes at midpoints of edges > ~12 regional cells (tyre-round1.md:267-272).
|
||
5. Named-route identity assignment: post-generation join of generated edges to systems.db named highway routes via optional named_route_id FK (paula-round1.md:107,:140; round-1-notes.md:322 L2-Q3 resolution under Amendment 3).
|
||
6. RailHeadFacing second pass: settlements at high-connectivity road/rail junctions get FoundingOrientation::RailHeadFacing, overriding AdminFacing-from-Synthetic (paula-round3.md:218-236) — wire into attractor_matching.rs.
|
||
|
||
Storage: RoadGraph{nodes,edges} on BodyWorldState (round-1-notes.md:257-267), session-cached, never serialized — runtime Rust, not systems.db (the atlas_road_nodes/atlas_road_edges schema shape carries forward per tyre-round1.md:42 but lives in session memory).
|
||
|
||
Downstream consumers (do NOT scope in, but design the output for them): road_entry_directions per city (see road-entry-octants ticket; generation-cascade/round-3-notes.md:104), TerritorialStatus quantitative road-coverage thresholds (round-1-notes.md:329-338), per-economic_role hinterland fill (round-1-notes.md:324-327, BRIEF.md:279), prosperity/atlas overlays.
|
||
|
||
Cascade-first fit: this is direction step (2) — the econ layer drawn onto the world between settlements. Parent: T-750. Suggested deps: blocks the road-entry-octants ticket; references D-205 (provinces), D-210, D-211, D-212, D-213.', 'in_progress', 'high', NULL, 'server', 'D-211', '2026-06-12 10:23:49', '2026-06-13 20:44:09', NULL, 'e178b187eaa605cf4d6edccf77304487', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ02F02JDDBSFMGPX0XASR', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Layer 2 — inter-settlement road/rail graph (MST + A* over terrain cost, MaintenanceAuthority, named-route identity)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
Generate the inter-settlement road/rail graph at Layer 2 — the workshopped-but-never-ticketed link between settlement placement (T-955/T-956, done) and everything that consumes transport topology. No road code exists today (zero RoadGraph/road_segment hits in server/src; TerritorialStatus shipped without its road-coverage inputs).
|
||
|
||
Scope (algorithm fully decided, docs/workshops/planet-down-cascade/tyre-round1.md:274-299):
|
||
1. MST force-connect all CityPlacements (Euclidean), then secondary direct links for city pairs within 30-60% of body scale whose MST path exceeds 1.5x Euclidean.
|
||
2. Route each edge with A* over the L1 terrain-cost field (terrain_modification_cost, D-210, server/src/atlas/subbiome.rs; cost spec: water impassable, roughness>0.7 = 10.0, river corridor = 0.5, flat = 1.0 — rivers as preferred valley routes). Budget ~30ms/body (round-1-notes.md:348).
|
||
3. Assign MaintenanceAuthority per edge from endpoint relationships (5-value enum Administrative/Corporate/Communal/Trade/Abandoned — generation-cascade/workshop-outcomes.md:177, resolution :257; player-readable in road condition per ozzie-round1.md:86-92).
|
||
4. Place waypoint sub-settlement nodes at midpoints of edges > ~12 regional cells (tyre-round1.md:267-272).
|
||
5. Named-route identity assignment: post-generation join of generated edges to systems.db named highway routes via optional named_route_id FK (paula-round1.md:107,:140; round-1-notes.md:322 L2-Q3 resolution under Amendment 3).
|
||
6. RailHeadFacing second pass: settlements at high-connectivity road/rail junctions get FoundingOrientation::RailHeadFacing, overriding AdminFacing-from-Synthetic (paula-round3.md:218-236) — wire into attractor_matching.rs.
|
||
|
||
Storage: RoadGraph{nodes,edges} on BodyWorldState (round-1-notes.md:257-267), session-cached, never serialized — runtime Rust, not systems.db (the atlas_road_nodes/atlas_road_edges schema shape carries forward per tyre-round1.md:42 but lives in session memory).
|
||
|
||
Downstream consumers (do NOT scope in, but design the output for them): road_entry_directions per city (see road-entry-octants ticket; generation-cascade/round-3-notes.md:104), TerritorialStatus quantitative road-coverage thresholds (round-1-notes.md:329-338), per-economic_role hinterland fill (round-1-notes.md:324-327, BRIEF.md:279), prosperity/atlas overlays.
|
||
|
||
Cascade-first fit: this is direction step (2) — the econ layer drawn onto the world between settlements. Parent: T-750. Suggested deps: blocks the road-entry-octants ticket; references D-205 (provinces), D-210, D-211, D-212, D-213.', 'in_progress', 'high', NULL, 'server', 'D-211', '2026-06-12 10:23:49', '2026-06-13 20:44:30', NULL, '591936c6e539ddf25905176ce059b676', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDG73NW7SNCA5Y8JN905QMR', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Corp HQ settlement model — remove HQs from the city pool; specialization-keyed standalone-vs-tenant; install-baked', 'Per D-242. Corp HQs are not cities and must leave atlas_city_names.
|
||
|
||
1. Remove the D-207/D-223 reserved=1 corp-HQ cross-reference (populate_atlas_city_names_corps, tooling/economy-db/economy_import/atlas.py) — it inserts one atlas_city_names row per corp HQ, creating duplicate co-named cities (e.g. 10 Groombridge rows on GJ380c).
|
||
2. Author a source-canonical specialization -> HQ-placement map ({CityTenant, Standalone}). corp_type is degenerate (corporation/combine only); key on corporations.specialization (and/or supply_chain_role). Install-baked.
|
||
3. CityTenant HQs: a corp->city link, no new settlement (many corps may tenant one city).
|
||
4. Standalone HQs (extraction/heavy-industry/shipyards): emit their own settlement (body + position) into the cascade settlement list. Requires resolving headquarters_body (today 0/165 set; only headquarters_system + a most-populated-body heuristic).
|
||
5. Cascade settlement input becomes: city pool + standalone-HQ settlements, merged.
|
||
|
||
Amends D-207, D-223. Blocks the road-graph hub refinement.', 'backlog', 'high', NULL, 'server', 'D-242', '2026-06-14 15:29:50', '2026-06-14 15:29:50', NULL, '9176515b9f67459f2dcee6c58de1e0fa', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDG73S4ET8KKTK62Z5KFEQM', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Bake per-settlement population + settlement_class into the install dataset (only position stays seed-derived)', 'Per D-242. population + settlement_class are install-baked, not seed-derived.
|
||
|
||
Today: body-level population is baked (273/3240 bodies > 0), but per-city population is 0 and settlement_class NULL for all 463 atlas_city_names rows. D-223 deferred these ''to placement (T-955)'', but match_cities only READS them for tiering — nothing assigns them, so the pop-from-seed step was never built and all cities fall to synthetic placement.
|
||
|
||
Bake the per-settlement population spread + settlement_class into the source data (importer/source TOMLs). Only POSITION stays seed-derived (D-211). Drop the never-built seed-population idea.
|
||
|
||
Supersedes the D-223 deferred-pop/class note. Enables significance-ranked hub selection.', 'backlog', 'high', NULL, 'server', 'D-242', '2026-06-14 15:29:50', '2026-06-14 15:29:50', NULL, 'a3e992272c50209fb1dfffbcfe6ea28c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDG73V9R6N024QSFDEJ4R68', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Road-graph hub refinement — scaled-cap hubs + co-location collapse + hybrid minor attach + RailHeadFacing junction pass', 'Follow-on to T-1038 (road-graph core shipped). Hub-selection refinement, gated on the resolved settlement model (D-242).
|
||
|
||
Build on server/src/atlas/road_graph.rs:
|
||
1. Hub selection: ''real cities, scaled cap'' — wiki cities anchor the MST; cap scales with body size; standalone HQs/minor settlements are non-hub.
|
||
2. Co-location collapse: group same-named settlements (defensive; the D-242 corp-HQ fix removes most at source).
|
||
3. Hybrid minor-settlement attach: snap to nearest existing road edge if close, else spur to nearest hub (add edge-split-at-attach).
|
||
4. RailHeadFacing junction pass (T-1038 step 6, deferred): junction settlements (RoadGraph::high_connectivity_junctions already computed) get FoundingOrientation::RailHeadFacing. REQUIRES a D-213 amendment (adopted enum has no RailHeadFacing) + Layer-4 skeleton_gen handling.
|
||
|
||
Needs population ranking — blocked on the corp-HQ-model + population-bake tickets.', 'backlog', 'medium', NULL, 'server', 'D-242', '2026-06-14 15:29:50', '2026-06-14 15:29:50', NULL, 'a9b2ff68ee5d9208cffb0a1ebe63bbe2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ02F02JDDBSFMGPX0XASR', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Layer 2 — inter-settlement road/rail graph (MST + A* over terrain cost, MaintenanceAuthority, named-route identity)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
Generate the inter-settlement road/rail graph at Layer 2 — the workshopped-but-never-ticketed link between settlement placement (T-955/T-956, done) and everything that consumes transport topology. No road code exists today (zero RoadGraph/road_segment hits in server/src; TerritorialStatus shipped without its road-coverage inputs).
|
||
|
||
Scope (algorithm fully decided, docs/workshops/planet-down-cascade/tyre-round1.md:274-299):
|
||
1. MST force-connect all CityPlacements (Euclidean), then secondary direct links for city pairs within 30-60% of body scale whose MST path exceeds 1.5x Euclidean.
|
||
2. Route each edge with A* over the L1 terrain-cost field (terrain_modification_cost, D-210, server/src/atlas/subbiome.rs; cost spec: water impassable, roughness>0.7 = 10.0, river corridor = 0.5, flat = 1.0 — rivers as preferred valley routes). Budget ~30ms/body (round-1-notes.md:348).
|
||
3. Assign MaintenanceAuthority per edge from endpoint relationships (5-value enum Administrative/Corporate/Communal/Trade/Abandoned — generation-cascade/workshop-outcomes.md:177, resolution :257; player-readable in road condition per ozzie-round1.md:86-92).
|
||
4. Place waypoint sub-settlement nodes at midpoints of edges > ~12 regional cells (tyre-round1.md:267-272).
|
||
5. Named-route identity assignment: post-generation join of generated edges to systems.db named highway routes via optional named_route_id FK (paula-round1.md:107,:140; round-1-notes.md:322 L2-Q3 resolution under Amendment 3).
|
||
6. RailHeadFacing second pass: settlements at high-connectivity road/rail junctions get FoundingOrientation::RailHeadFacing, overriding AdminFacing-from-Synthetic (paula-round3.md:218-236) — wire into attractor_matching.rs.
|
||
|
||
Storage: RoadGraph{nodes,edges} on BodyWorldState (round-1-notes.md:257-267), session-cached, never serialized — runtime Rust, not systems.db (the atlas_road_nodes/atlas_road_edges schema shape carries forward per tyre-round1.md:42 but lives in session memory).
|
||
|
||
Downstream consumers (do NOT scope in, but design the output for them): road_entry_directions per city (see road-entry-octants ticket; generation-cascade/round-3-notes.md:104), TerritorialStatus quantitative road-coverage thresholds (round-1-notes.md:329-338), per-economic_role hinterland fill (round-1-notes.md:324-327, BRIEF.md:279), prosperity/atlas overlays.
|
||
|
||
Cascade-first fit: this is direction step (2) — the econ layer drawn onto the world between settlements. Parent: T-750. Suggested deps: blocks the road-entry-octants ticket; references D-205 (provinces), D-210, D-211, D-212, D-213.
|
||
|
||
---
|
||
Implementation (2026-06-14):
|
||
SHIPPED — deterministic road-graph CORE in server/src/atlas/road_graph.rs (CascadeLayer::RoadGraph, stored on BodyWorldState.road_graph, never serialized):
|
||
1. MST force-connect (strict Kruskal over dist^2) + secondary links (30-60% body-scale band, >1.5x MST detour).
|
||
2. A* over the L1 terrain-cost field (ocean/lake impassable, river 1/2 cost, slope>=35deg 10x, else D-210 terrain_modification_cost) on a coarse 64-wide routing grid; equirectangular column wrap.
|
||
3. MaintenanceAuthority per edge (new generator.rs enum: Administrative/Corporate/Communal/Trade/Abandoned) from endpoint political archetypes + haul length.
|
||
4. Waypoint nodes at midpoints of edges > 12 routing cells.
|
||
5. Named-route identity join (named_route_id, designed-for; pool empty post-D-223 -> no-op).
|
||
+ junction detection (RoadGraph::high_connectivity_junctions, degree>=3).
|
||
Wired into the cascade (gen_queue requests CascadeLayer::RoadGraph) + BodyWorldState. 10 road_graph unit tests + a cascade e2e test; full lib suite green.
|
||
|
||
DEFERRED (-> T-1076, gated on the D-242 settlement model T-1074/T-1075):
|
||
- step 6 RailHeadFacing second pass — the adopted FoundingOrientation enum (D-213) has no RailHeadFacing; needs a D-213 amendment + Layer-4 skeleton_gen handling. Junction data is already exposed for it.
|
||
- hub-selection refinement (scaled-cap hubs, co-location collapse, hybrid minor-settlement attach) — needs baked population/specialization (D-242).
|
||
Decision D-242 filed (corp-HQ settlement model) — resolves why corp HQs were polluting the city pool as duplicate settlements.', 'in_progress', 'high', NULL, 'server', 'D-211', '2026-06-12 10:23:49', '2026-06-14 15:30:58', NULL, '55c0e158089122497cf34e9574595d50', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCF56EAJ55PHQ977SV866CFM', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Re-scale the cascade to the D-243 ladder + elastic-seam resampling (region 205km / district 2km)', 'Per D-243 (resolves Q-110). Make the code match the canonical ladder.
|
||
|
||
1. Re-scale the terrain/climate carrier: the current ~1km RegionProfile (region_profile.rs, derive_all_regions 8-cells/region) moves to the DISTRICT (2km), aligning with D-239 §2''s climate district. Rename RegionProfile -> DistrictProfile (or equivalent); fix the contradictory scale assumptions Q-110 flagged (region_profile.rs:3-4 ~1km doc, cascade.rs:235-237 ''8 cells/region on 128x64'', chunk_context.rs:137-141 ''region=16 chunks'').
|
||
2. Add the REGION tier = 100x100 districts = 204.8km (~205km) = the top hard block.
|
||
3. Elastic seam region<->planet: round(2*pi*R/204.8km) regions per body from body_radius_km (D-204). ChunkPos -> district -> region is fixed integer math; region->heightmap-sample is the only body-specific function.
|
||
4. Detail-scatter synthesis (D-243 §2): interpolate the coarse heightmap (~40-78km/px) + compose a simple multi-octave seed+position-keyed detail field (shaped by morphology/slope, continuous) atop the D-239 §4 domain warp — invented, not stored (D-227), plausible-at-a-glance.
|
||
|
||
Blocks T-1046 (the tier can''t wire to production until its scale matches the ladder).', 'backlog', 'high', NULL, 'server', 'D-243', '2026-06-14 19:21:18', '2026-06-14 19:21:18', NULL, '07e0b2847d5908017dbb53e5e34b16d8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCF56ED5ZJZRXFMF3PNSNZF0', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Region climate stack — weather/season/temperature baseline + district modulation + edge fuzz', 'Per D-243 §3/§4 (refines D-239 §2; contributes the region-clock toward Q-105).
|
||
|
||
Three-level climate stack:
|
||
- REGION (~205km): the climate context — latitude-driven temperature baseline, weather state, seasonal clock. Resolved ONCE per region (the Q-105 cheap-dynamism source); inherited by every district/tile inside. ''Region temperature'' = context, not a uniform slab.
|
||
- DISTRICT (2km): local temperature = region baseline + elevation lapse + slope aspect (D-239 §2''s district temperature, now a MODULATION of the region rather than derived from scratch).
|
||
- CHUNK/VOXEL: D-239 §3 freeze/snow scatter on the local temperature.
|
||
|
||
EDGE FUZZ (D-243 §4): climate does not change on a line. A tile''s climate is a continuous warp-perturbed blend of surrounding regions'' baselines (bilinear across region centres + noise displacement so the boundary is ragged); same at district edges. The region/district grid must be invisible in the output. This is the climate counterpart to D-239 §4''s domain warp — climate is feathered/blended (continuous field), unlike morphology which stays sharp-but-organic (D-239 §7).', 'backlog', 'medium', NULL, 'server', 'D-243', '2026-06-14 19:21:18', '2026-06-14 19:21:18', NULL, '5ea7ddbb4540f2e443e2b9e08d0ecc73', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXP19FFZEVED140S1708W', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Wire the Region→Chunk→Voxel tier into production — ChunkPos→RegionPos mapping, proxy layers, Atlas surfacing', '(description follows in first append)
|
||
|
||
---
|
||
Q-110 resolved (2026-06-14) -> D-243. Scope item (1) ChunkPos->RegionPos is now defined: the D-243 absolute ladder is voxel(1m)->chunk(64m)->block(128m)->quarter(512m)->district(2km)->region(~205km), with a single elastic seam region<->planet (round(2*pi*R/204.8km) regions per body from body_radius_km). ChunkPos->district->region is fixed integer math; only region->heightmap-sample is body-specific.
|
||
|
||
Prerequisite: T-1077 re-scales the code to this ladder (the current ~1km RegionProfile moves onto the 2km district; the region becomes the new 205km top hard block) — T-1046 now blocked by T-1077. Climate/weather lockdown + edge fuzz on the region is T-1078. Once T-1077 lands, T-1046 is the production wiring (proxy layers + Atlas surfacing) over a ladder whose scale is finally coherent.', 'backlog', 'high', NULL, 'server', 'D-239', '2026-06-12 10:40:58', '2026-06-14 19:22:14', NULL, 'c3379b82cb706bdf11174688e5d203e6', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCF56EAJ55PHQ977SV866CFM', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Re-scale the cascade to the D-243 ladder + elastic-seam resampling (region 205km / district 2km)', 'Per D-243 (resolves Q-110). Make the code match the canonical ladder.
|
||
|
||
1. Re-scale the terrain/climate carrier: the current ~1km RegionProfile (region_profile.rs, derive_all_regions 8-cells/region) moves to the DISTRICT (2km), aligning with D-239 §2''s climate district. Rename RegionProfile -> DistrictProfile (or equivalent); fix the contradictory scale assumptions Q-110 flagged (region_profile.rs:3-4 ~1km doc, cascade.rs:235-237 ''8 cells/region on 128x64'', chunk_context.rs:137-141 ''region=16 chunks'').
|
||
2. Add the REGION tier = 100x100 districts = 204.8km (~205km) = the top hard block.
|
||
3. Elastic seam region<->planet: round(2*pi*R/204.8km) regions per body from body_radius_km (D-204). ChunkPos -> district -> region is fixed integer math; region->heightmap-sample is the only body-specific function.
|
||
4. Detail-scatter synthesis (D-243 §2): interpolate the coarse heightmap (~40-78km/px) + compose a simple multi-octave seed+position-keyed detail field (shaped by morphology/slope, continuous) atop the D-239 §4 domain warp — invented, not stored (D-227), plausible-at-a-glance.
|
||
|
||
Blocks T-1046 (the tier can''t wire to production until its scale matches the ladder).', 'in_progress', 'high', NULL, 'server', 'D-243', '2026-06-14 19:21:18', '2026-06-14 19:40:42', NULL, '752fdfed97c7f7fe81747a8504dee793', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCF56EAJ55PHQ977SV866CFM', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Re-scale the cascade to the D-243 ladder + elastic-seam resampling (region 205km / district 2km)', 'Per D-243 (resolves Q-110). Make the code match the canonical ladder.
|
||
|
||
1. Re-scale the terrain/climate carrier: the current ~1km RegionProfile (region_profile.rs, derive_all_regions 8-cells/region) moves to the DISTRICT (2km), aligning with D-239 §2''s climate district. Rename RegionProfile -> DistrictProfile (or equivalent); fix the contradictory scale assumptions Q-110 flagged (region_profile.rs:3-4 ~1km doc, cascade.rs:235-237 ''8 cells/region on 128x64'', chunk_context.rs:137-141 ''region=16 chunks'').
|
||
2. Add the REGION tier = 100x100 districts = 204.8km (~205km) = the top hard block.
|
||
3. Elastic seam region<->planet: round(2*pi*R/204.8km) regions per body from body_radius_km (D-204). ChunkPos -> district -> region is fixed integer math; region->heightmap-sample is the only body-specific function.
|
||
4. Detail-scatter synthesis (D-243 §2): interpolate the coarse heightmap (~40-78km/px) + compose a simple multi-octave seed+position-keyed detail field (shaped by morphology/slope, continuous) atop the D-239 §4 domain warp — invented, not stored (D-227), plausible-at-a-glance.
|
||
|
||
Blocks T-1046 (the tier can''t wire to production until its scale matches the ladder).', 'in_progress', 'high', NULL, 'server', 'D-243', '2026-06-14 19:21:18', '2026-06-14 19:51:10', NULL, 'ecae1405c540fb403d3f1126ce5b4082', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCF56EAJ55PHQ977SV866CFM', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Re-scale the cascade to the D-243 ladder + elastic-seam resampling (region 205km / district 2km)', 'Per D-243 (resolves Q-110). Make the code match the canonical ladder.
|
||
|
||
1. Re-scale the terrain/climate carrier: the current ~1km RegionProfile (region_profile.rs, derive_all_regions 8-cells/region) moves to the DISTRICT (2km), aligning with D-239 §2''s climate district. Rename RegionProfile -> DistrictProfile (or equivalent); fix the contradictory scale assumptions Q-110 flagged (region_profile.rs:3-4 ~1km doc, cascade.rs:235-237 ''8 cells/region on 128x64'', chunk_context.rs:137-141 ''region=16 chunks'').
|
||
2. Add the REGION tier = 100x100 districts = 204.8km (~205km) = the top hard block.
|
||
3. Elastic seam region<->planet: round(2*pi*R/204.8km) regions per body from body_radius_km (D-204). ChunkPos -> district -> region is fixed integer math; region->heightmap-sample is the only body-specific function.
|
||
4. Detail-scatter synthesis (D-243 §2): interpolate the coarse heightmap (~40-78km/px) + compose a simple multi-octave seed+position-keyed detail field (shaped by morphology/slope, continuous) atop the D-239 §4 domain warp — invented, not stored (D-227), plausible-at-a-glance.
|
||
|
||
Blocks T-1046 (the tier can''t wire to production until its scale matches the ladder).
|
||
|
||
---
|
||
Implementation (2026-06-15) — all four parts delivered, committed to main, full suite + clippy -D warnings green:
|
||
|
||
Phase 1 (38054d4b1): server/src/atlas/scale.rs — the single canonical ladder (voxel/chunk/block/quarter/district/region edge metres + ChunkPos->DistrictPos->RegionPos integer addressing + regions_per_equator elastic seam), with compile-time const asserts so the rungs cannot drift again (the structural fix for the Q-110 failure mode). body_radius_km wired through BodyParams + the reader (D-204, the seam input).
|
||
|
||
Phase 2 (b3b5bfc2e): RegionProfile->DistrictProfile, RegionPos->DistrictPos, region_profile.rs->district_profile.rs, derive_*_regions->derive_*_districts across all 10 consumers + the harness. chunk_context re-scaled to scale:: (district 1024m->2048m, shift 4->5). Caught + fixed a real latent bug: the seed-district used a literal ''>> 4'' while the anchor used the constant, so same-district chunks could derive different anchors. Harness scale literals converted to scale:: constants; voxel golden re-pinned (anchors moved, deterministic).
|
||
|
||
Phase 3 (e96ed0e9e): detail_scatter.rs (the mid-scale 2-40km ''stretch magic'' — adaptive ruggedness, envelope+modulation, deterministic value-noise) + derive_district() (on-demand 2km carrier: heightmap interpolation via the body_radius seam + scatter), factored build_district_profile() tail. 10 new tests.
|
||
|
||
Ticket parts: (1) carrier re-scaled to 2km district = done (derive_district + rename). (2) REGION tier 205km = done (scale.rs). (3) elastic seam = done. (4) detail-scatter = done.
|
||
|
||
HAND-OFF to T-1046: production still reads the coarse eager derive_all_districts grid (the Atlas overlay); swapping it to on-demand district + eager 205km region surfacing (decision A) is T-1046''s chartered scope. The detail-scatter ships with sensible defaults; its VISUAL quality (''reads as real, doesn''t invite scrutiny'') can only be validated once T-1046 surfaces districts in the Atlas — tune there if needed.
|
||
|
||
Status -> review pending that visual validation.', 'in_progress', 'high', NULL, 'server', 'D-243', '2026-06-14 19:21:18', '2026-06-15 08:49:17', NULL, '306287494e42bffe7a787033550ebe20', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCF56EAJ55PHQ977SV866CFM', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Re-scale the cascade to the D-243 ladder + elastic-seam resampling (region 205km / district 2km)', 'Per D-243 (resolves Q-110). Make the code match the canonical ladder.
|
||
|
||
1. Re-scale the terrain/climate carrier: the current ~1km RegionProfile (region_profile.rs, derive_all_regions 8-cells/region) moves to the DISTRICT (2km), aligning with D-239 §2''s climate district. Rename RegionProfile -> DistrictProfile (or equivalent); fix the contradictory scale assumptions Q-110 flagged (region_profile.rs:3-4 ~1km doc, cascade.rs:235-237 ''8 cells/region on 128x64'', chunk_context.rs:137-141 ''region=16 chunks'').
|
||
2. Add the REGION tier = 100x100 districts = 204.8km (~205km) = the top hard block.
|
||
3. Elastic seam region<->planet: round(2*pi*R/204.8km) regions per body from body_radius_km (D-204). ChunkPos -> district -> region is fixed integer math; region->heightmap-sample is the only body-specific function.
|
||
4. Detail-scatter synthesis (D-243 §2): interpolate the coarse heightmap (~40-78km/px) + compose a simple multi-octave seed+position-keyed detail field (shaped by morphology/slope, continuous) atop the D-239 §4 domain warp — invented, not stored (D-227), plausible-at-a-glance.
|
||
|
||
Blocks T-1046 (the tier can''t wire to production until its scale matches the ladder).
|
||
|
||
---
|
||
Implementation (2026-06-15) — all four parts delivered, committed to main, full suite + clippy -D warnings green:
|
||
|
||
Phase 1 (38054d4b1): server/src/atlas/scale.rs — the single canonical ladder (voxel/chunk/block/quarter/district/region edge metres + ChunkPos->DistrictPos->RegionPos integer addressing + regions_per_equator elastic seam), with compile-time const asserts so the rungs cannot drift again (the structural fix for the Q-110 failure mode). body_radius_km wired through BodyParams + the reader (D-204, the seam input).
|
||
|
||
Phase 2 (b3b5bfc2e): RegionProfile->DistrictProfile, RegionPos->DistrictPos, region_profile.rs->district_profile.rs, derive_*_regions->derive_*_districts across all 10 consumers + the harness. chunk_context re-scaled to scale:: (district 1024m->2048m, shift 4->5). Caught + fixed a real latent bug: the seed-district used a literal ''>> 4'' while the anchor used the constant, so same-district chunks could derive different anchors. Harness scale literals converted to scale:: constants; voxel golden re-pinned (anchors moved, deterministic).
|
||
|
||
Phase 3 (e96ed0e9e): detail_scatter.rs (the mid-scale 2-40km ''stretch magic'' — adaptive ruggedness, envelope+modulation, deterministic value-noise) + derive_district() (on-demand 2km carrier: heightmap interpolation via the body_radius seam + scatter), factored build_district_profile() tail. 10 new tests.
|
||
|
||
Ticket parts: (1) carrier re-scaled to 2km district = done (derive_district + rename). (2) REGION tier 205km = done (scale.rs). (3) elastic seam = done. (4) detail-scatter = done.
|
||
|
||
HAND-OFF to T-1046: production still reads the coarse eager derive_all_districts grid (the Atlas overlay); swapping it to on-demand district + eager 205km region surfacing (decision A) is T-1046''s chartered scope. The detail-scatter ships with sensible defaults; its VISUAL quality (''reads as real, doesn''t invite scrutiny'') can only be validated once T-1046 surfaces districts in the Atlas — tune there if needed.
|
||
|
||
Status -> review pending that visual validation.', 'review', 'high', NULL, 'server', 'D-243', '2026-06-14 19:21:18', '2026-06-15 08:49:17', NULL, 'b764b4944775746d584223afc535292f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXP19FFZEVED140S1708W', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Wire the Region→Chunk→Voxel tier into production — ChunkPos→RegionPos mapping, proxy layers, Atlas surfacing', '(description follows in first append)
|
||
|
||
---
|
||
Q-110 resolved (2026-06-14) -> D-243. Scope item (1) ChunkPos->RegionPos is now defined: the D-243 absolute ladder is voxel(1m)->chunk(64m)->block(128m)->quarter(512m)->district(2km)->region(~205km), with a single elastic seam region<->planet (round(2*pi*R/204.8km) regions per body from body_radius_km). ChunkPos->district->region is fixed integer math; only region->heightmap-sample is body-specific.
|
||
|
||
Prerequisite: T-1077 re-scales the code to this ladder (the current ~1km RegionProfile moves onto the 2km district; the region becomes the new 205km top hard block) — T-1046 now blocked by T-1077. Climate/weather lockdown + edge fuzz on the region is T-1078. Once T-1077 lands, T-1046 is the production wiring (proxy layers + Atlas surfacing) over a ladder whose scale is finally coherent.', 'in_progress', 'high', NULL, 'server', 'D-239', '2026-06-12 10:40:58', '2026-06-15 08:57:03', NULL, 'c7008f3bcd45d91ecc82fb0e0dedf82e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCF56EAJ55PHQ977SV866CFM', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Re-scale the cascade to the D-243 ladder + elastic-seam resampling (region 205km / district 2km)', 'Per D-243 (resolves Q-110). Make the code match the canonical ladder.
|
||
|
||
1. Re-scale the terrain/climate carrier: the current ~1km RegionProfile (region_profile.rs, derive_all_regions 8-cells/region) moves to the DISTRICT (2km), aligning with D-239 §2''s climate district. Rename RegionProfile -> DistrictProfile (or equivalent); fix the contradictory scale assumptions Q-110 flagged (region_profile.rs:3-4 ~1km doc, cascade.rs:235-237 ''8 cells/region on 128x64'', chunk_context.rs:137-141 ''region=16 chunks'').
|
||
2. Add the REGION tier = 100x100 districts = 204.8km (~205km) = the top hard block.
|
||
3. Elastic seam region<->planet: round(2*pi*R/204.8km) regions per body from body_radius_km (D-204). ChunkPos -> district -> region is fixed integer math; region->heightmap-sample is the only body-specific function.
|
||
4. Detail-scatter synthesis (D-243 §2): interpolate the coarse heightmap (~40-78km/px) + compose a simple multi-octave seed+position-keyed detail field (shaped by morphology/slope, continuous) atop the D-239 §4 domain warp — invented, not stored (D-227), plausible-at-a-glance.
|
||
|
||
Blocks T-1046 (the tier can''t wire to production until its scale matches the ladder).
|
||
|
||
---
|
||
Implementation (2026-06-15) — all four parts delivered, committed to main, full suite + clippy -D warnings green:
|
||
|
||
Phase 1 (38054d4b1): server/src/atlas/scale.rs — the single canonical ladder (voxel/chunk/block/quarter/district/region edge metres + ChunkPos->DistrictPos->RegionPos integer addressing + regions_per_equator elastic seam), with compile-time const asserts so the rungs cannot drift again (the structural fix for the Q-110 failure mode). body_radius_km wired through BodyParams + the reader (D-204, the seam input).
|
||
|
||
Phase 2 (b3b5bfc2e): RegionProfile->DistrictProfile, RegionPos->DistrictPos, region_profile.rs->district_profile.rs, derive_*_regions->derive_*_districts across all 10 consumers + the harness. chunk_context re-scaled to scale:: (district 1024m->2048m, shift 4->5). Caught + fixed a real latent bug: the seed-district used a literal ''>> 4'' while the anchor used the constant, so same-district chunks could derive different anchors. Harness scale literals converted to scale:: constants; voxel golden re-pinned (anchors moved, deterministic).
|
||
|
||
Phase 3 (e96ed0e9e): detail_scatter.rs (the mid-scale 2-40km ''stretch magic'' — adaptive ruggedness, envelope+modulation, deterministic value-noise) + derive_district() (on-demand 2km carrier: heightmap interpolation via the body_radius seam + scatter), factored build_district_profile() tail. 10 new tests.
|
||
|
||
Ticket parts: (1) carrier re-scaled to 2km district = done (derive_district + rename). (2) REGION tier 205km = done (scale.rs). (3) elastic seam = done. (4) detail-scatter = done.
|
||
|
||
HAND-OFF to T-1046: production still reads the coarse eager derive_all_districts grid (the Atlas overlay); swapping it to on-demand district + eager 205km region surfacing (decision A) is T-1046''s chartered scope. The detail-scatter ships with sensible defaults; its VISUAL quality (''reads as real, doesn''t invite scrutiny'') can only be validated once T-1046 surfaces districts in the Atlas — tune there if needed.
|
||
|
||
Status -> review pending that visual validation.', 'done', 'high', NULL, 'server', 'D-243', '2026-06-14 19:21:18', '2026-06-15 08:57:30', NULL, '0fd215db7a33e6569fbe7d76c846df48', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXP19FFZEVED140S1708W', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Wire the Region→Chunk→Voxel tier into production — ChunkPos→RegionPos mapping, proxy layers, Atlas surfacing', '(description follows in first append)
|
||
|
||
---
|
||
Q-110 resolved (2026-06-14) -> D-243. Scope item (1) ChunkPos->RegionPos is now defined: the D-243 absolute ladder is voxel(1m)->chunk(64m)->block(128m)->quarter(512m)->district(2km)->region(~205km), with a single elastic seam region<->planet (round(2*pi*R/204.8km) regions per body from body_radius_km). ChunkPos->district->region is fixed integer math; only region->heightmap-sample is body-specific.
|
||
|
||
Prerequisite: T-1077 re-scales the code to this ladder (the current ~1km RegionProfile moves onto the 2km district; the region becomes the new 205km top hard block) — T-1046 now blocked by T-1077. Climate/weather lockdown + edge fuzz on the region is T-1078. Once T-1077 lands, T-1046 is the production wiring (proxy layers + Atlas surfacing) over a ladder whose scale is finally coherent.', 'in_progress', 'high', NULL, 'server', 'D-239', '2026-06-12 10:40:58', '2026-06-15 08:57:31', NULL, 'fa35e0e45bb6ad8c5659d5b8327ea4e8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXP19FFZEVED140S1708W', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Wire the Region→Chunk→Voxel tier into production — ChunkPos→RegionPos mapping, proxy layers, Atlas surfacing', '(description follows in first append)
|
||
|
||
---
|
||
Q-110 resolved (2026-06-14) -> D-243. Scope item (1) ChunkPos->RegionPos is now defined: the D-243 absolute ladder is voxel(1m)->chunk(64m)->block(128m)->quarter(512m)->district(2km)->region(~205km), with a single elastic seam region<->planet (round(2*pi*R/204.8km) regions per body from body_radius_km). ChunkPos->district->region is fixed integer math; only region->heightmap-sample is body-specific.
|
||
|
||
Prerequisite: T-1077 re-scales the code to this ladder (the current ~1km RegionProfile moves onto the 2km district; the region becomes the new 205km top hard block) — T-1046 now blocked by T-1077. Climate/weather lockdown + edge fuzz on the region is T-1078. Once T-1077 lands, T-1046 is the production wiring (proxy layers + Atlas surfacing) over a ladder whose scale is finally coherent.
|
||
|
||
---
|
||
Implementation (2026-06-15) — the derived tier is now VISIBLE in the Atlas.
|
||
|
||
(1) ChunkPos->RegionPos: done in scale.rs (T-1077) — fixed integer addressing.
|
||
(2) Proxy serves the tier (d03b4d1e0): AtlasLayerResponse gains DistrictGridLayer (cols/rows + row-major MorphologyZone discriminants + elev_q) via build_district_grid(); populated on cache hit. rmp_serde msgpack flows it to the client automatically.
|
||
(3) Atlas surfacing (cfd5e18d0): protocol.gd decodes district_grid; atlas_viewer.gd adds the gen_district (''MRPH'') toggle + state; atlas_marker_overlay.gd paints the coarse grid coloured by morphology zone (17-zone palette, D-239 §6). gdUnit4 test green.
|
||
|
||
SCOPE NOTE: this surfaces the PLANETARY-SCALE coarse morphology grid — the Atlas map view of the derived tier (the audit headline: "the Atlas cannot show the tiers that exist" is resolved). The on-demand 2km derive_district + per-voxel geometry (T-1077) are for IN-WORLD Phase 5 rendering, NOT the planetary map; "voxel layers in the proxy" from the original audit scope belongs to Phase 5, not here.
|
||
|
||
Status -> review. Visual palette tuning can follow once eyeballed in the running Atlas (the map now renders the morphology overlay over real bodies).', 'in_progress', 'high', NULL, 'server', 'D-239', '2026-06-12 10:40:58', '2026-06-15 10:58:18', NULL, 'bd6c24cce8317898b29f27d68958aea1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXP19FFZEVED140S1708W', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Wire the Region→Chunk→Voxel tier into production — ChunkPos→RegionPos mapping, proxy layers, Atlas surfacing', '(description follows in first append)
|
||
|
||
---
|
||
Q-110 resolved (2026-06-14) -> D-243. Scope item (1) ChunkPos->RegionPos is now defined: the D-243 absolute ladder is voxel(1m)->chunk(64m)->block(128m)->quarter(512m)->district(2km)->region(~205km), with a single elastic seam region<->planet (round(2*pi*R/204.8km) regions per body from body_radius_km). ChunkPos->district->region is fixed integer math; only region->heightmap-sample is body-specific.
|
||
|
||
Prerequisite: T-1077 re-scales the code to this ladder (the current ~1km RegionProfile moves onto the 2km district; the region becomes the new 205km top hard block) — T-1046 now blocked by T-1077. Climate/weather lockdown + edge fuzz on the region is T-1078. Once T-1077 lands, T-1046 is the production wiring (proxy layers + Atlas surfacing) over a ladder whose scale is finally coherent.
|
||
|
||
---
|
||
Implementation (2026-06-15) — the derived tier is now VISIBLE in the Atlas.
|
||
|
||
(1) ChunkPos->RegionPos: done in scale.rs (T-1077) — fixed integer addressing.
|
||
(2) Proxy serves the tier (d03b4d1e0): AtlasLayerResponse gains DistrictGridLayer (cols/rows + row-major MorphologyZone discriminants + elev_q) via build_district_grid(); populated on cache hit. rmp_serde msgpack flows it to the client automatically.
|
||
(3) Atlas surfacing (cfd5e18d0): protocol.gd decodes district_grid; atlas_viewer.gd adds the gen_district (''MRPH'') toggle + state; atlas_marker_overlay.gd paints the coarse grid coloured by morphology zone (17-zone palette, D-239 §6). gdUnit4 test green.
|
||
|
||
SCOPE NOTE: this surfaces the PLANETARY-SCALE coarse morphology grid — the Atlas map view of the derived tier (the audit headline: "the Atlas cannot show the tiers that exist" is resolved). The on-demand 2km derive_district + per-voxel geometry (T-1077) are for IN-WORLD Phase 5 rendering, NOT the planetary map; "voxel layers in the proxy" from the original audit scope belongs to Phase 5, not here.
|
||
|
||
Status -> review. Visual palette tuning can follow once eyeballed in the running Atlas (the map now renders the morphology overlay over real bodies).', 'review', 'high', NULL, 'server', 'D-239', '2026-06-12 10:40:58', '2026-06-15 10:58:18', NULL, 'fdedb874bc8bd5e6c47e551508dca6b5', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ0308CFF9WKNGBBYQ763W', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Cross-region parameter blending at chunk/voxel scale (replace single-profile walking skeleton)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
Implement cross-region parameter blending at the chunk/voxel scale, replacing the walking-skeleton single-profile restriction (server/src/atlas/chunk_context.rs:119-123: ''in the future a blend of adjacent profiles will handle cross-region chunk seams''). Today every voxel generator reads the one covering RegionProfile''s values directly (region.elev_q at voxel.rs:614, :731, :1067-1068; channel/meander params likewise), so continuous parameters step discontinuously at every region-grid border — elevation cliffs at the region pitch, visible as a grid at Atlas/voxel scale.
|
||
|
||
Design is decided — stay inside the D-239 §7 seam policy:
|
||
- NEVER blend morphology family selection. Family seams are prevented at source (gate ordering + build-time compatibility matrix) or kept sharp (cliff-fjord, lithology faults are real geology). Tyre''s cross-family elevation-blend was explicitly resolved against (D-239 dissent line).
|
||
- DO blend continuous positional parameters: elevation, channel width, meander wavelength/phase, freeze/moisture scalars. Mechanism from tile-derivation-contract/tyre-round1.md: ChunkContext gains secondary: Option<RegionProfile> + blend_weight: u8 (255 = fully primary; :123-125), blend zone one chunk (64 m) each side of the region border (:101-102); derive_voxel resolves parameters from both profiles and integer-blends BEFORE material selection (:217-220), reusing the same warp offset so the blend seam cannot align with the chunk edge; elevation sampled bilinearly from the region grid to chunk resolution (:130, the elevation_grid sketch).
|
||
- D-010 discipline: integer blend arithmetic; the f64 path only for position math per D-239 §4.
|
||
|
||
Note: region size in metres is currently ambiguous (see the scale-anchoring Q-record) — the blend can be implemented against the region grid index regardless, but the Q should be resolved before tuning blend-zone width in metres.
|
||
|
||
Acceptance: T-1031 harness cross-region chunk pairs show no elevation step exceeding the lithology-permitted slope (D-239 §8) at region borders; family seams remain sharp; determinism golden-seed unchanged for chunks far from borders. Parent: T-750. Refs: D-239 §4/§7/§8, D-010; Q-102; T-1026/T-1028/T-1029 (predecessors).
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — supersedes the stale code/scale refs above. The original scope was authored 2026-06-12, BEFORE T-1077 landed (RegionProfile→DistrictProfile rename + D-243 re-scale). Design intent unchanged; the references below are the current tree.
|
||
|
||
REFRAME — this is cross-DISTRICT blending, not cross-region. After T-1077 the per-voxel carrier is the DistrictProfile (2,048 m district), so the single-profile "walking skeleton" restriction is a single-DISTRICT-profile restriction and the visible step is at the 2 km district pitch (finer / more visible than the old "region grid" framing). There is no RegionProfile / region.elev_q in the tree anymore.
|
||
|
||
CURRENT REFS (use these):
|
||
- Carrier: server/src/atlas/district_profile.rs (DistrictProfile).
|
||
- The "future blend" TODO: server/src/atlas/chunk_context.rs:166-168 ("in the future a blend of adjacent profiles will handle cross-district chunk seams, but for the walking skeleton one profile is sufficient").
|
||
- Per-voxel elevation reads: server/src/atlas/voxel.rs:443/515/605/723/808/984/1062-1063/1157 (all district.elev_q).
|
||
- channel width / meander wavelength+phase already live ON ChunkContext (precomputed from DistrictProfile) — blend them on the context, do NOT re-read them from the profile in the blend path.
|
||
- derive_chunk_context entry: chunk_context.rs:176. derive_voxel_column entry: voxel.rs:330.
|
||
|
||
SCALE-Q RESOLVED: D-243 fixed district=2,048 m, region=~205 km — the "region size in metres ambiguous" note is obsolete. Q-102 (noise-basis algorithm) stays open but does NOT block blend-zone arithmetic. Blend zone = one chunk (64 m) each side of the district border, against the district grid index.
|
||
|
||
D-243 §4 / D-239 §7 RECONCILIATION (no conflict): D-243 §4''s continuous edge-fuzz mandate governs CLIMATE scalars — that is T-1078''s job. T-1042 blends continuous TERRAIN positional params only: elevation, channel width, meander wavelength/phase, freeze/moisture scalars. Morphology FAMILY selection is NEVER blended — it stays sharp per D-239 §7 (gate ordering + compatibility matrix; cliff-fjord/lithology faults are real geology). The two decisions partition cleanly: family sharp, continuous params feathered.
|
||
|
||
API SHAPE (follow the ticket''s own mechanism): ChunkContext gains `secondary: Option<DistrictProfile>` + `blend_weight: u8` (255 = fully primary). The caller of derive_chunk_context detects a chunk lying within one chunk of a district boundary and supplies the adjacent DistrictProfile; derive_voxel_column reads secondary+blend_weight off ChunkContext and integer-blends (D-010: integer arithmetic; f64 only for position per D-239 §4) BEFORE material selection, reusing the same warp offset so the blend seam cannot align with the chunk edge. No new parameter on derive_voxel_column — it reads the context.
|
||
|
||
ACCEPTANCE (concrete): add a cross-district chunk-pair test to server/tests/derivation_harness.rs (alongside channel_continuous_across_chunk_boundary_far_from_origin:1054). Pass condition — the elevation step across a district seam is no larger than the typical step between adjacent INTERIOR chunks within a district (i.e. the seam is invisible — operationalizes D-243 "the grid must be invisible"); morphology family seams remain sharp; golden-seed determinism unchanged for chunks far from any district border. No fixed metre threshold (D-239 §8 is qualitative per lithology) — assert continuity relative to interior variation, not an absolute bound.', 'backlog', 'medium', NULL, 'server', 'D-239', '2026-06-12 10:23:50', '2026-06-15 11:30:30', NULL, '9ab66310f1cf116a762378e72b44dfb4', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCF56ED5ZJZRXFMF3PNSNZF0', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Region climate stack — weather/season/temperature baseline + district modulation + edge fuzz', 'Per D-243 §3/§4 (refines D-239 §2; contributes the region-clock toward Q-105).
|
||
|
||
Three-level climate stack:
|
||
- REGION (~205km): the climate context — latitude-driven temperature baseline, weather state, seasonal clock. Resolved ONCE per region (the Q-105 cheap-dynamism source); inherited by every district/tile inside. ''Region temperature'' = context, not a uniform slab.
|
||
- DISTRICT (2km): local temperature = region baseline + elevation lapse + slope aspect (D-239 §2''s district temperature, now a MODULATION of the region rather than derived from scratch).
|
||
- CHUNK/VOXEL: D-239 §3 freeze/snow scatter on the local temperature.
|
||
|
||
EDGE FUZZ (D-243 §4): climate does not change on a line. A tile''s climate is a continuous warp-perturbed blend of surrounding regions'' baselines (bilinear across region centres + noise displacement so the boundary is ragged); same at district edges. The region/district grid must be invisible in the output. This is the climate counterpart to D-239 §4''s domain warp — climate is feathered/blended (continuous field), unlike morphology which stays sharp-but-organic (D-239 §7).
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — READY. Implementer brief against the current tree (post-T-1077).
|
||
|
||
NET-NEW vs REFACTOR:
|
||
- NET-NEW: the region (~205 km) climate tier is new structure. RegionPos + district_to_region/chunk_to_region already exist (server/src/atlas/scale.rs:70/82/91, from T-1077) — addressing skeleton is laid. There is NO RegionProfile/RegionClimate struct, no weather state, and no seasonal clock in the tree today; this ticket introduces them.
|
||
- REFACTOR: derive_temperature_c (server/src/atlas/district_profile.rs:792) currently derives district temperature FROM SCRATCH (D-240 class-envelope latitude lerp + greenhouse nudge + lapse + seed nudge, per district). Split it into (a) a region-baseline fn (latitude + greenhouse + nudge, keeping the D-240 planet_class envelope anchoring) and (b) a district-modulation fn (elevation lapse + slope aspect on top of the baseline) per D-239 §2 — district temperature becomes a MODULATION of the region baseline, not an independent derivation.
|
||
|
||
DOWNSTREAM (no signature change): derive_cover freeze/snow scatter (voxel.rs:1408, reads district.temperature_c at :1417, from T-1030) consumes the post-refactor per-district value as-is.
|
||
|
||
EDGE FUZZ (D-243 §4): climate is a continuous warp-perturbed bilinear blend of surrounding region baselines (+ noise displacement so the boundary is ragged) — the climate counterpart to D-239 §4''s domain warp. Resolved UPSTREAM of build_district_profile, so ChunkContext is unaffected.
|
||
|
||
RELATION TO T-1042 (independent — do NOT share the mechanism): T-1078 blends CLIMATE scalars at the region→district seam (205 km); T-1042 blends TERRAIN scalars at the district→chunk seam (2 km). Separate mechanisms — do NOT reuse ChunkContext.secondary/blend_weight for climate. Both proceed in parallel.
|
||
|
||
Q-105 DEFERRAL: build the static/mean-state region baseline + edge-fuzz blend + the region-clock STRUCTURE. The transient clock-phase callbacks (seasonal frost form/melt, crop-cycle cadence, recompute schedule) are deferred to Q-105 per the two-phase convention already established in the derive_cover docblock (voxel.rs:185-189). This ticket CONTRIBUTES the region-clock toward Q-105; it does not resolve it.
|
||
|
||
FILES: district_profile.rs (split derive_temperature_c; refactor build_district_profile to take a region baseline); new region_profile.rs (RegionProfile/RegionClimate + baseline derivation + edge-fuzz blend); scale.rs (no change — RegionPos/addressing already present); cascade.rs (wire the region tier into the derivation chain). Governing: D-243 §3/§4 (primary), D-239 §2/§3, D-240 (class-envelope anchoring), Q-105 (deferred transient clock).', 'backlog', 'medium', NULL, 'server', 'D-243', '2026-06-14 19:21:18', '2026-06-15 11:30:30', NULL, '2a55bf30a8cc21711e3c5cd250d75958', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCF56ED5ZJZRXFMF3PNSNZF0', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Region climate stack — weather/season/temperature baseline + district modulation + edge fuzz', 'Per D-243 §3/§4 (refines D-239 §2; contributes the region-clock toward Q-105).
|
||
|
||
Three-level climate stack:
|
||
- REGION (~205km): the climate context — latitude-driven temperature baseline, weather state, seasonal clock. Resolved ONCE per region (the Q-105 cheap-dynamism source); inherited by every district/tile inside. ''Region temperature'' = context, not a uniform slab.
|
||
- DISTRICT (2km): local temperature = region baseline + elevation lapse + slope aspect (D-239 §2''s district temperature, now a MODULATION of the region rather than derived from scratch).
|
||
- CHUNK/VOXEL: D-239 §3 freeze/snow scatter on the local temperature.
|
||
|
||
EDGE FUZZ (D-243 §4): climate does not change on a line. A tile''s climate is a continuous warp-perturbed blend of surrounding regions'' baselines (bilinear across region centres + noise displacement so the boundary is ragged); same at district edges. The region/district grid must be invisible in the output. This is the climate counterpart to D-239 §4''s domain warp — climate is feathered/blended (continuous field), unlike morphology which stays sharp-but-organic (D-239 §7).
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — READY. Implementer brief against the current tree (post-T-1077).
|
||
|
||
NET-NEW vs REFACTOR:
|
||
- NET-NEW: the region (~205 km) climate tier is new structure. RegionPos + district_to_region/chunk_to_region already exist (server/src/atlas/scale.rs:70/82/91, from T-1077) — addressing skeleton is laid. There is NO RegionProfile/RegionClimate struct, no weather state, and no seasonal clock in the tree today; this ticket introduces them.
|
||
- REFACTOR: derive_temperature_c (server/src/atlas/district_profile.rs:792) currently derives district temperature FROM SCRATCH (D-240 class-envelope latitude lerp + greenhouse nudge + lapse + seed nudge, per district). Split it into (a) a region-baseline fn (latitude + greenhouse + nudge, keeping the D-240 planet_class envelope anchoring) and (b) a district-modulation fn (elevation lapse + slope aspect on top of the baseline) per D-239 §2 — district temperature becomes a MODULATION of the region baseline, not an independent derivation.
|
||
|
||
DOWNSTREAM (no signature change): derive_cover freeze/snow scatter (voxel.rs:1408, reads district.temperature_c at :1417, from T-1030) consumes the post-refactor per-district value as-is.
|
||
|
||
EDGE FUZZ (D-243 §4): climate is a continuous warp-perturbed bilinear blend of surrounding region baselines (+ noise displacement so the boundary is ragged) — the climate counterpart to D-239 §4''s domain warp. Resolved UPSTREAM of build_district_profile, so ChunkContext is unaffected.
|
||
|
||
RELATION TO T-1042 (independent — do NOT share the mechanism): T-1078 blends CLIMATE scalars at the region→district seam (205 km); T-1042 blends TERRAIN scalars at the district→chunk seam (2 km). Separate mechanisms — do NOT reuse ChunkContext.secondary/blend_weight for climate. Both proceed in parallel.
|
||
|
||
Q-105 DEFERRAL: build the static/mean-state region baseline + edge-fuzz blend + the region-clock STRUCTURE. The transient clock-phase callbacks (seasonal frost form/melt, crop-cycle cadence, recompute schedule) are deferred to Q-105 per the two-phase convention already established in the derive_cover docblock (voxel.rs:185-189). This ticket CONTRIBUTES the region-clock toward Q-105; it does not resolve it.
|
||
|
||
FILES: district_profile.rs (split derive_temperature_c; refactor build_district_profile to take a region baseline); new region_profile.rs (RegionProfile/RegionClimate + baseline derivation + edge-fuzz blend); scale.rs (no change — RegionPos/addressing already present); cascade.rs (wire the region tier into the derivation chain). Governing: D-243 §3/§4 (primary), D-239 §2/§3, D-240 (class-envelope anchoring), Q-105 (deferred transient clock).', 'in_progress', 'medium', NULL, 'server', 'D-243', '2026-06-14 19:21:18', '2026-06-15 11:32:21', NULL, '5ee59a431e592e3a700cfbba56f29c15', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ0308CFF9WKNGBBYQ763W', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Cross-region parameter blending at chunk/voxel scale (replace single-profile walking skeleton)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
Implement cross-region parameter blending at the chunk/voxel scale, replacing the walking-skeleton single-profile restriction (server/src/atlas/chunk_context.rs:119-123: ''in the future a blend of adjacent profiles will handle cross-region chunk seams''). Today every voxel generator reads the one covering RegionProfile''s values directly (region.elev_q at voxel.rs:614, :731, :1067-1068; channel/meander params likewise), so continuous parameters step discontinuously at every region-grid border — elevation cliffs at the region pitch, visible as a grid at Atlas/voxel scale.
|
||
|
||
Design is decided — stay inside the D-239 §7 seam policy:
|
||
- NEVER blend morphology family selection. Family seams are prevented at source (gate ordering + build-time compatibility matrix) or kept sharp (cliff-fjord, lithology faults are real geology). Tyre''s cross-family elevation-blend was explicitly resolved against (D-239 dissent line).
|
||
- DO blend continuous positional parameters: elevation, channel width, meander wavelength/phase, freeze/moisture scalars. Mechanism from tile-derivation-contract/tyre-round1.md: ChunkContext gains secondary: Option<RegionProfile> + blend_weight: u8 (255 = fully primary; :123-125), blend zone one chunk (64 m) each side of the region border (:101-102); derive_voxel resolves parameters from both profiles and integer-blends BEFORE material selection (:217-220), reusing the same warp offset so the blend seam cannot align with the chunk edge; elevation sampled bilinearly from the region grid to chunk resolution (:130, the elevation_grid sketch).
|
||
- D-010 discipline: integer blend arithmetic; the f64 path only for position math per D-239 §4.
|
||
|
||
Note: region size in metres is currently ambiguous (see the scale-anchoring Q-record) — the blend can be implemented against the region grid index regardless, but the Q should be resolved before tuning blend-zone width in metres.
|
||
|
||
Acceptance: T-1031 harness cross-region chunk pairs show no elevation step exceeding the lithology-permitted slope (D-239 §8) at region borders; family seams remain sharp; determinism golden-seed unchanged for chunks far from borders. Parent: T-750. Refs: D-239 §4/§7/§8, D-010; Q-102; T-1026/T-1028/T-1029 (predecessors).
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — supersedes the stale code/scale refs above. The original scope was authored 2026-06-12, BEFORE T-1077 landed (RegionProfile→DistrictProfile rename + D-243 re-scale). Design intent unchanged; the references below are the current tree.
|
||
|
||
REFRAME — this is cross-DISTRICT blending, not cross-region. After T-1077 the per-voxel carrier is the DistrictProfile (2,048 m district), so the single-profile "walking skeleton" restriction is a single-DISTRICT-profile restriction and the visible step is at the 2 km district pitch (finer / more visible than the old "region grid" framing). There is no RegionProfile / region.elev_q in the tree anymore.
|
||
|
||
CURRENT REFS (use these):
|
||
- Carrier: server/src/atlas/district_profile.rs (DistrictProfile).
|
||
- The "future blend" TODO: server/src/atlas/chunk_context.rs:166-168 ("in the future a blend of adjacent profiles will handle cross-district chunk seams, but for the walking skeleton one profile is sufficient").
|
||
- Per-voxel elevation reads: server/src/atlas/voxel.rs:443/515/605/723/808/984/1062-1063/1157 (all district.elev_q).
|
||
- channel width / meander wavelength+phase already live ON ChunkContext (precomputed from DistrictProfile) — blend them on the context, do NOT re-read them from the profile in the blend path.
|
||
- derive_chunk_context entry: chunk_context.rs:176. derive_voxel_column entry: voxel.rs:330.
|
||
|
||
SCALE-Q RESOLVED: D-243 fixed district=2,048 m, region=~205 km — the "region size in metres ambiguous" note is obsolete. Q-102 (noise-basis algorithm) stays open but does NOT block blend-zone arithmetic. Blend zone = one chunk (64 m) each side of the district border, against the district grid index.
|
||
|
||
D-243 §4 / D-239 §7 RECONCILIATION (no conflict): D-243 §4''s continuous edge-fuzz mandate governs CLIMATE scalars — that is T-1078''s job. T-1042 blends continuous TERRAIN positional params only: elevation, channel width, meander wavelength/phase, freeze/moisture scalars. Morphology FAMILY selection is NEVER blended — it stays sharp per D-239 §7 (gate ordering + compatibility matrix; cliff-fjord/lithology faults are real geology). The two decisions partition cleanly: family sharp, continuous params feathered.
|
||
|
||
API SHAPE (follow the ticket''s own mechanism): ChunkContext gains `secondary: Option<DistrictProfile>` + `blend_weight: u8` (255 = fully primary). The caller of derive_chunk_context detects a chunk lying within one chunk of a district boundary and supplies the adjacent DistrictProfile; derive_voxel_column reads secondary+blend_weight off ChunkContext and integer-blends (D-010: integer arithmetic; f64 only for position per D-239 §4) BEFORE material selection, reusing the same warp offset so the blend seam cannot align with the chunk edge. No new parameter on derive_voxel_column — it reads the context.
|
||
|
||
ACCEPTANCE (concrete): add a cross-district chunk-pair test to server/tests/derivation_harness.rs (alongside channel_continuous_across_chunk_boundary_far_from_origin:1054). Pass condition — the elevation step across a district seam is no larger than the typical step between adjacent INTERIOR chunks within a district (i.e. the seam is invisible — operationalizes D-243 "the grid must be invisible"); morphology family seams remain sharp; golden-seed determinism unchanged for chunks far from any district border. No fixed metre threshold (D-239 §8 is qualitative per lithology) — assert continuity relative to interior variation, not an absolute bound.', 'in_progress', 'medium', NULL, 'server', 'D-239', '2026-06-12 10:23:50', '2026-06-15 11:32:21', NULL, 'a6d1c442e8f9b428633f40440a4a7695', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXP19FFZEVED140S1708W', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Wire the Region→Chunk→Voxel tier into production — ChunkPos→RegionPos mapping, proxy layers, Atlas surfacing', '(description follows in first append)
|
||
|
||
---
|
||
Q-110 resolved (2026-06-14) -> D-243. Scope item (1) ChunkPos->RegionPos is now defined: the D-243 absolute ladder is voxel(1m)->chunk(64m)->block(128m)->quarter(512m)->district(2km)->region(~205km), with a single elastic seam region<->planet (round(2*pi*R/204.8km) regions per body from body_radius_km). ChunkPos->district->region is fixed integer math; only region->heightmap-sample is body-specific.
|
||
|
||
Prerequisite: T-1077 re-scales the code to this ladder (the current ~1km RegionProfile moves onto the 2km district; the region becomes the new 205km top hard block) — T-1046 now blocked by T-1077. Climate/weather lockdown + edge fuzz on the region is T-1078. Once T-1077 lands, T-1046 is the production wiring (proxy layers + Atlas surfacing) over a ladder whose scale is finally coherent.
|
||
|
||
---
|
||
Implementation (2026-06-15) — the derived tier is now VISIBLE in the Atlas.
|
||
|
||
(1) ChunkPos->RegionPos: done in scale.rs (T-1077) — fixed integer addressing.
|
||
(2) Proxy serves the tier (d03b4d1e0): AtlasLayerResponse gains DistrictGridLayer (cols/rows + row-major MorphologyZone discriminants + elev_q) via build_district_grid(); populated on cache hit. rmp_serde msgpack flows it to the client automatically.
|
||
(3) Atlas surfacing (cfd5e18d0): protocol.gd decodes district_grid; atlas_viewer.gd adds the gen_district (''MRPH'') toggle + state; atlas_marker_overlay.gd paints the coarse grid coloured by morphology zone (17-zone palette, D-239 §6). gdUnit4 test green.
|
||
|
||
SCOPE NOTE: this surfaces the PLANETARY-SCALE coarse morphology grid — the Atlas map view of the derived tier (the audit headline: "the Atlas cannot show the tiers that exist" is resolved). The on-demand 2km derive_district + per-voxel geometry (T-1077) are for IN-WORLD Phase 5 rendering, NOT the planetary map; "voxel layers in the proxy" from the original audit scope belongs to Phase 5, not here.
|
||
|
||
Status -> review. Visual palette tuning can follow once eyeballed in the running Atlas (the map now renders the morphology overlay over real bodies).', 'done', 'high', NULL, 'server', 'D-239', '2026-06-12 10:40:58', '2026-06-15 11:32:22', NULL, '4e3bf92ba623a3aa5717429ef13543bd', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCF56ED5ZJZRXFMF3PNSNZF0', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Region climate stack — weather/season/temperature baseline + district modulation + edge fuzz', 'Per D-243 §3/§4 (refines D-239 §2; contributes the region-clock toward Q-105).
|
||
|
||
Three-level climate stack:
|
||
- REGION (~205km): the climate context — latitude-driven temperature baseline, weather state, seasonal clock. Resolved ONCE per region (the Q-105 cheap-dynamism source); inherited by every district/tile inside. ''Region temperature'' = context, not a uniform slab.
|
||
- DISTRICT (2km): local temperature = region baseline + elevation lapse + slope aspect (D-239 §2''s district temperature, now a MODULATION of the region rather than derived from scratch).
|
||
- CHUNK/VOXEL: D-239 §3 freeze/snow scatter on the local temperature.
|
||
|
||
EDGE FUZZ (D-243 §4): climate does not change on a line. A tile''s climate is a continuous warp-perturbed blend of surrounding regions'' baselines (bilinear across region centres + noise displacement so the boundary is ragged); same at district edges. The region/district grid must be invisible in the output. This is the climate counterpart to D-239 §4''s domain warp — climate is feathered/blended (continuous field), unlike morphology which stays sharp-but-organic (D-239 §7).
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — READY. Implementer brief against the current tree (post-T-1077).
|
||
|
||
NET-NEW vs REFACTOR:
|
||
- NET-NEW: the region (~205 km) climate tier is new structure. RegionPos + district_to_region/chunk_to_region already exist (server/src/atlas/scale.rs:70/82/91, from T-1077) — addressing skeleton is laid. There is NO RegionProfile/RegionClimate struct, no weather state, and no seasonal clock in the tree today; this ticket introduces them.
|
||
- REFACTOR: derive_temperature_c (server/src/atlas/district_profile.rs:792) currently derives district temperature FROM SCRATCH (D-240 class-envelope latitude lerp + greenhouse nudge + lapse + seed nudge, per district). Split it into (a) a region-baseline fn (latitude + greenhouse + nudge, keeping the D-240 planet_class envelope anchoring) and (b) a district-modulation fn (elevation lapse + slope aspect on top of the baseline) per D-239 §2 — district temperature becomes a MODULATION of the region baseline, not an independent derivation.
|
||
|
||
DOWNSTREAM (no signature change): derive_cover freeze/snow scatter (voxel.rs:1408, reads district.temperature_c at :1417, from T-1030) consumes the post-refactor per-district value as-is.
|
||
|
||
EDGE FUZZ (D-243 §4): climate is a continuous warp-perturbed bilinear blend of surrounding region baselines (+ noise displacement so the boundary is ragged) — the climate counterpart to D-239 §4''s domain warp. Resolved UPSTREAM of build_district_profile, so ChunkContext is unaffected.
|
||
|
||
RELATION TO T-1042 (independent — do NOT share the mechanism): T-1078 blends CLIMATE scalars at the region→district seam (205 km); T-1042 blends TERRAIN scalars at the district→chunk seam (2 km). Separate mechanisms — do NOT reuse ChunkContext.secondary/blend_weight for climate. Both proceed in parallel.
|
||
|
||
Q-105 DEFERRAL: build the static/mean-state region baseline + edge-fuzz blend + the region-clock STRUCTURE. The transient clock-phase callbacks (seasonal frost form/melt, crop-cycle cadence, recompute schedule) are deferred to Q-105 per the two-phase convention already established in the derive_cover docblock (voxel.rs:185-189). This ticket CONTRIBUTES the region-clock toward Q-105; it does not resolve it.
|
||
|
||
FILES: district_profile.rs (split derive_temperature_c; refactor build_district_profile to take a region baseline); new region_profile.rs (RegionProfile/RegionClimate + baseline derivation + edge-fuzz blend); scale.rs (no change — RegionPos/addressing already present); cascade.rs (wire the region tier into the derivation chain). Governing: D-243 §3/§4 (primary), D-239 §2/§3, D-240 (class-envelope anchoring), Q-105 (deferred transient clock).', 'review', 'medium', NULL, 'server', 'D-243', '2026-06-14 19:21:18', '2026-06-15 12:05:57', NULL, '2694bf9b555dbdd497774a82bb0b48bc', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ0308CFF9WKNGBBYQ763W', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Cross-region parameter blending at chunk/voxel scale (replace single-profile walking skeleton)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
Implement cross-region parameter blending at the chunk/voxel scale, replacing the walking-skeleton single-profile restriction (server/src/atlas/chunk_context.rs:119-123: ''in the future a blend of adjacent profiles will handle cross-region chunk seams''). Today every voxel generator reads the one covering RegionProfile''s values directly (region.elev_q at voxel.rs:614, :731, :1067-1068; channel/meander params likewise), so continuous parameters step discontinuously at every region-grid border — elevation cliffs at the region pitch, visible as a grid at Atlas/voxel scale.
|
||
|
||
Design is decided — stay inside the D-239 §7 seam policy:
|
||
- NEVER blend morphology family selection. Family seams are prevented at source (gate ordering + build-time compatibility matrix) or kept sharp (cliff-fjord, lithology faults are real geology). Tyre''s cross-family elevation-blend was explicitly resolved against (D-239 dissent line).
|
||
- DO blend continuous positional parameters: elevation, channel width, meander wavelength/phase, freeze/moisture scalars. Mechanism from tile-derivation-contract/tyre-round1.md: ChunkContext gains secondary: Option<RegionProfile> + blend_weight: u8 (255 = fully primary; :123-125), blend zone one chunk (64 m) each side of the region border (:101-102); derive_voxel resolves parameters from both profiles and integer-blends BEFORE material selection (:217-220), reusing the same warp offset so the blend seam cannot align with the chunk edge; elevation sampled bilinearly from the region grid to chunk resolution (:130, the elevation_grid sketch).
|
||
- D-010 discipline: integer blend arithmetic; the f64 path only for position math per D-239 §4.
|
||
|
||
Note: region size in metres is currently ambiguous (see the scale-anchoring Q-record) — the blend can be implemented against the region grid index regardless, but the Q should be resolved before tuning blend-zone width in metres.
|
||
|
||
Acceptance: T-1031 harness cross-region chunk pairs show no elevation step exceeding the lithology-permitted slope (D-239 §8) at region borders; family seams remain sharp; determinism golden-seed unchanged for chunks far from borders. Parent: T-750. Refs: D-239 §4/§7/§8, D-010; Q-102; T-1026/T-1028/T-1029 (predecessors).
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — supersedes the stale code/scale refs above. The original scope was authored 2026-06-12, BEFORE T-1077 landed (RegionProfile→DistrictProfile rename + D-243 re-scale). Design intent unchanged; the references below are the current tree.
|
||
|
||
REFRAME — this is cross-DISTRICT blending, not cross-region. After T-1077 the per-voxel carrier is the DistrictProfile (2,048 m district), so the single-profile "walking skeleton" restriction is a single-DISTRICT-profile restriction and the visible step is at the 2 km district pitch (finer / more visible than the old "region grid" framing). There is no RegionProfile / region.elev_q in the tree anymore.
|
||
|
||
CURRENT REFS (use these):
|
||
- Carrier: server/src/atlas/district_profile.rs (DistrictProfile).
|
||
- The "future blend" TODO: server/src/atlas/chunk_context.rs:166-168 ("in the future a blend of adjacent profiles will handle cross-district chunk seams, but for the walking skeleton one profile is sufficient").
|
||
- Per-voxel elevation reads: server/src/atlas/voxel.rs:443/515/605/723/808/984/1062-1063/1157 (all district.elev_q).
|
||
- channel width / meander wavelength+phase already live ON ChunkContext (precomputed from DistrictProfile) — blend them on the context, do NOT re-read them from the profile in the blend path.
|
||
- derive_chunk_context entry: chunk_context.rs:176. derive_voxel_column entry: voxel.rs:330.
|
||
|
||
SCALE-Q RESOLVED: D-243 fixed district=2,048 m, region=~205 km — the "region size in metres ambiguous" note is obsolete. Q-102 (noise-basis algorithm) stays open but does NOT block blend-zone arithmetic. Blend zone = one chunk (64 m) each side of the district border, against the district grid index.
|
||
|
||
D-243 §4 / D-239 §7 RECONCILIATION (no conflict): D-243 §4''s continuous edge-fuzz mandate governs CLIMATE scalars — that is T-1078''s job. T-1042 blends continuous TERRAIN positional params only: elevation, channel width, meander wavelength/phase, freeze/moisture scalars. Morphology FAMILY selection is NEVER blended — it stays sharp per D-239 §7 (gate ordering + compatibility matrix; cliff-fjord/lithology faults are real geology). The two decisions partition cleanly: family sharp, continuous params feathered.
|
||
|
||
API SHAPE (follow the ticket''s own mechanism): ChunkContext gains `secondary: Option<DistrictProfile>` + `blend_weight: u8` (255 = fully primary). The caller of derive_chunk_context detects a chunk lying within one chunk of a district boundary and supplies the adjacent DistrictProfile; derive_voxel_column reads secondary+blend_weight off ChunkContext and integer-blends (D-010: integer arithmetic; f64 only for position per D-239 §4) BEFORE material selection, reusing the same warp offset so the blend seam cannot align with the chunk edge. No new parameter on derive_voxel_column — it reads the context.
|
||
|
||
ACCEPTANCE (concrete): add a cross-district chunk-pair test to server/tests/derivation_harness.rs (alongside channel_continuous_across_chunk_boundary_far_from_origin:1054). Pass condition — the elevation step across a district seam is no larger than the typical step between adjacent INTERIOR chunks within a district (i.e. the seam is invisible — operationalizes D-243 "the grid must be invisible"); morphology family seams remain sharp; golden-seed determinism unchanged for chunks far from any district border. No fixed metre threshold (D-239 §8 is qualitative per lithology) — assert continuity relative to interior variation, not an absolute bound.', 'review', 'medium', NULL, 'server', 'D-239', '2026-06-12 10:23:50', '2026-06-15 12:05:57', NULL, 'd61b0595ecc6d66929b7ecabf32a6d63', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ0308CFF9WKNGBBYQ763W', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Cross-region parameter blending at chunk/voxel scale (replace single-profile walking skeleton)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
Implement cross-region parameter blending at the chunk/voxel scale, replacing the walking-skeleton single-profile restriction (server/src/atlas/chunk_context.rs:119-123: ''in the future a blend of adjacent profiles will handle cross-region chunk seams''). Today every voxel generator reads the one covering RegionProfile''s values directly (region.elev_q at voxel.rs:614, :731, :1067-1068; channel/meander params likewise), so continuous parameters step discontinuously at every region-grid border — elevation cliffs at the region pitch, visible as a grid at Atlas/voxel scale.
|
||
|
||
Design is decided — stay inside the D-239 §7 seam policy:
|
||
- NEVER blend morphology family selection. Family seams are prevented at source (gate ordering + build-time compatibility matrix) or kept sharp (cliff-fjord, lithology faults are real geology). Tyre''s cross-family elevation-blend was explicitly resolved against (D-239 dissent line).
|
||
- DO blend continuous positional parameters: elevation, channel width, meander wavelength/phase, freeze/moisture scalars. Mechanism from tile-derivation-contract/tyre-round1.md: ChunkContext gains secondary: Option<RegionProfile> + blend_weight: u8 (255 = fully primary; :123-125), blend zone one chunk (64 m) each side of the region border (:101-102); derive_voxel resolves parameters from both profiles and integer-blends BEFORE material selection (:217-220), reusing the same warp offset so the blend seam cannot align with the chunk edge; elevation sampled bilinearly from the region grid to chunk resolution (:130, the elevation_grid sketch).
|
||
- D-010 discipline: integer blend arithmetic; the f64 path only for position math per D-239 §4.
|
||
|
||
Note: region size in metres is currently ambiguous (see the scale-anchoring Q-record) — the blend can be implemented against the region grid index regardless, but the Q should be resolved before tuning blend-zone width in metres.
|
||
|
||
Acceptance: T-1031 harness cross-region chunk pairs show no elevation step exceeding the lithology-permitted slope (D-239 §8) at region borders; family seams remain sharp; determinism golden-seed unchanged for chunks far from borders. Parent: T-750. Refs: D-239 §4/§7/§8, D-010; Q-102; T-1026/T-1028/T-1029 (predecessors).
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — supersedes the stale code/scale refs above. The original scope was authored 2026-06-12, BEFORE T-1077 landed (RegionProfile→DistrictProfile rename + D-243 re-scale). Design intent unchanged; the references below are the current tree.
|
||
|
||
REFRAME — this is cross-DISTRICT blending, not cross-region. After T-1077 the per-voxel carrier is the DistrictProfile (2,048 m district), so the single-profile "walking skeleton" restriction is a single-DISTRICT-profile restriction and the visible step is at the 2 km district pitch (finer / more visible than the old "region grid" framing). There is no RegionProfile / region.elev_q in the tree anymore.
|
||
|
||
CURRENT REFS (use these):
|
||
- Carrier: server/src/atlas/district_profile.rs (DistrictProfile).
|
||
- The "future blend" TODO: server/src/atlas/chunk_context.rs:166-168 ("in the future a blend of adjacent profiles will handle cross-district chunk seams, but for the walking skeleton one profile is sufficient").
|
||
- Per-voxel elevation reads: server/src/atlas/voxel.rs:443/515/605/723/808/984/1062-1063/1157 (all district.elev_q).
|
||
- channel width / meander wavelength+phase already live ON ChunkContext (precomputed from DistrictProfile) — blend them on the context, do NOT re-read them from the profile in the blend path.
|
||
- derive_chunk_context entry: chunk_context.rs:176. derive_voxel_column entry: voxel.rs:330.
|
||
|
||
SCALE-Q RESOLVED: D-243 fixed district=2,048 m, region=~205 km — the "region size in metres ambiguous" note is obsolete. Q-102 (noise-basis algorithm) stays open but does NOT block blend-zone arithmetic. Blend zone = one chunk (64 m) each side of the district border, against the district grid index.
|
||
|
||
D-243 §4 / D-239 §7 RECONCILIATION (no conflict): D-243 §4''s continuous edge-fuzz mandate governs CLIMATE scalars — that is T-1078''s job. T-1042 blends continuous TERRAIN positional params only: elevation, channel width, meander wavelength/phase, freeze/moisture scalars. Morphology FAMILY selection is NEVER blended — it stays sharp per D-239 §7 (gate ordering + compatibility matrix; cliff-fjord/lithology faults are real geology). The two decisions partition cleanly: family sharp, continuous params feathered.
|
||
|
||
API SHAPE (follow the ticket''s own mechanism): ChunkContext gains `secondary: Option<DistrictProfile>` + `blend_weight: u8` (255 = fully primary). The caller of derive_chunk_context detects a chunk lying within one chunk of a district boundary and supplies the adjacent DistrictProfile; derive_voxel_column reads secondary+blend_weight off ChunkContext and integer-blends (D-010: integer arithmetic; f64 only for position per D-239 §4) BEFORE material selection, reusing the same warp offset so the blend seam cannot align with the chunk edge. No new parameter on derive_voxel_column — it reads the context.
|
||
|
||
ACCEPTANCE (concrete): add a cross-district chunk-pair test to server/tests/derivation_harness.rs (alongside channel_continuous_across_chunk_boundary_far_from_origin:1054). Pass condition — the elevation step across a district seam is no larger than the typical step between adjacent INTERIOR chunks within a district (i.e. the seam is invisible — operationalizes D-243 "the grid must be invisible"); morphology family seams remain sharp; golden-seed determinism unchanged for chunks far from any district border. No fixed metre threshold (D-239 §8 is qualitative per lithology) — assert continuity relative to interior variation, not an absolute bound.', 'done', 'medium', NULL, 'server', 'D-239', '2026-06-12 10:23:50', '2026-06-15 15:42:21', NULL, 'c91397fc200682ad0f6122ab54b877db', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCF56ED5ZJZRXFMF3PNSNZF0', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Region climate stack — weather/season/temperature baseline + district modulation + edge fuzz', 'Per D-243 §3/§4 (refines D-239 §2; contributes the region-clock toward Q-105).
|
||
|
||
Three-level climate stack:
|
||
- REGION (~205km): the climate context — latitude-driven temperature baseline, weather state, seasonal clock. Resolved ONCE per region (the Q-105 cheap-dynamism source); inherited by every district/tile inside. ''Region temperature'' = context, not a uniform slab.
|
||
- DISTRICT (2km): local temperature = region baseline + elevation lapse + slope aspect (D-239 §2''s district temperature, now a MODULATION of the region rather than derived from scratch).
|
||
- CHUNK/VOXEL: D-239 §3 freeze/snow scatter on the local temperature.
|
||
|
||
EDGE FUZZ (D-243 §4): climate does not change on a line. A tile''s climate is a continuous warp-perturbed blend of surrounding regions'' baselines (bilinear across region centres + noise displacement so the boundary is ragged); same at district edges. The region/district grid must be invisible in the output. This is the climate counterpart to D-239 §4''s domain warp — climate is feathered/blended (continuous field), unlike morphology which stays sharp-but-organic (D-239 §7).
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — READY. Implementer brief against the current tree (post-T-1077).
|
||
|
||
NET-NEW vs REFACTOR:
|
||
- NET-NEW: the region (~205 km) climate tier is new structure. RegionPos + district_to_region/chunk_to_region already exist (server/src/atlas/scale.rs:70/82/91, from T-1077) — addressing skeleton is laid. There is NO RegionProfile/RegionClimate struct, no weather state, and no seasonal clock in the tree today; this ticket introduces them.
|
||
- REFACTOR: derive_temperature_c (server/src/atlas/district_profile.rs:792) currently derives district temperature FROM SCRATCH (D-240 class-envelope latitude lerp + greenhouse nudge + lapse + seed nudge, per district). Split it into (a) a region-baseline fn (latitude + greenhouse + nudge, keeping the D-240 planet_class envelope anchoring) and (b) a district-modulation fn (elevation lapse + slope aspect on top of the baseline) per D-239 §2 — district temperature becomes a MODULATION of the region baseline, not an independent derivation.
|
||
|
||
DOWNSTREAM (no signature change): derive_cover freeze/snow scatter (voxel.rs:1408, reads district.temperature_c at :1417, from T-1030) consumes the post-refactor per-district value as-is.
|
||
|
||
EDGE FUZZ (D-243 §4): climate is a continuous warp-perturbed bilinear blend of surrounding region baselines (+ noise displacement so the boundary is ragged) — the climate counterpart to D-239 §4''s domain warp. Resolved UPSTREAM of build_district_profile, so ChunkContext is unaffected.
|
||
|
||
RELATION TO T-1042 (independent — do NOT share the mechanism): T-1078 blends CLIMATE scalars at the region→district seam (205 km); T-1042 blends TERRAIN scalars at the district→chunk seam (2 km). Separate mechanisms — do NOT reuse ChunkContext.secondary/blend_weight for climate. Both proceed in parallel.
|
||
|
||
Q-105 DEFERRAL: build the static/mean-state region baseline + edge-fuzz blend + the region-clock STRUCTURE. The transient clock-phase callbacks (seasonal frost form/melt, crop-cycle cadence, recompute schedule) are deferred to Q-105 per the two-phase convention already established in the derive_cover docblock (voxel.rs:185-189). This ticket CONTRIBUTES the region-clock toward Q-105; it does not resolve it.
|
||
|
||
FILES: district_profile.rs (split derive_temperature_c; refactor build_district_profile to take a region baseline); new region_profile.rs (RegionProfile/RegionClimate + baseline derivation + edge-fuzz blend); scale.rs (no change — RegionPos/addressing already present); cascade.rs (wire the region tier into the derivation chain). Governing: D-243 §3/§4 (primary), D-239 §2/§3, D-240 (class-envelope anchoring), Q-105 (deferred transient clock).', 'done', 'medium', NULL, 'server', 'D-243', '2026-06-14 19:21:18', '2026-06-15 15:42:21', NULL, 'd89530be1679ff1513ed790d838f216c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ02KN9147H4Z12KJW7H1M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Thread political_archetype / arrangement_pattern / morphology_zone through the L3→L4 GenerateSkeleton dispatch', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
Thread the remaining Layer-3 character fields through the L3->L4 GenerateSkeleton dispatch. T-1022 wired the dispatch, but build_skeleton_work_item (server/src/atlas/plugin.rs:179-212) overrides only founding_orientation (:192-193); political_archetype stays the Commission stub (city_context_reader.rs:471-474) and morphology_zone stays AlluvialPlain (:487-488) even though:
|
||
- CityPlacement already carries the real political_archetype (D-214, derived from TerritorialStatus + economic_role at attractor_matching.rs:595-602) and arrangement_pattern (D-215, city_character at :282-293) — fields :49-64;
|
||
- the covering region''s real morphology_zone (D-239 §6 frozen vocab, T-1027, region_profile.rs:180/:499) is available from snapshot.layer_region, populated in the same cascade run (cascade.rs:238-240) — map placement.position to its covering region cell.
|
||
|
||
Consequences of the stubs: skeleton_gen''s morphology gating (D-234a Topology selection) always takes the AlluvialPlain Prim-MST mesh path — fjord/delta cities get plains street networks; block_irregularity/layout-mode always sees Commission (skeleton_gen.rs:68-77). D-234''s implementation note explicitly lists this threading as the pending dependency of the (done, tested, dormant) morphology-gated street rules.
|
||
|
||
Also decide arrangement_pattern''s path: CityGenerationContext has NO arrangement_pattern field (generator.rs:1078 has political_archetype only; ArrangementPattern :442 is defined but unconsumed at L4). Either (a) add the field and have skeleton_gen consume the D-215 explicit pattern, or (b) record that L4 derives layout from archetype alone and the placement''s pattern is Atlas/UI-only. Option (a) matches the workshop intent (ozzie-round1.md:112-118 backs explicit arrangement).
|
||
|
||
Miri''s queryability requirement (tile-derivation-contract/tyre-round1.md:308-311) — morphology_zone readable at Atlas-generation time — is satisfied by reading from BodyWorldState regions, no recompute.
|
||
|
||
Acceptance: dispatch a body with a FjordWall-region coastal placement in a CorpTerritory province -> the generated quarter uses Ribbon topology and CompanyTown-class layout, not mesh+Commission. Parent: T-750. Refs: D-214, D-215, D-228, D-234, D-239 §6; T-1022 (predecessor), T-983, T-1014 (adjacent, different fields).
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — READY. Supersedes stale region-scale refs (authored 2026-06-12, pre-T-1077 RegionProfile->DistrictProfile rename + T-1078). Current tree:
|
||
|
||
MORPHOLOGY CARRIER MOVED: morphology_zone now lives on DistrictProfile.morphology_zone (district_profile.rs:193, 2km carrier), NOT region_profile.rs. Snapshot field is layer_district (not layer_region — gone); map is BodyWorldState.districts (body_world_state.rs:102), populated by cascade (cascade.rs:270, converted :110-126). The ticket''s snapshot.layer_region / region_profile.rs:180/:499 / "covering region" refs are stale.
|
||
|
||
PLACEMENT->DISTRICT MAPPING: CityPlacement.position is heightmap pixel (row,col) (u16,u16) (attractor_matching.rs:51). DistrictPos = position / CELLS_PER_DISTRICT (8). No helper yet — add inline. Inverse at district_profile.rs:1023-1026.
|
||
|
||
STUB SITES: political_archetype stub city_context_reader.rs:474 (Commission); morphology_zone stub :488 (AlluvialPlain); both in context_from_read_set() (:462). build_skeleton_work_item (plugin.rs:180-213) threads only founding_orientation (:194) and does NOT receive the districts map — pass &state.districts in (available in the GenCompletion::BodyAnalyzed arm, plugin.rs:101) or resolve before the call; fallback AlluvialPlain on miss.
|
||
|
||
THREE OVERRIDES:
|
||
- political_archetype: one-liner — context.political_archetype = placement.political_archetype (real D-214 value, attractor_matching.rs:58/:602), parallel to founding_orientation at plugin.rs:194.
|
||
- morphology_zone: state.districts.get(&(pos.0/8, pos.1/8)).map(|d| d.morphology_zone).unwrap_or(AlluvialPlain).
|
||
- arrangement_pattern: OPTION (a) (D-215-backed) — CityGenerationContext has NO arrangement_pattern field (generator.rs:1098-1124); add it, thread placement.arrangement_pattern (attractor_matching.rs:60/:629), have skeleton_gen consume it (doesn''t yet).
|
||
|
||
CONSUMERS LIVE-BUT-DORMANT: street_topology() (skeleton_gen.rs:1048) gates on MorphologyZone (Ribbon: Fjord/CliffCoast/MountainPass/Alpine/ValleyFloor; HubSpoke: Delta/Estuarine/OpenOcean/Lake/DuneStrand/TidalFlat; Mesh: AlluvialPlain/MeanderReach/RiverBank/BraidedPlain/Wetland/Volcanic); derive_layout_mode (:235)+block_irregularity (:68) gate on political_archetype. T-989/T-990 done — always get AlluvialPlain+Commission until this lands.
|
||
|
||
ACCEPTANCE: FjordWall-region coastal placement in CorpTerritory -> Ribbon topology + CompanyTown/CampusGrid layout, not mesh+Commission.
|
||
|
||
Governing: D-234 (primary), D-214, D-215 (-> option a), D-239 sec 6 (frozen vocab, now district_profile.rs), D-243.
|
||
|
||
OVERLAP w/ T-1043: both edit build_skeleton_work_item (plugin.rs), city_context_reader.rs, CityGenerationContext (generator.rs), skeleton_gen consumers. Implement together in ONE pass (one agent), not parallel.', 'backlog', 'high', NULL, 'server', 'D-234', '2026-06-12 10:23:49', '2026-06-15 15:59:03', NULL, '85b17213041c195d9aab9a7d8a1e6885', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ034DKN4ENSGX5HTYTBJG', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Derive road_entry_directions at L3 and thread through the dispatch (interim: MST-neighbor bearings + water_bearing)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
Derive road_entry_directions at Layer 3 and thread them through the GenerateSkeleton dispatch. CityGenerationContext.road_entry_directions (server/src/simulation/generator.rs:1083-1084, compass octants 0=N..7=NW) is stubbed empty (city_context_reader.rs:478-479) and never overridden by the T-1022 dispatch, so derive_access_points (skeleton_gen.rs:1008-1036) never emits QuarterEdge access nodes — every quarter falls back to reservation gates or a single central BlockJunction (:1029-1034), and the D-234 arterial graph has no outward connection to the world.
|
||
|
||
Workshop contract: the field is a per-city output of the inter-settlement road graph (generation-cascade/round-3-notes.md:104 ''Layer C: Road graph (road_entry_directions per city)''; burnelli-sheldon-round4.md:308). Full-fidelity derivation therefore lands with the inter-settlement-transport ticket: octant = bearing of each connecting road edge where it crosses the city footprint radius (D-204 footprint), de-duplicated per octant, retaining per-entry quality for the consumer rule below.
|
||
|
||
Interim derivation (no road graph required, deterministic, replace-don''t-rework): derive octants at L3 from (a) bearings to the settlement''s MST-neighbor placements (positions already in BodyWorldState.placements) and (b) the founding-orientation water bearing (TerrainAnalysis::water_bearing, 8-octant integer — D-234 implementation note) for port/river settlements. Thread through build_skeleton_work_item (plugin.rs:179-212) next to the founding_orientation override.
|
||
|
||
Consumer rule to honour (already decided): the AdminFacing arrangement pattern picks its prestige edge as the edge facing the highest-quality road entry (paula-round2.md:428-433, paula-round3.md:320-322) — so the octant list should be ordered or annotated by quality once the graph exists. Player-experience intent: the approach should present the city''s FoundingOrientation face (ozzie-round1.md:96-100).
|
||
|
||
Acceptance: a dispatched settlement with >=1 neighbor produces >=1 AccessKind::QuarterEdge node on the correct octant; the BlockJunction fallback fires only for genuinely isolated settlements. Parent: T-750. Blocked-by (soft): inter-settlement-transport ticket for full fidelity. Refs: D-234, D-213, D-204; T-990 (consumer, done), T-1022 (dispatch, done).
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — READY, with a SCOPE UPDATE. The "interim: MST-neighbor bearings" framing in the title is now obsolete.
|
||
|
||
T-1038 ROAD GRAPH HAS SHIPPED — go full-fidelity, skip the interim. The inter-settlement road graph is live in the tree: road_graph.rs exists; the cascade runs CascadeLayer::RoadGraph (gen_queue.rs:383); BodyWorldState.road_graph (body_world_state.rs:91) is populated BEFORE GenCompletion::BodyAnalyzed fires, so at L3->L4 dispatch (plugin.rs:99-133) state.road_graph is already live. Therefore do NOT implement the MST-neighbor approximation — derive octants directly from state.road_graph.edges for the city''s node (match by RoadNode.city_id), bearing = city.position -> neighbor.position, octant = bearing_deg / 45. (NB: T-1038''s ticket still shows in_progress though its code shipped — consume the live road_graph regardless; flag if road_graph turns out not fully populated for some bodies.)
|
||
|
||
CURRENT REFS: CityGenerationContext.road_entry_directions = generator.rs:1107 (Vec<u8>, octants 0=N..7=NW); empty stub city_context_reader.rs:479; derive_access_points skeleton_gen.rs:1008-1035; BlockJunction fallback :1029-1034; build_skeleton_work_item plugin.rs:180-213 (insert next to the founding_orientation override at :194).
|
||
|
||
ISOLATED SETTLEMENTS (no road_graph edges): take the water bearing from placement.founding_orientation — Coastal{facing_degrees} / RiverAligned{bearing_degrees} already encode it (octant = degrees/45). Note TerrainAnalysis::water_bearing (features.rs:133, u16 deg, 360=none) is NOT stored on CityPlacement/BodyWorldState, so reading founding_orientation is the clean access path (no attractor position-match needed).
|
||
|
||
CONSUMER: T-990 (done) emits AccessKind::QuarterEdge per octant in derive_access_points. The AdminFacing prestige-edge rule (pick the edge facing the highest-quality road entry) is forward-looking — no AdminFacing code exists yet — so order/annotate octants by quality only once that consumer lands.
|
||
|
||
ACCEPTANCE: a dispatched settlement whose city_id has >=1 road_graph edge emits >=1 AccessKind::QuarterEdge on the matching octant; BlockJunction fallback fires only for genuinely isolated settlements.
|
||
|
||
Governing: D-234, D-213, D-204 (footprint radius). T-990 (consumer, done), T-1022 (dispatch, done), T-1038 (road graph, shipped).
|
||
|
||
OVERLAP w/ T-1039: both edit build_skeleton_work_item (plugin.rs), city_context_reader.rs, CityGenerationContext (generator.rs). Implement both in ONE pass (one agent), not parallel.', 'backlog', 'medium', NULL, 'server', 'D-234', '2026-06-12 10:23:50', '2026-06-15 15:59:03', NULL, 'd59a1581909e78cdfd4961c1ce54c48e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ02KN9147H4Z12KJW7H1M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Thread political_archetype / arrangement_pattern / morphology_zone through the L3→L4 GenerateSkeleton dispatch', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
Thread the remaining Layer-3 character fields through the L3->L4 GenerateSkeleton dispatch. T-1022 wired the dispatch, but build_skeleton_work_item (server/src/atlas/plugin.rs:179-212) overrides only founding_orientation (:192-193); political_archetype stays the Commission stub (city_context_reader.rs:471-474) and morphology_zone stays AlluvialPlain (:487-488) even though:
|
||
- CityPlacement already carries the real political_archetype (D-214, derived from TerritorialStatus + economic_role at attractor_matching.rs:595-602) and arrangement_pattern (D-215, city_character at :282-293) — fields :49-64;
|
||
- the covering region''s real morphology_zone (D-239 §6 frozen vocab, T-1027, region_profile.rs:180/:499) is available from snapshot.layer_region, populated in the same cascade run (cascade.rs:238-240) — map placement.position to its covering region cell.
|
||
|
||
Consequences of the stubs: skeleton_gen''s morphology gating (D-234a Topology selection) always takes the AlluvialPlain Prim-MST mesh path — fjord/delta cities get plains street networks; block_irregularity/layout-mode always sees Commission (skeleton_gen.rs:68-77). D-234''s implementation note explicitly lists this threading as the pending dependency of the (done, tested, dormant) morphology-gated street rules.
|
||
|
||
Also decide arrangement_pattern''s path: CityGenerationContext has NO arrangement_pattern field (generator.rs:1078 has political_archetype only; ArrangementPattern :442 is defined but unconsumed at L4). Either (a) add the field and have skeleton_gen consume the D-215 explicit pattern, or (b) record that L4 derives layout from archetype alone and the placement''s pattern is Atlas/UI-only. Option (a) matches the workshop intent (ozzie-round1.md:112-118 backs explicit arrangement).
|
||
|
||
Miri''s queryability requirement (tile-derivation-contract/tyre-round1.md:308-311) — morphology_zone readable at Atlas-generation time — is satisfied by reading from BodyWorldState regions, no recompute.
|
||
|
||
Acceptance: dispatch a body with a FjordWall-region coastal placement in a CorpTerritory province -> the generated quarter uses Ribbon topology and CompanyTown-class layout, not mesh+Commission. Parent: T-750. Refs: D-214, D-215, D-228, D-234, D-239 §6; T-1022 (predecessor), T-983, T-1014 (adjacent, different fields).
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — READY. Supersedes stale region-scale refs (authored 2026-06-12, pre-T-1077 RegionProfile->DistrictProfile rename + T-1078). Current tree:
|
||
|
||
MORPHOLOGY CARRIER MOVED: morphology_zone now lives on DistrictProfile.morphology_zone (district_profile.rs:193, 2km carrier), NOT region_profile.rs. Snapshot field is layer_district (not layer_region — gone); map is BodyWorldState.districts (body_world_state.rs:102), populated by cascade (cascade.rs:270, converted :110-126). The ticket''s snapshot.layer_region / region_profile.rs:180/:499 / "covering region" refs are stale.
|
||
|
||
PLACEMENT->DISTRICT MAPPING: CityPlacement.position is heightmap pixel (row,col) (u16,u16) (attractor_matching.rs:51). DistrictPos = position / CELLS_PER_DISTRICT (8). No helper yet — add inline. Inverse at district_profile.rs:1023-1026.
|
||
|
||
STUB SITES: political_archetype stub city_context_reader.rs:474 (Commission); morphology_zone stub :488 (AlluvialPlain); both in context_from_read_set() (:462). build_skeleton_work_item (plugin.rs:180-213) threads only founding_orientation (:194) and does NOT receive the districts map — pass &state.districts in (available in the GenCompletion::BodyAnalyzed arm, plugin.rs:101) or resolve before the call; fallback AlluvialPlain on miss.
|
||
|
||
THREE OVERRIDES:
|
||
- political_archetype: one-liner — context.political_archetype = placement.political_archetype (real D-214 value, attractor_matching.rs:58/:602), parallel to founding_orientation at plugin.rs:194.
|
||
- morphology_zone: state.districts.get(&(pos.0/8, pos.1/8)).map(|d| d.morphology_zone).unwrap_or(AlluvialPlain).
|
||
- arrangement_pattern: OPTION (a) (D-215-backed) — CityGenerationContext has NO arrangement_pattern field (generator.rs:1098-1124); add it, thread placement.arrangement_pattern (attractor_matching.rs:60/:629), have skeleton_gen consume it (doesn''t yet).
|
||
|
||
CONSUMERS LIVE-BUT-DORMANT: street_topology() (skeleton_gen.rs:1048) gates on MorphologyZone (Ribbon: Fjord/CliffCoast/MountainPass/Alpine/ValleyFloor; HubSpoke: Delta/Estuarine/OpenOcean/Lake/DuneStrand/TidalFlat; Mesh: AlluvialPlain/MeanderReach/RiverBank/BraidedPlain/Wetland/Volcanic); derive_layout_mode (:235)+block_irregularity (:68) gate on political_archetype. T-989/T-990 done — always get AlluvialPlain+Commission until this lands.
|
||
|
||
ACCEPTANCE: FjordWall-region coastal placement in CorpTerritory -> Ribbon topology + CompanyTown/CampusGrid layout, not mesh+Commission.
|
||
|
||
Governing: D-234 (primary), D-214, D-215 (-> option a), D-239 sec 6 (frozen vocab, now district_profile.rs), D-243.
|
||
|
||
OVERLAP w/ T-1043: both edit build_skeleton_work_item (plugin.rs), city_context_reader.rs, CityGenerationContext (generator.rs), skeleton_gen consumers. Implement together in ONE pass (one agent), not parallel.
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — staleness corrections + locked decision. Original scope authored 2026-06-12, BEFORE T-1077 (RegionProfile→DistrictProfile rename) and T-1078 (region climate tier, merged today). Corrected refs below.
|
||
|
||
STALENESS CORRECTIONS (the description''s code refs are pre-T-1077/T-1078):
|
||
- morphology_zone lives on **DistrictProfile** (server/src/atlas/district_profile.rs:193), NOT on RegionProfile (region_profile.rs:155 is a pure climate carrier — no morphology_zone). The ticket''s "region_profile.rs:180/:499" and "snapshot.layer_region" are wrong.
|
||
- Access path at dispatch: `state.districts.get(&district_pos)` on BodyWorldState.districts (server/src/atlas/body_world_state.rs:102). The cascade snapshot field is `layer_district` (cascade.rs:79), not `layer_region`.
|
||
- Position→DistrictPos: CityPlacement.position is (u16,u16) heightmap-pixel coords (attractor_matching.rs:51). Convert via the cells-per-district factor (currently a LOCAL `CELLS_PER_REGION = 8` in cascade.rs:260 — pre-D-243 naming). Do NOT hardcode 8 in plugin.rs: export a helper/const (prefer reusing server/src/atlas/scale.rs addressing) and call it from the dispatch.
|
||
- Verified current locations: build_skeleton_work_item = plugin.rs:180-213 (founding_orientation override is the threading site); political_archetype stub ~city_context_reader.rs:471-474; political_archetype derivation = attractor_matching.rs:602; CityPlacement fields ~attractor_matching.rs:49-64.
|
||
|
||
DECISION — arrangement_pattern path: **OPTION (b), re-derive. LOCKED.**
|
||
- skeleton_gen re-derives via the single shared pure fn `attractor_matching::arrangement_pattern(&political_archetype, &economic_role)` (attractor_matching.rs:629). Both inputs are available at L4: economic_role is ALREADY threaded (plugin.rs:189 reads it, :209 passes it); political_archetype is threaded by THIS ticket. NO new CityGenerationContext field; NO data-contract amendment.
|
||
- Rationale: arrangement_pattern is a pure TOTAL function (6-way archetype match + the `economic_role=="transit_hub"` override) — no seed/RNG/DB/clock/float. Re-derivation is provably identical to L3; cheaper to compute than to store; aligns with the "DB is only a cache, everything re-derivable from seed" principle (no stored derived spatial verdict).
|
||
- **HARDENING REQUIRED (the drift tripwire):** add a parity test asserting, for representative (archetype, economic_role) pairs, `arrangement_pattern(&placement.political_archetype, &placement.economic_role) == placement.arrangement_pattern` (CityPlacement already stores the L3-computed value at attractor_matching.rs:60). This locks L3≡L4 and trips the instant anyone changes arrangement_pattern''s input set. Optionally debug_assert the same equality in the dispatch. Never inline a second copy of the derivation — both sites call the one function.
|
||
|
||
COORDINATION: T-1039 and T-1043 both edit build_skeleton_work_item (plugin.rs:180-213). Do them as ONE combined branch/PR (single implementer), not two parallel edits to the same function.
|
||
|
||
Acceptance (unchanged): dispatch a FjordWall-region coastal placement in a CorpTerritory province → the generated quarter uses Ribbon topology and CompanyTown-class layout, not the AlluvialPlain mesh + Commission stub path.', 'backlog', 'high', NULL, 'server', 'D-234', '2026-06-12 10:23:49', '2026-06-15 16:15:05', NULL, 'cc4879ec3f398a3489dd150113c7dfbb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ034DKN4ENSGX5HTYTBJG', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Derive road_entry_directions at L3 and thread through the dispatch (interim: MST-neighbor bearings + water_bearing)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
Derive road_entry_directions at Layer 3 and thread them through the GenerateSkeleton dispatch. CityGenerationContext.road_entry_directions (server/src/simulation/generator.rs:1083-1084, compass octants 0=N..7=NW) is stubbed empty (city_context_reader.rs:478-479) and never overridden by the T-1022 dispatch, so derive_access_points (skeleton_gen.rs:1008-1036) never emits QuarterEdge access nodes — every quarter falls back to reservation gates or a single central BlockJunction (:1029-1034), and the D-234 arterial graph has no outward connection to the world.
|
||
|
||
Workshop contract: the field is a per-city output of the inter-settlement road graph (generation-cascade/round-3-notes.md:104 ''Layer C: Road graph (road_entry_directions per city)''; burnelli-sheldon-round4.md:308). Full-fidelity derivation therefore lands with the inter-settlement-transport ticket: octant = bearing of each connecting road edge where it crosses the city footprint radius (D-204 footprint), de-duplicated per octant, retaining per-entry quality for the consumer rule below.
|
||
|
||
Interim derivation (no road graph required, deterministic, replace-don''t-rework): derive octants at L3 from (a) bearings to the settlement''s MST-neighbor placements (positions already in BodyWorldState.placements) and (b) the founding-orientation water bearing (TerrainAnalysis::water_bearing, 8-octant integer — D-234 implementation note) for port/river settlements. Thread through build_skeleton_work_item (plugin.rs:179-212) next to the founding_orientation override.
|
||
|
||
Consumer rule to honour (already decided): the AdminFacing arrangement pattern picks its prestige edge as the edge facing the highest-quality road entry (paula-round2.md:428-433, paula-round3.md:320-322) — so the octant list should be ordered or annotated by quality once the graph exists. Player-experience intent: the approach should present the city''s FoundingOrientation face (ozzie-round1.md:96-100).
|
||
|
||
Acceptance: a dispatched settlement with >=1 neighbor produces >=1 AccessKind::QuarterEdge node on the correct octant; the BlockJunction fallback fires only for genuinely isolated settlements. Parent: T-750. Blocked-by (soft): inter-settlement-transport ticket for full fidelity. Refs: D-234, D-213, D-204; T-990 (consumer, done), T-1022 (dispatch, done).
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — READY, with a SCOPE UPDATE. The "interim: MST-neighbor bearings" framing in the title is now obsolete.
|
||
|
||
T-1038 ROAD GRAPH HAS SHIPPED — go full-fidelity, skip the interim. The inter-settlement road graph is live in the tree: road_graph.rs exists; the cascade runs CascadeLayer::RoadGraph (gen_queue.rs:383); BodyWorldState.road_graph (body_world_state.rs:91) is populated BEFORE GenCompletion::BodyAnalyzed fires, so at L3->L4 dispatch (plugin.rs:99-133) state.road_graph is already live. Therefore do NOT implement the MST-neighbor approximation — derive octants directly from state.road_graph.edges for the city''s node (match by RoadNode.city_id), bearing = city.position -> neighbor.position, octant = bearing_deg / 45. (NB: T-1038''s ticket still shows in_progress though its code shipped — consume the live road_graph regardless; flag if road_graph turns out not fully populated for some bodies.)
|
||
|
||
CURRENT REFS: CityGenerationContext.road_entry_directions = generator.rs:1107 (Vec<u8>, octants 0=N..7=NW); empty stub city_context_reader.rs:479; derive_access_points skeleton_gen.rs:1008-1035; BlockJunction fallback :1029-1034; build_skeleton_work_item plugin.rs:180-213 (insert next to the founding_orientation override at :194).
|
||
|
||
ISOLATED SETTLEMENTS (no road_graph edges): take the water bearing from placement.founding_orientation — Coastal{facing_degrees} / RiverAligned{bearing_degrees} already encode it (octant = degrees/45). Note TerrainAnalysis::water_bearing (features.rs:133, u16 deg, 360=none) is NOT stored on CityPlacement/BodyWorldState, so reading founding_orientation is the clean access path (no attractor position-match needed).
|
||
|
||
CONSUMER: T-990 (done) emits AccessKind::QuarterEdge per octant in derive_access_points. The AdminFacing prestige-edge rule (pick the edge facing the highest-quality road entry) is forward-looking — no AdminFacing code exists yet — so order/annotate octants by quality only once that consumer lands.
|
||
|
||
ACCEPTANCE: a dispatched settlement whose city_id has >=1 road_graph edge emits >=1 AccessKind::QuarterEdge on the matching octant; BlockJunction fallback fires only for genuinely isolated settlements.
|
||
|
||
Governing: D-234, D-213, D-204 (footprint radius). T-990 (consumer, done), T-1022 (dispatch, done), T-1038 (road graph, shipped).
|
||
|
||
OVERLAP w/ T-1039: both edit build_skeleton_work_item (plugin.rs), city_context_reader.rs, CityGenerationContext (generator.rs). Implement both in ONE pass (one agent), not parallel.
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — locked decision + staleness corrections. Original scope authored 2026-06-12.
|
||
|
||
DECISION — road_entry_directions source: **USE T-1038''s RoadGraph (full fidelity). LOCKED.** The interim MST-neighbor path is DROPPED.
|
||
- T-1038 has shipped a populated `BodyWorldState.road_graph` (RoadGraph) with `RoadNode.city_id` and `RoadEdge.path` (A*-routed polylines in heightmap working-grid coords), available at dispatch time (BodyWorldState is fully populated before the GenCompletion branch in plugin.rs).
|
||
- Derive each entry octant from the bearing of the connecting road edge where it crosses the city footprint radius (D-204 footprint_radius), de-duplicated per octant — the D-234 "full fidelity" definition. Order/annotate by edge quality so the AdminFacing consumer (paula-round2.md:428-433: prestige edge faces the highest-quality road entry) can pick correctly.
|
||
- COUPLING ACCEPTED: T-1038 is still in_progress; if its RoadGraph field shapes shift, this consumer adjusts. (User accepted this tradeoff over the throwaway interim path.)
|
||
|
||
water_bearing: NOT a CityPlacement field — it is encoded inside the founding_orientation enum arms (Coastal{facing_degrees}, RiverAligned{bearing_degrees}); TerrainAnalysis is not stored on BodyWorldState (T-1044 TODO). With the RoadGraph as the primary source, water_bearing is secondary; if used as a supplementary octant for port/river settlements, extract the bearing from those two arms only — Cardinal/Free/TerrainFollowing variants get no water octant.
|
||
|
||
STALENESS / verified current locations: road_entry_directions field = generator.rs:1107; stub = city_context_reader.rs:478-479; derive_access_points = skeleton_gen.rs:1008-1036 (BlockJunction fallback :1029-1034); build_skeleton_work_item = plugin.rs:180-213. (Confirmed unchanged by T-1077/T-1078.)
|
||
|
||
COORDINATION: T-1039 and T-1043 both edit build_skeleton_work_item (plugin.rs:180-213). Do them as ONE combined branch/PR (single implementer), not two parallel edits to the same function. Thread road_entry_directions next to political_archetype/morphology_zone in the same override block.
|
||
|
||
Acceptance (unchanged): a dispatched settlement with ≥1 road connection produces ≥1 AccessKind::QuarterEdge node on the correct octant; the BlockJunction fallback fires only for genuinely isolated settlements.', 'backlog', 'medium', NULL, 'server', 'D-234', '2026-06-12 10:23:50', '2026-06-15 16:15:05', NULL, '7a8f4f2810c9a96c556681e71d778a1a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ034DKN4ENSGX5HTYTBJG', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Derive road_entry_directions at L3 and thread through the dispatch (interim: MST-neighbor bearings + water_bearing)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
Derive road_entry_directions at Layer 3 and thread them through the GenerateSkeleton dispatch. CityGenerationContext.road_entry_directions (server/src/simulation/generator.rs:1083-1084, compass octants 0=N..7=NW) is stubbed empty (city_context_reader.rs:478-479) and never overridden by the T-1022 dispatch, so derive_access_points (skeleton_gen.rs:1008-1036) never emits QuarterEdge access nodes — every quarter falls back to reservation gates or a single central BlockJunction (:1029-1034), and the D-234 arterial graph has no outward connection to the world.
|
||
|
||
Workshop contract: the field is a per-city output of the inter-settlement road graph (generation-cascade/round-3-notes.md:104 ''Layer C: Road graph (road_entry_directions per city)''; burnelli-sheldon-round4.md:308). Full-fidelity derivation therefore lands with the inter-settlement-transport ticket: octant = bearing of each connecting road edge where it crosses the city footprint radius (D-204 footprint), de-duplicated per octant, retaining per-entry quality for the consumer rule below.
|
||
|
||
Interim derivation (no road graph required, deterministic, replace-don''t-rework): derive octants at L3 from (a) bearings to the settlement''s MST-neighbor placements (positions already in BodyWorldState.placements) and (b) the founding-orientation water bearing (TerrainAnalysis::water_bearing, 8-octant integer — D-234 implementation note) for port/river settlements. Thread through build_skeleton_work_item (plugin.rs:179-212) next to the founding_orientation override.
|
||
|
||
Consumer rule to honour (already decided): the AdminFacing arrangement pattern picks its prestige edge as the edge facing the highest-quality road entry (paula-round2.md:428-433, paula-round3.md:320-322) — so the octant list should be ordered or annotated by quality once the graph exists. Player-experience intent: the approach should present the city''s FoundingOrientation face (ozzie-round1.md:96-100).
|
||
|
||
Acceptance: a dispatched settlement with >=1 neighbor produces >=1 AccessKind::QuarterEdge node on the correct octant; the BlockJunction fallback fires only for genuinely isolated settlements. Parent: T-750. Blocked-by (soft): inter-settlement-transport ticket for full fidelity. Refs: D-234, D-213, D-204; T-990 (consumer, done), T-1022 (dispatch, done).
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — READY, with a SCOPE UPDATE. The "interim: MST-neighbor bearings" framing in the title is now obsolete.
|
||
|
||
T-1038 ROAD GRAPH HAS SHIPPED — go full-fidelity, skip the interim. The inter-settlement road graph is live in the tree: road_graph.rs exists; the cascade runs CascadeLayer::RoadGraph (gen_queue.rs:383); BodyWorldState.road_graph (body_world_state.rs:91) is populated BEFORE GenCompletion::BodyAnalyzed fires, so at L3->L4 dispatch (plugin.rs:99-133) state.road_graph is already live. Therefore do NOT implement the MST-neighbor approximation — derive octants directly from state.road_graph.edges for the city''s node (match by RoadNode.city_id), bearing = city.position -> neighbor.position, octant = bearing_deg / 45. (NB: T-1038''s ticket still shows in_progress though its code shipped — consume the live road_graph regardless; flag if road_graph turns out not fully populated for some bodies.)
|
||
|
||
CURRENT REFS: CityGenerationContext.road_entry_directions = generator.rs:1107 (Vec<u8>, octants 0=N..7=NW); empty stub city_context_reader.rs:479; derive_access_points skeleton_gen.rs:1008-1035; BlockJunction fallback :1029-1034; build_skeleton_work_item plugin.rs:180-213 (insert next to the founding_orientation override at :194).
|
||
|
||
ISOLATED SETTLEMENTS (no road_graph edges): take the water bearing from placement.founding_orientation — Coastal{facing_degrees} / RiverAligned{bearing_degrees} already encode it (octant = degrees/45). Note TerrainAnalysis::water_bearing (features.rs:133, u16 deg, 360=none) is NOT stored on CityPlacement/BodyWorldState, so reading founding_orientation is the clean access path (no attractor position-match needed).
|
||
|
||
CONSUMER: T-990 (done) emits AccessKind::QuarterEdge per octant in derive_access_points. The AdminFacing prestige-edge rule (pick the edge facing the highest-quality road entry) is forward-looking — no AdminFacing code exists yet — so order/annotate octants by quality only once that consumer lands.
|
||
|
||
ACCEPTANCE: a dispatched settlement whose city_id has >=1 road_graph edge emits >=1 AccessKind::QuarterEdge on the matching octant; BlockJunction fallback fires only for genuinely isolated settlements.
|
||
|
||
Governing: D-234, D-213, D-204 (footprint radius). T-990 (consumer, done), T-1022 (dispatch, done), T-1038 (road graph, shipped).
|
||
|
||
OVERLAP w/ T-1039: both edit build_skeleton_work_item (plugin.rs), city_context_reader.rs, CityGenerationContext (generator.rs). Implement both in ONE pass (one agent), not parallel.
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — locked decision + staleness corrections. Original scope authored 2026-06-12.
|
||
|
||
DECISION — road_entry_directions source: **USE T-1038''s RoadGraph (full fidelity). LOCKED.** The interim MST-neighbor path is DROPPED.
|
||
- T-1038 has shipped a populated `BodyWorldState.road_graph` (RoadGraph) with `RoadNode.city_id` and `RoadEdge.path` (A*-routed polylines in heightmap working-grid coords), available at dispatch time (BodyWorldState is fully populated before the GenCompletion branch in plugin.rs).
|
||
- Derive each entry octant from the bearing of the connecting road edge where it crosses the city footprint radius (D-204 footprint_radius), de-duplicated per octant — the D-234 "full fidelity" definition. Order/annotate by edge quality so the AdminFacing consumer (paula-round2.md:428-433: prestige edge faces the highest-quality road entry) can pick correctly.
|
||
- COUPLING ACCEPTED: T-1038 is still in_progress; if its RoadGraph field shapes shift, this consumer adjusts. (User accepted this tradeoff over the throwaway interim path.)
|
||
|
||
water_bearing: NOT a CityPlacement field — it is encoded inside the founding_orientation enum arms (Coastal{facing_degrees}, RiverAligned{bearing_degrees}); TerrainAnalysis is not stored on BodyWorldState (T-1044 TODO). With the RoadGraph as the primary source, water_bearing is secondary; if used as a supplementary octant for port/river settlements, extract the bearing from those two arms only — Cardinal/Free/TerrainFollowing variants get no water octant.
|
||
|
||
STALENESS / verified current locations: road_entry_directions field = generator.rs:1107; stub = city_context_reader.rs:478-479; derive_access_points = skeleton_gen.rs:1008-1036 (BlockJunction fallback :1029-1034); build_skeleton_work_item = plugin.rs:180-213. (Confirmed unchanged by T-1077/T-1078.)
|
||
|
||
COORDINATION: T-1039 and T-1043 both edit build_skeleton_work_item (plugin.rs:180-213). Do them as ONE combined branch/PR (single implementer), not two parallel edits to the same function. Thread road_entry_directions next to political_archetype/morphology_zone in the same override block.
|
||
|
||
Acceptance (unchanged): a dispatched settlement with ≥1 road connection produces ≥1 AccessKind::QuarterEdge node on the correct octant; the BlockJunction fallback fires only for genuinely isolated settlements.', 'in_progress', 'medium', NULL, 'server', 'D-234', '2026-06-12 10:23:50', '2026-06-15 16:15:05', NULL, '247a80310a5816287ef9065c25025a4d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ02KN9147H4Z12KJW7H1M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Thread political_archetype / arrangement_pattern / morphology_zone through the L3→L4 GenerateSkeleton dispatch', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
Thread the remaining Layer-3 character fields through the L3->L4 GenerateSkeleton dispatch. T-1022 wired the dispatch, but build_skeleton_work_item (server/src/atlas/plugin.rs:179-212) overrides only founding_orientation (:192-193); political_archetype stays the Commission stub (city_context_reader.rs:471-474) and morphology_zone stays AlluvialPlain (:487-488) even though:
|
||
- CityPlacement already carries the real political_archetype (D-214, derived from TerritorialStatus + economic_role at attractor_matching.rs:595-602) and arrangement_pattern (D-215, city_character at :282-293) — fields :49-64;
|
||
- the covering region''s real morphology_zone (D-239 §6 frozen vocab, T-1027, region_profile.rs:180/:499) is available from snapshot.layer_region, populated in the same cascade run (cascade.rs:238-240) — map placement.position to its covering region cell.
|
||
|
||
Consequences of the stubs: skeleton_gen''s morphology gating (D-234a Topology selection) always takes the AlluvialPlain Prim-MST mesh path — fjord/delta cities get plains street networks; block_irregularity/layout-mode always sees Commission (skeleton_gen.rs:68-77). D-234''s implementation note explicitly lists this threading as the pending dependency of the (done, tested, dormant) morphology-gated street rules.
|
||
|
||
Also decide arrangement_pattern''s path: CityGenerationContext has NO arrangement_pattern field (generator.rs:1078 has political_archetype only; ArrangementPattern :442 is defined but unconsumed at L4). Either (a) add the field and have skeleton_gen consume the D-215 explicit pattern, or (b) record that L4 derives layout from archetype alone and the placement''s pattern is Atlas/UI-only. Option (a) matches the workshop intent (ozzie-round1.md:112-118 backs explicit arrangement).
|
||
|
||
Miri''s queryability requirement (tile-derivation-contract/tyre-round1.md:308-311) — morphology_zone readable at Atlas-generation time — is satisfied by reading from BodyWorldState regions, no recompute.
|
||
|
||
Acceptance: dispatch a body with a FjordWall-region coastal placement in a CorpTerritory province -> the generated quarter uses Ribbon topology and CompanyTown-class layout, not mesh+Commission. Parent: T-750. Refs: D-214, D-215, D-228, D-234, D-239 §6; T-1022 (predecessor), T-983, T-1014 (adjacent, different fields).
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — READY. Supersedes stale region-scale refs (authored 2026-06-12, pre-T-1077 RegionProfile->DistrictProfile rename + T-1078). Current tree:
|
||
|
||
MORPHOLOGY CARRIER MOVED: morphology_zone now lives on DistrictProfile.morphology_zone (district_profile.rs:193, 2km carrier), NOT region_profile.rs. Snapshot field is layer_district (not layer_region — gone); map is BodyWorldState.districts (body_world_state.rs:102), populated by cascade (cascade.rs:270, converted :110-126). The ticket''s snapshot.layer_region / region_profile.rs:180/:499 / "covering region" refs are stale.
|
||
|
||
PLACEMENT->DISTRICT MAPPING: CityPlacement.position is heightmap pixel (row,col) (u16,u16) (attractor_matching.rs:51). DistrictPos = position / CELLS_PER_DISTRICT (8). No helper yet — add inline. Inverse at district_profile.rs:1023-1026.
|
||
|
||
STUB SITES: political_archetype stub city_context_reader.rs:474 (Commission); morphology_zone stub :488 (AlluvialPlain); both in context_from_read_set() (:462). build_skeleton_work_item (plugin.rs:180-213) threads only founding_orientation (:194) and does NOT receive the districts map — pass &state.districts in (available in the GenCompletion::BodyAnalyzed arm, plugin.rs:101) or resolve before the call; fallback AlluvialPlain on miss.
|
||
|
||
THREE OVERRIDES:
|
||
- political_archetype: one-liner — context.political_archetype = placement.political_archetype (real D-214 value, attractor_matching.rs:58/:602), parallel to founding_orientation at plugin.rs:194.
|
||
- morphology_zone: state.districts.get(&(pos.0/8, pos.1/8)).map(|d| d.morphology_zone).unwrap_or(AlluvialPlain).
|
||
- arrangement_pattern: OPTION (a) (D-215-backed) — CityGenerationContext has NO arrangement_pattern field (generator.rs:1098-1124); add it, thread placement.arrangement_pattern (attractor_matching.rs:60/:629), have skeleton_gen consume it (doesn''t yet).
|
||
|
||
CONSUMERS LIVE-BUT-DORMANT: street_topology() (skeleton_gen.rs:1048) gates on MorphologyZone (Ribbon: Fjord/CliffCoast/MountainPass/Alpine/ValleyFloor; HubSpoke: Delta/Estuarine/OpenOcean/Lake/DuneStrand/TidalFlat; Mesh: AlluvialPlain/MeanderReach/RiverBank/BraidedPlain/Wetland/Volcanic); derive_layout_mode (:235)+block_irregularity (:68) gate on political_archetype. T-989/T-990 done — always get AlluvialPlain+Commission until this lands.
|
||
|
||
ACCEPTANCE: FjordWall-region coastal placement in CorpTerritory -> Ribbon topology + CompanyTown/CampusGrid layout, not mesh+Commission.
|
||
|
||
Governing: D-234 (primary), D-214, D-215 (-> option a), D-239 sec 6 (frozen vocab, now district_profile.rs), D-243.
|
||
|
||
OVERLAP w/ T-1043: both edit build_skeleton_work_item (plugin.rs), city_context_reader.rs, CityGenerationContext (generator.rs), skeleton_gen consumers. Implement together in ONE pass (one agent), not parallel.
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — staleness corrections + locked decision. Original scope authored 2026-06-12, BEFORE T-1077 (RegionProfile→DistrictProfile rename) and T-1078 (region climate tier, merged today). Corrected refs below.
|
||
|
||
STALENESS CORRECTIONS (the description''s code refs are pre-T-1077/T-1078):
|
||
- morphology_zone lives on **DistrictProfile** (server/src/atlas/district_profile.rs:193), NOT on RegionProfile (region_profile.rs:155 is a pure climate carrier — no morphology_zone). The ticket''s "region_profile.rs:180/:499" and "snapshot.layer_region" are wrong.
|
||
- Access path at dispatch: `state.districts.get(&district_pos)` on BodyWorldState.districts (server/src/atlas/body_world_state.rs:102). The cascade snapshot field is `layer_district` (cascade.rs:79), not `layer_region`.
|
||
- Position→DistrictPos: CityPlacement.position is (u16,u16) heightmap-pixel coords (attractor_matching.rs:51). Convert via the cells-per-district factor (currently a LOCAL `CELLS_PER_REGION = 8` in cascade.rs:260 — pre-D-243 naming). Do NOT hardcode 8 in plugin.rs: export a helper/const (prefer reusing server/src/atlas/scale.rs addressing) and call it from the dispatch.
|
||
- Verified current locations: build_skeleton_work_item = plugin.rs:180-213 (founding_orientation override is the threading site); political_archetype stub ~city_context_reader.rs:471-474; political_archetype derivation = attractor_matching.rs:602; CityPlacement fields ~attractor_matching.rs:49-64.
|
||
|
||
DECISION — arrangement_pattern path: **OPTION (b), re-derive. LOCKED.**
|
||
- skeleton_gen re-derives via the single shared pure fn `attractor_matching::arrangement_pattern(&political_archetype, &economic_role)` (attractor_matching.rs:629). Both inputs are available at L4: economic_role is ALREADY threaded (plugin.rs:189 reads it, :209 passes it); political_archetype is threaded by THIS ticket. NO new CityGenerationContext field; NO data-contract amendment.
|
||
- Rationale: arrangement_pattern is a pure TOTAL function (6-way archetype match + the `economic_role=="transit_hub"` override) — no seed/RNG/DB/clock/float. Re-derivation is provably identical to L3; cheaper to compute than to store; aligns with the "DB is only a cache, everything re-derivable from seed" principle (no stored derived spatial verdict).
|
||
- **HARDENING REQUIRED (the drift tripwire):** add a parity test asserting, for representative (archetype, economic_role) pairs, `arrangement_pattern(&placement.political_archetype, &placement.economic_role) == placement.arrangement_pattern` (CityPlacement already stores the L3-computed value at attractor_matching.rs:60). This locks L3≡L4 and trips the instant anyone changes arrangement_pattern''s input set. Optionally debug_assert the same equality in the dispatch. Never inline a second copy of the derivation — both sites call the one function.
|
||
|
||
COORDINATION: T-1039 and T-1043 both edit build_skeleton_work_item (plugin.rs:180-213). Do them as ONE combined branch/PR (single implementer), not two parallel edits to the same function.
|
||
|
||
Acceptance (unchanged): dispatch a FjordWall-region coastal placement in a CorpTerritory province → the generated quarter uses Ribbon topology and CompanyTown-class layout, not the AlluvialPlain mesh + Commission stub path.', 'in_progress', 'high', NULL, 'server', 'D-234', '2026-06-12 10:23:49', '2026-06-15 16:15:05', NULL, '79bd02124feabe8047e351b506ef3443', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ8BFVNWDH17CMH1YM', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Per-layer Atlas map viewer (generation progress viewer)', 'Render each cascade layer as a MAP in the implant Atlas (D-191, the Phase 3 viewer — D-166 amendment): terrain → water → biome → settlements → political zones → quarter/block skeleton → tiles. This is the progress-viewer deliverable; NO in-world rendering. Grows as each layer lands.
|
||
|
||
---
|
||
Refinement (2026-05-23, /whats-next):
|
||
- DATA TRANSPORT (resolves Q-098): NO bake — baking derived layer data makes mods second-class. A server-side FILE STREAM PROXY: resolves a body source files across base + mod paths, runs the deterministic cascade on demand (run_cascade, LRU-cached per D-203, ~45ms), and streams serialized layer data to the Godot client over IPC. First-party and mod bodies use the identical path; no pre-baked derived artifacts. Protocol/stream spec designed with Tyre and recorded in a D-record resolving Q-098.
|
||
- UI: layer selector in the existing regional Atlas view; layers are ADDITIVE overlays (toggle heightmap + rivers + attractors + sub-biome together and composite), not one-at-a-time — matching the existing overlay-bar model (D-191).
|
||
- SCOPE NOW: only Layer 0 (heightmap) + Layer 1 (rivers/basins/attractors/sub-biome) exist; the viewer grows as layers land (D-166). Acceptance: Layer 0 + Layer 1 render as additive, toggleable overlays for a body, fed by the proxy.
|
||
|
||
---
|
||
Design (D-226, Araminta, 2026-05-24) — human-visual layer of the inspection harness. Extend OVERLAY_DEFS / AtlasOverlayBar with a generation overlay group (second row) + a left-side legend panel; do NOT build a separate viewer. Encoding: relief base; rivers as blue polylines (mouths = double-circle markers, confluences where in-degree >= 3); basin fills very translucent + thin boundary polylines; attractors as markers where SHAPE encodes the 7 AttractorTypes (circle/half-circle/diamond/down-tri/up-tri/hollow-circle/square) and COLOR encodes sub-biome (shape carries identity in headless/monochrome; color is additive); size scales with strength, skip strength < 0.15. Stable button ids gen_l0_heightmap / gen_l1_rivers / gen_l1_basins / gen_l1_attractors; start pending/locked, unlock+activate via notify_gen_layer_ready(id) as data arrives (grows as layers land, D-166). Consumes the live proxy (#969); the agent channel (#971) drives this same UI.
|
||
|
||
Remaining to close (Si sweep 2026-06-07): add the gen_l0_heightmap overlay to OVERLAY_DEFS + render path in atlas_viewer.gd / atlas_marker_overlay.gd — required by the D-226/T-960 acceptance criteria but currently absent. Layer-1 overlays (rivers/basins/attractors) + proxy wire + pending indicator are already implemented; this Layer-0 overlay is the sole remaining piece.', 'backlog', 'high', NULL, 'client', 'D-191', '2026-05-22 17:42:34', '2026-06-16 09:36:03', NULL, '98ada0147662421feb0784787b4073fb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ02F02JDDBSFMGPX0XASR', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Layer 2 — inter-settlement road/rail graph (MST + A* over terrain cost, MaintenanceAuthority, named-route identity)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
Generate the inter-settlement road/rail graph at Layer 2 — the workshopped-but-never-ticketed link between settlement placement (T-955/T-956, done) and everything that consumes transport topology. No road code exists today (zero RoadGraph/road_segment hits in server/src; TerritorialStatus shipped without its road-coverage inputs).
|
||
|
||
Scope (algorithm fully decided, docs/workshops/planet-down-cascade/tyre-round1.md:274-299):
|
||
1. MST force-connect all CityPlacements (Euclidean), then secondary direct links for city pairs within 30-60% of body scale whose MST path exceeds 1.5x Euclidean.
|
||
2. Route each edge with A* over the L1 terrain-cost field (terrain_modification_cost, D-210, server/src/atlas/subbiome.rs; cost spec: water impassable, roughness>0.7 = 10.0, river corridor = 0.5, flat = 1.0 — rivers as preferred valley routes). Budget ~30ms/body (round-1-notes.md:348).
|
||
3. Assign MaintenanceAuthority per edge from endpoint relationships (5-value enum Administrative/Corporate/Communal/Trade/Abandoned — generation-cascade/workshop-outcomes.md:177, resolution :257; player-readable in road condition per ozzie-round1.md:86-92).
|
||
4. Place waypoint sub-settlement nodes at midpoints of edges > ~12 regional cells (tyre-round1.md:267-272).
|
||
5. Named-route identity assignment: post-generation join of generated edges to systems.db named highway routes via optional named_route_id FK (paula-round1.md:107,:140; round-1-notes.md:322 L2-Q3 resolution under Amendment 3).
|
||
6. RailHeadFacing second pass: settlements at high-connectivity road/rail junctions get FoundingOrientation::RailHeadFacing, overriding AdminFacing-from-Synthetic (paula-round3.md:218-236) — wire into attractor_matching.rs.
|
||
|
||
Storage: RoadGraph{nodes,edges} on BodyWorldState (round-1-notes.md:257-267), session-cached, never serialized — runtime Rust, not systems.db (the atlas_road_nodes/atlas_road_edges schema shape carries forward per tyre-round1.md:42 but lives in session memory).
|
||
|
||
Downstream consumers (do NOT scope in, but design the output for them): road_entry_directions per city (see road-entry-octants ticket; generation-cascade/round-3-notes.md:104), TerritorialStatus quantitative road-coverage thresholds (round-1-notes.md:329-338), per-economic_role hinterland fill (round-1-notes.md:324-327, BRIEF.md:279), prosperity/atlas overlays.
|
||
|
||
Cascade-first fit: this is direction step (2) — the econ layer drawn onto the world between settlements. Parent: T-750. Suggested deps: blocks the road-entry-octants ticket; references D-205 (provinces), D-210, D-211, D-212, D-213.
|
||
|
||
---
|
||
Implementation (2026-06-14):
|
||
SHIPPED — deterministic road-graph CORE in server/src/atlas/road_graph.rs (CascadeLayer::RoadGraph, stored on BodyWorldState.road_graph, never serialized):
|
||
1. MST force-connect (strict Kruskal over dist^2) + secondary links (30-60% body-scale band, >1.5x MST detour).
|
||
2. A* over the L1 terrain-cost field (ocean/lake impassable, river 1/2 cost, slope>=35deg 10x, else D-210 terrain_modification_cost) on a coarse 64-wide routing grid; equirectangular column wrap.
|
||
3. MaintenanceAuthority per edge (new generator.rs enum: Administrative/Corporate/Communal/Trade/Abandoned) from endpoint political archetypes + haul length.
|
||
4. Waypoint nodes at midpoints of edges > 12 routing cells.
|
||
5. Named-route identity join (named_route_id, designed-for; pool empty post-D-223 -> no-op).
|
||
+ junction detection (RoadGraph::high_connectivity_junctions, degree>=3).
|
||
Wired into the cascade (gen_queue requests CascadeLayer::RoadGraph) + BodyWorldState. 10 road_graph unit tests + a cascade e2e test; full lib suite green.
|
||
|
||
DEFERRED (-> T-1076, gated on the D-242 settlement model T-1074/T-1075):
|
||
- step 6 RailHeadFacing second pass — the adopted FoundingOrientation enum (D-213) has no RailHeadFacing; needs a D-213 amendment + Layer-4 skeleton_gen handling. Junction data is already exposed for it.
|
||
- hub-selection refinement (scaled-cap hubs, co-location collapse, hybrid minor-settlement attach) — needs baked population/specialization (D-242).
|
||
Decision D-242 filed (corp-HQ settlement model) — resolves why corp HQs were polluting the city pool as duplicate settlements.', 'done', 'high', NULL, 'server', 'D-211', '2026-06-12 10:23:49', '2026-06-16 09:38:09', NULL, '765c830e60f3b5cb392f4699a996e348', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ02KN9147H4Z12KJW7H1M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Thread political_archetype / arrangement_pattern / morphology_zone through the L3→L4 GenerateSkeleton dispatch', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
Thread the remaining Layer-3 character fields through the L3->L4 GenerateSkeleton dispatch. T-1022 wired the dispatch, but build_skeleton_work_item (server/src/atlas/plugin.rs:179-212) overrides only founding_orientation (:192-193); political_archetype stays the Commission stub (city_context_reader.rs:471-474) and morphology_zone stays AlluvialPlain (:487-488) even though:
|
||
- CityPlacement already carries the real political_archetype (D-214, derived from TerritorialStatus + economic_role at attractor_matching.rs:595-602) and arrangement_pattern (D-215, city_character at :282-293) — fields :49-64;
|
||
- the covering region''s real morphology_zone (D-239 §6 frozen vocab, T-1027, region_profile.rs:180/:499) is available from snapshot.layer_region, populated in the same cascade run (cascade.rs:238-240) — map placement.position to its covering region cell.
|
||
|
||
Consequences of the stubs: skeleton_gen''s morphology gating (D-234a Topology selection) always takes the AlluvialPlain Prim-MST mesh path — fjord/delta cities get plains street networks; block_irregularity/layout-mode always sees Commission (skeleton_gen.rs:68-77). D-234''s implementation note explicitly lists this threading as the pending dependency of the (done, tested, dormant) morphology-gated street rules.
|
||
|
||
Also decide arrangement_pattern''s path: CityGenerationContext has NO arrangement_pattern field (generator.rs:1078 has political_archetype only; ArrangementPattern :442 is defined but unconsumed at L4). Either (a) add the field and have skeleton_gen consume the D-215 explicit pattern, or (b) record that L4 derives layout from archetype alone and the placement''s pattern is Atlas/UI-only. Option (a) matches the workshop intent (ozzie-round1.md:112-118 backs explicit arrangement).
|
||
|
||
Miri''s queryability requirement (tile-derivation-contract/tyre-round1.md:308-311) — morphology_zone readable at Atlas-generation time — is satisfied by reading from BodyWorldState regions, no recompute.
|
||
|
||
Acceptance: dispatch a body with a FjordWall-region coastal placement in a CorpTerritory province -> the generated quarter uses Ribbon topology and CompanyTown-class layout, not mesh+Commission. Parent: T-750. Refs: D-214, D-215, D-228, D-234, D-239 §6; T-1022 (predecessor), T-983, T-1014 (adjacent, different fields).
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — READY. Supersedes stale region-scale refs (authored 2026-06-12, pre-T-1077 RegionProfile->DistrictProfile rename + T-1078). Current tree:
|
||
|
||
MORPHOLOGY CARRIER MOVED: morphology_zone now lives on DistrictProfile.morphology_zone (district_profile.rs:193, 2km carrier), NOT region_profile.rs. Snapshot field is layer_district (not layer_region — gone); map is BodyWorldState.districts (body_world_state.rs:102), populated by cascade (cascade.rs:270, converted :110-126). The ticket''s snapshot.layer_region / region_profile.rs:180/:499 / "covering region" refs are stale.
|
||
|
||
PLACEMENT->DISTRICT MAPPING: CityPlacement.position is heightmap pixel (row,col) (u16,u16) (attractor_matching.rs:51). DistrictPos = position / CELLS_PER_DISTRICT (8). No helper yet — add inline. Inverse at district_profile.rs:1023-1026.
|
||
|
||
STUB SITES: political_archetype stub city_context_reader.rs:474 (Commission); morphology_zone stub :488 (AlluvialPlain); both in context_from_read_set() (:462). build_skeleton_work_item (plugin.rs:180-213) threads only founding_orientation (:194) and does NOT receive the districts map — pass &state.districts in (available in the GenCompletion::BodyAnalyzed arm, plugin.rs:101) or resolve before the call; fallback AlluvialPlain on miss.
|
||
|
||
THREE OVERRIDES:
|
||
- political_archetype: one-liner — context.political_archetype = placement.political_archetype (real D-214 value, attractor_matching.rs:58/:602), parallel to founding_orientation at plugin.rs:194.
|
||
- morphology_zone: state.districts.get(&(pos.0/8, pos.1/8)).map(|d| d.morphology_zone).unwrap_or(AlluvialPlain).
|
||
- arrangement_pattern: OPTION (a) (D-215-backed) — CityGenerationContext has NO arrangement_pattern field (generator.rs:1098-1124); add it, thread placement.arrangement_pattern (attractor_matching.rs:60/:629), have skeleton_gen consume it (doesn''t yet).
|
||
|
||
CONSUMERS LIVE-BUT-DORMANT: street_topology() (skeleton_gen.rs:1048) gates on MorphologyZone (Ribbon: Fjord/CliffCoast/MountainPass/Alpine/ValleyFloor; HubSpoke: Delta/Estuarine/OpenOcean/Lake/DuneStrand/TidalFlat; Mesh: AlluvialPlain/MeanderReach/RiverBank/BraidedPlain/Wetland/Volcanic); derive_layout_mode (:235)+block_irregularity (:68) gate on political_archetype. T-989/T-990 done — always get AlluvialPlain+Commission until this lands.
|
||
|
||
ACCEPTANCE: FjordWall-region coastal placement in CorpTerritory -> Ribbon topology + CompanyTown/CampusGrid layout, not mesh+Commission.
|
||
|
||
Governing: D-234 (primary), D-214, D-215 (-> option a), D-239 sec 6 (frozen vocab, now district_profile.rs), D-243.
|
||
|
||
OVERLAP w/ T-1043: both edit build_skeleton_work_item (plugin.rs), city_context_reader.rs, CityGenerationContext (generator.rs), skeleton_gen consumers. Implement together in ONE pass (one agent), not parallel.
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — staleness corrections + locked decision. Original scope authored 2026-06-12, BEFORE T-1077 (RegionProfile→DistrictProfile rename) and T-1078 (region climate tier, merged today). Corrected refs below.
|
||
|
||
STALENESS CORRECTIONS (the description''s code refs are pre-T-1077/T-1078):
|
||
- morphology_zone lives on **DistrictProfile** (server/src/atlas/district_profile.rs:193), NOT on RegionProfile (region_profile.rs:155 is a pure climate carrier — no morphology_zone). The ticket''s "region_profile.rs:180/:499" and "snapshot.layer_region" are wrong.
|
||
- Access path at dispatch: `state.districts.get(&district_pos)` on BodyWorldState.districts (server/src/atlas/body_world_state.rs:102). The cascade snapshot field is `layer_district` (cascade.rs:79), not `layer_region`.
|
||
- Position→DistrictPos: CityPlacement.position is (u16,u16) heightmap-pixel coords (attractor_matching.rs:51). Convert via the cells-per-district factor (currently a LOCAL `CELLS_PER_REGION = 8` in cascade.rs:260 — pre-D-243 naming). Do NOT hardcode 8 in plugin.rs: export a helper/const (prefer reusing server/src/atlas/scale.rs addressing) and call it from the dispatch.
|
||
- Verified current locations: build_skeleton_work_item = plugin.rs:180-213 (founding_orientation override is the threading site); political_archetype stub ~city_context_reader.rs:471-474; political_archetype derivation = attractor_matching.rs:602; CityPlacement fields ~attractor_matching.rs:49-64.
|
||
|
||
DECISION — arrangement_pattern path: **OPTION (b), re-derive. LOCKED.**
|
||
- skeleton_gen re-derives via the single shared pure fn `attractor_matching::arrangement_pattern(&political_archetype, &economic_role)` (attractor_matching.rs:629). Both inputs are available at L4: economic_role is ALREADY threaded (plugin.rs:189 reads it, :209 passes it); political_archetype is threaded by THIS ticket. NO new CityGenerationContext field; NO data-contract amendment.
|
||
- Rationale: arrangement_pattern is a pure TOTAL function (6-way archetype match + the `economic_role=="transit_hub"` override) — no seed/RNG/DB/clock/float. Re-derivation is provably identical to L3; cheaper to compute than to store; aligns with the "DB is only a cache, everything re-derivable from seed" principle (no stored derived spatial verdict).
|
||
- **HARDENING REQUIRED (the drift tripwire):** add a parity test asserting, for representative (archetype, economic_role) pairs, `arrangement_pattern(&placement.political_archetype, &placement.economic_role) == placement.arrangement_pattern` (CityPlacement already stores the L3-computed value at attractor_matching.rs:60). This locks L3≡L4 and trips the instant anyone changes arrangement_pattern''s input set. Optionally debug_assert the same equality in the dispatch. Never inline a second copy of the derivation — both sites call the one function.
|
||
|
||
COORDINATION: T-1039 and T-1043 both edit build_skeleton_work_item (plugin.rs:180-213). Do them as ONE combined branch/PR (single implementer), not two parallel edits to the same function.
|
||
|
||
Acceptance (unchanged): dispatch a FjordWall-region coastal placement in a CorpTerritory province → the generated quarter uses Ribbon topology and CompanyTown-class layout, not the AlluvialPlain mesh + Commission stub path.', 'in_progress', 'high', NULL, 'server', 'D-234', '2026-06-12 10:23:49', '2026-06-16 09:42:26', NULL, '77782abe064317b1636998c676c42433', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ034DKN4ENSGX5HTYTBJG', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Derive road_entry_directions at L3 and thread through the dispatch (interim: MST-neighbor bearings + water_bearing)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
Derive road_entry_directions at Layer 3 and thread them through the GenerateSkeleton dispatch. CityGenerationContext.road_entry_directions (server/src/simulation/generator.rs:1083-1084, compass octants 0=N..7=NW) is stubbed empty (city_context_reader.rs:478-479) and never overridden by the T-1022 dispatch, so derive_access_points (skeleton_gen.rs:1008-1036) never emits QuarterEdge access nodes — every quarter falls back to reservation gates or a single central BlockJunction (:1029-1034), and the D-234 arterial graph has no outward connection to the world.
|
||
|
||
Workshop contract: the field is a per-city output of the inter-settlement road graph (generation-cascade/round-3-notes.md:104 ''Layer C: Road graph (road_entry_directions per city)''; burnelli-sheldon-round4.md:308). Full-fidelity derivation therefore lands with the inter-settlement-transport ticket: octant = bearing of each connecting road edge where it crosses the city footprint radius (D-204 footprint), de-duplicated per octant, retaining per-entry quality for the consumer rule below.
|
||
|
||
Interim derivation (no road graph required, deterministic, replace-don''t-rework): derive octants at L3 from (a) bearings to the settlement''s MST-neighbor placements (positions already in BodyWorldState.placements) and (b) the founding-orientation water bearing (TerrainAnalysis::water_bearing, 8-octant integer — D-234 implementation note) for port/river settlements. Thread through build_skeleton_work_item (plugin.rs:179-212) next to the founding_orientation override.
|
||
|
||
Consumer rule to honour (already decided): the AdminFacing arrangement pattern picks its prestige edge as the edge facing the highest-quality road entry (paula-round2.md:428-433, paula-round3.md:320-322) — so the octant list should be ordered or annotated by quality once the graph exists. Player-experience intent: the approach should present the city''s FoundingOrientation face (ozzie-round1.md:96-100).
|
||
|
||
Acceptance: a dispatched settlement with >=1 neighbor produces >=1 AccessKind::QuarterEdge node on the correct octant; the BlockJunction fallback fires only for genuinely isolated settlements. Parent: T-750. Blocked-by (soft): inter-settlement-transport ticket for full fidelity. Refs: D-234, D-213, D-204; T-990 (consumer, done), T-1022 (dispatch, done).
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — READY, with a SCOPE UPDATE. The "interim: MST-neighbor bearings" framing in the title is now obsolete.
|
||
|
||
T-1038 ROAD GRAPH HAS SHIPPED — go full-fidelity, skip the interim. The inter-settlement road graph is live in the tree: road_graph.rs exists; the cascade runs CascadeLayer::RoadGraph (gen_queue.rs:383); BodyWorldState.road_graph (body_world_state.rs:91) is populated BEFORE GenCompletion::BodyAnalyzed fires, so at L3->L4 dispatch (plugin.rs:99-133) state.road_graph is already live. Therefore do NOT implement the MST-neighbor approximation — derive octants directly from state.road_graph.edges for the city''s node (match by RoadNode.city_id), bearing = city.position -> neighbor.position, octant = bearing_deg / 45. (NB: T-1038''s ticket still shows in_progress though its code shipped — consume the live road_graph regardless; flag if road_graph turns out not fully populated for some bodies.)
|
||
|
||
CURRENT REFS: CityGenerationContext.road_entry_directions = generator.rs:1107 (Vec<u8>, octants 0=N..7=NW); empty stub city_context_reader.rs:479; derive_access_points skeleton_gen.rs:1008-1035; BlockJunction fallback :1029-1034; build_skeleton_work_item plugin.rs:180-213 (insert next to the founding_orientation override at :194).
|
||
|
||
ISOLATED SETTLEMENTS (no road_graph edges): take the water bearing from placement.founding_orientation — Coastal{facing_degrees} / RiverAligned{bearing_degrees} already encode it (octant = degrees/45). Note TerrainAnalysis::water_bearing (features.rs:133, u16 deg, 360=none) is NOT stored on CityPlacement/BodyWorldState, so reading founding_orientation is the clean access path (no attractor position-match needed).
|
||
|
||
CONSUMER: T-990 (done) emits AccessKind::QuarterEdge per octant in derive_access_points. The AdminFacing prestige-edge rule (pick the edge facing the highest-quality road entry) is forward-looking — no AdminFacing code exists yet — so order/annotate octants by quality only once that consumer lands.
|
||
|
||
ACCEPTANCE: a dispatched settlement whose city_id has >=1 road_graph edge emits >=1 AccessKind::QuarterEdge on the matching octant; BlockJunction fallback fires only for genuinely isolated settlements.
|
||
|
||
Governing: D-234, D-213, D-204 (footprint radius). T-990 (consumer, done), T-1022 (dispatch, done), T-1038 (road graph, shipped).
|
||
|
||
OVERLAP w/ T-1039: both edit build_skeleton_work_item (plugin.rs), city_context_reader.rs, CityGenerationContext (generator.rs). Implement both in ONE pass (one agent), not parallel.
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — locked decision + staleness corrections. Original scope authored 2026-06-12.
|
||
|
||
DECISION — road_entry_directions source: **USE T-1038''s RoadGraph (full fidelity). LOCKED.** The interim MST-neighbor path is DROPPED.
|
||
- T-1038 has shipped a populated `BodyWorldState.road_graph` (RoadGraph) with `RoadNode.city_id` and `RoadEdge.path` (A*-routed polylines in heightmap working-grid coords), available at dispatch time (BodyWorldState is fully populated before the GenCompletion branch in plugin.rs).
|
||
- Derive each entry octant from the bearing of the connecting road edge where it crosses the city footprint radius (D-204 footprint_radius), de-duplicated per octant — the D-234 "full fidelity" definition. Order/annotate by edge quality so the AdminFacing consumer (paula-round2.md:428-433: prestige edge faces the highest-quality road entry) can pick correctly.
|
||
- COUPLING ACCEPTED: T-1038 is still in_progress; if its RoadGraph field shapes shift, this consumer adjusts. (User accepted this tradeoff over the throwaway interim path.)
|
||
|
||
water_bearing: NOT a CityPlacement field — it is encoded inside the founding_orientation enum arms (Coastal{facing_degrees}, RiverAligned{bearing_degrees}); TerrainAnalysis is not stored on BodyWorldState (T-1044 TODO). With the RoadGraph as the primary source, water_bearing is secondary; if used as a supplementary octant for port/river settlements, extract the bearing from those two arms only — Cardinal/Free/TerrainFollowing variants get no water octant.
|
||
|
||
STALENESS / verified current locations: road_entry_directions field = generator.rs:1107; stub = city_context_reader.rs:478-479; derive_access_points = skeleton_gen.rs:1008-1036 (BlockJunction fallback :1029-1034); build_skeleton_work_item = plugin.rs:180-213. (Confirmed unchanged by T-1077/T-1078.)
|
||
|
||
COORDINATION: T-1039 and T-1043 both edit build_skeleton_work_item (plugin.rs:180-213). Do them as ONE combined branch/PR (single implementer), not two parallel edits to the same function. Thread road_entry_directions next to political_archetype/morphology_zone in the same override block.
|
||
|
||
Acceptance (unchanged): a dispatched settlement with ≥1 road connection produces ≥1 AccessKind::QuarterEdge node on the correct octant; the BlockJunction fallback fires only for genuinely isolated settlements.', 'in_progress', 'medium', NULL, 'server', 'D-234', '2026-06-12 10:23:50', '2026-06-16 09:42:26', NULL, 'dbe27cb938a21c2cd7754c4589e8032c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ034DKN4ENSGX5HTYTBJG', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Derive road_entry_directions at L3 and thread through the dispatch (interim: MST-neighbor bearings + water_bearing)', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
Derive road_entry_directions at Layer 3 and thread them through the GenerateSkeleton dispatch. CityGenerationContext.road_entry_directions (server/src/simulation/generator.rs:1083-1084, compass octants 0=N..7=NW) is stubbed empty (city_context_reader.rs:478-479) and never overridden by the T-1022 dispatch, so derive_access_points (skeleton_gen.rs:1008-1036) never emits QuarterEdge access nodes — every quarter falls back to reservation gates or a single central BlockJunction (:1029-1034), and the D-234 arterial graph has no outward connection to the world.
|
||
|
||
Workshop contract: the field is a per-city output of the inter-settlement road graph (generation-cascade/round-3-notes.md:104 ''Layer C: Road graph (road_entry_directions per city)''; burnelli-sheldon-round4.md:308). Full-fidelity derivation therefore lands with the inter-settlement-transport ticket: octant = bearing of each connecting road edge where it crosses the city footprint radius (D-204 footprint), de-duplicated per octant, retaining per-entry quality for the consumer rule below.
|
||
|
||
Interim derivation (no road graph required, deterministic, replace-don''t-rework): derive octants at L3 from (a) bearings to the settlement''s MST-neighbor placements (positions already in BodyWorldState.placements) and (b) the founding-orientation water bearing (TerrainAnalysis::water_bearing, 8-octant integer — D-234 implementation note) for port/river settlements. Thread through build_skeleton_work_item (plugin.rs:179-212) next to the founding_orientation override.
|
||
|
||
Consumer rule to honour (already decided): the AdminFacing arrangement pattern picks its prestige edge as the edge facing the highest-quality road entry (paula-round2.md:428-433, paula-round3.md:320-322) — so the octant list should be ordered or annotated by quality once the graph exists. Player-experience intent: the approach should present the city''s FoundingOrientation face (ozzie-round1.md:96-100).
|
||
|
||
Acceptance: a dispatched settlement with >=1 neighbor produces >=1 AccessKind::QuarterEdge node on the correct octant; the BlockJunction fallback fires only for genuinely isolated settlements. Parent: T-750. Blocked-by (soft): inter-settlement-transport ticket for full fidelity. Refs: D-234, D-213, D-204; T-990 (consumer, done), T-1022 (dispatch, done).
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — READY, with a SCOPE UPDATE. The "interim: MST-neighbor bearings" framing in the title is now obsolete.
|
||
|
||
T-1038 ROAD GRAPH HAS SHIPPED — go full-fidelity, skip the interim. The inter-settlement road graph is live in the tree: road_graph.rs exists; the cascade runs CascadeLayer::RoadGraph (gen_queue.rs:383); BodyWorldState.road_graph (body_world_state.rs:91) is populated BEFORE GenCompletion::BodyAnalyzed fires, so at L3->L4 dispatch (plugin.rs:99-133) state.road_graph is already live. Therefore do NOT implement the MST-neighbor approximation — derive octants directly from state.road_graph.edges for the city''s node (match by RoadNode.city_id), bearing = city.position -> neighbor.position, octant = bearing_deg / 45. (NB: T-1038''s ticket still shows in_progress though its code shipped — consume the live road_graph regardless; flag if road_graph turns out not fully populated for some bodies.)
|
||
|
||
CURRENT REFS: CityGenerationContext.road_entry_directions = generator.rs:1107 (Vec<u8>, octants 0=N..7=NW); empty stub city_context_reader.rs:479; derive_access_points skeleton_gen.rs:1008-1035; BlockJunction fallback :1029-1034; build_skeleton_work_item plugin.rs:180-213 (insert next to the founding_orientation override at :194).
|
||
|
||
ISOLATED SETTLEMENTS (no road_graph edges): take the water bearing from placement.founding_orientation — Coastal{facing_degrees} / RiverAligned{bearing_degrees} already encode it (octant = degrees/45). Note TerrainAnalysis::water_bearing (features.rs:133, u16 deg, 360=none) is NOT stored on CityPlacement/BodyWorldState, so reading founding_orientation is the clean access path (no attractor position-match needed).
|
||
|
||
CONSUMER: T-990 (done) emits AccessKind::QuarterEdge per octant in derive_access_points. The AdminFacing prestige-edge rule (pick the edge facing the highest-quality road entry) is forward-looking — no AdminFacing code exists yet — so order/annotate octants by quality only once that consumer lands.
|
||
|
||
ACCEPTANCE: a dispatched settlement whose city_id has >=1 road_graph edge emits >=1 AccessKind::QuarterEdge on the matching octant; BlockJunction fallback fires only for genuinely isolated settlements.
|
||
|
||
Governing: D-234, D-213, D-204 (footprint radius). T-990 (consumer, done), T-1022 (dispatch, done), T-1038 (road graph, shipped).
|
||
|
||
OVERLAP w/ T-1039: both edit build_skeleton_work_item (plugin.rs), city_context_reader.rs, CityGenerationContext (generator.rs). Implement both in ONE pass (one agent), not parallel.
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — locked decision + staleness corrections. Original scope authored 2026-06-12.
|
||
|
||
DECISION — road_entry_directions source: **USE T-1038''s RoadGraph (full fidelity). LOCKED.** The interim MST-neighbor path is DROPPED.
|
||
- T-1038 has shipped a populated `BodyWorldState.road_graph` (RoadGraph) with `RoadNode.city_id` and `RoadEdge.path` (A*-routed polylines in heightmap working-grid coords), available at dispatch time (BodyWorldState is fully populated before the GenCompletion branch in plugin.rs).
|
||
- Derive each entry octant from the bearing of the connecting road edge where it crosses the city footprint radius (D-204 footprint_radius), de-duplicated per octant — the D-234 "full fidelity" definition. Order/annotate by edge quality so the AdminFacing consumer (paula-round2.md:428-433: prestige edge faces the highest-quality road entry) can pick correctly.
|
||
- COUPLING ACCEPTED: T-1038 is still in_progress; if its RoadGraph field shapes shift, this consumer adjusts. (User accepted this tradeoff over the throwaway interim path.)
|
||
|
||
water_bearing: NOT a CityPlacement field — it is encoded inside the founding_orientation enum arms (Coastal{facing_degrees}, RiverAligned{bearing_degrees}); TerrainAnalysis is not stored on BodyWorldState (T-1044 TODO). With the RoadGraph as the primary source, water_bearing is secondary; if used as a supplementary octant for port/river settlements, extract the bearing from those two arms only — Cardinal/Free/TerrainFollowing variants get no water octant.
|
||
|
||
STALENESS / verified current locations: road_entry_directions field = generator.rs:1107; stub = city_context_reader.rs:478-479; derive_access_points = skeleton_gen.rs:1008-1036 (BlockJunction fallback :1029-1034); build_skeleton_work_item = plugin.rs:180-213. (Confirmed unchanged by T-1077/T-1078.)
|
||
|
||
COORDINATION: T-1039 and T-1043 both edit build_skeleton_work_item (plugin.rs:180-213). Do them as ONE combined branch/PR (single implementer), not two parallel edits to the same function. Thread road_entry_directions next to political_archetype/morphology_zone in the same override block.
|
||
|
||
Acceptance (unchanged): a dispatched settlement with ≥1 road connection produces ≥1 AccessKind::QuarterEdge node on the correct octant; the BlockJunction fallback fires only for genuinely isolated settlements.', 'done', 'medium', NULL, 'server', 'D-234', '2026-06-12 10:23:50', '2026-06-16 11:04:51', NULL, 'b4e826fe18cf961d6800470e396b3141', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ02KN9147H4Z12KJW7H1M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Thread political_archetype / arrangement_pattern / morphology_zone through the L3→L4 GenerateSkeleton dispatch', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
Thread the remaining Layer-3 character fields through the L3->L4 GenerateSkeleton dispatch. T-1022 wired the dispatch, but build_skeleton_work_item (server/src/atlas/plugin.rs:179-212) overrides only founding_orientation (:192-193); political_archetype stays the Commission stub (city_context_reader.rs:471-474) and morphology_zone stays AlluvialPlain (:487-488) even though:
|
||
- CityPlacement already carries the real political_archetype (D-214, derived from TerritorialStatus + economic_role at attractor_matching.rs:595-602) and arrangement_pattern (D-215, city_character at :282-293) — fields :49-64;
|
||
- the covering region''s real morphology_zone (D-239 §6 frozen vocab, T-1027, region_profile.rs:180/:499) is available from snapshot.layer_region, populated in the same cascade run (cascade.rs:238-240) — map placement.position to its covering region cell.
|
||
|
||
Consequences of the stubs: skeleton_gen''s morphology gating (D-234a Topology selection) always takes the AlluvialPlain Prim-MST mesh path — fjord/delta cities get plains street networks; block_irregularity/layout-mode always sees Commission (skeleton_gen.rs:68-77). D-234''s implementation note explicitly lists this threading as the pending dependency of the (done, tested, dormant) morphology-gated street rules.
|
||
|
||
Also decide arrangement_pattern''s path: CityGenerationContext has NO arrangement_pattern field (generator.rs:1078 has political_archetype only; ArrangementPattern :442 is defined but unconsumed at L4). Either (a) add the field and have skeleton_gen consume the D-215 explicit pattern, or (b) record that L4 derives layout from archetype alone and the placement''s pattern is Atlas/UI-only. Option (a) matches the workshop intent (ozzie-round1.md:112-118 backs explicit arrangement).
|
||
|
||
Miri''s queryability requirement (tile-derivation-contract/tyre-round1.md:308-311) — morphology_zone readable at Atlas-generation time — is satisfied by reading from BodyWorldState regions, no recompute.
|
||
|
||
Acceptance: dispatch a body with a FjordWall-region coastal placement in a CorpTerritory province -> the generated quarter uses Ribbon topology and CompanyTown-class layout, not mesh+Commission. Parent: T-750. Refs: D-214, D-215, D-228, D-234, D-239 §6; T-1022 (predecessor), T-983, T-1014 (adjacent, different fields).
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — READY. Supersedes stale region-scale refs (authored 2026-06-12, pre-T-1077 RegionProfile->DistrictProfile rename + T-1078). Current tree:
|
||
|
||
MORPHOLOGY CARRIER MOVED: morphology_zone now lives on DistrictProfile.morphology_zone (district_profile.rs:193, 2km carrier), NOT region_profile.rs. Snapshot field is layer_district (not layer_region — gone); map is BodyWorldState.districts (body_world_state.rs:102), populated by cascade (cascade.rs:270, converted :110-126). The ticket''s snapshot.layer_region / region_profile.rs:180/:499 / "covering region" refs are stale.
|
||
|
||
PLACEMENT->DISTRICT MAPPING: CityPlacement.position is heightmap pixel (row,col) (u16,u16) (attractor_matching.rs:51). DistrictPos = position / CELLS_PER_DISTRICT (8). No helper yet — add inline. Inverse at district_profile.rs:1023-1026.
|
||
|
||
STUB SITES: political_archetype stub city_context_reader.rs:474 (Commission); morphology_zone stub :488 (AlluvialPlain); both in context_from_read_set() (:462). build_skeleton_work_item (plugin.rs:180-213) threads only founding_orientation (:194) and does NOT receive the districts map — pass &state.districts in (available in the GenCompletion::BodyAnalyzed arm, plugin.rs:101) or resolve before the call; fallback AlluvialPlain on miss.
|
||
|
||
THREE OVERRIDES:
|
||
- political_archetype: one-liner — context.political_archetype = placement.political_archetype (real D-214 value, attractor_matching.rs:58/:602), parallel to founding_orientation at plugin.rs:194.
|
||
- morphology_zone: state.districts.get(&(pos.0/8, pos.1/8)).map(|d| d.morphology_zone).unwrap_or(AlluvialPlain).
|
||
- arrangement_pattern: OPTION (a) (D-215-backed) — CityGenerationContext has NO arrangement_pattern field (generator.rs:1098-1124); add it, thread placement.arrangement_pattern (attractor_matching.rs:60/:629), have skeleton_gen consume it (doesn''t yet).
|
||
|
||
CONSUMERS LIVE-BUT-DORMANT: street_topology() (skeleton_gen.rs:1048) gates on MorphologyZone (Ribbon: Fjord/CliffCoast/MountainPass/Alpine/ValleyFloor; HubSpoke: Delta/Estuarine/OpenOcean/Lake/DuneStrand/TidalFlat; Mesh: AlluvialPlain/MeanderReach/RiverBank/BraidedPlain/Wetland/Volcanic); derive_layout_mode (:235)+block_irregularity (:68) gate on political_archetype. T-989/T-990 done — always get AlluvialPlain+Commission until this lands.
|
||
|
||
ACCEPTANCE: FjordWall-region coastal placement in CorpTerritory -> Ribbon topology + CompanyTown/CampusGrid layout, not mesh+Commission.
|
||
|
||
Governing: D-234 (primary), D-214, D-215 (-> option a), D-239 sec 6 (frozen vocab, now district_profile.rs), D-243.
|
||
|
||
OVERLAP w/ T-1043: both edit build_skeleton_work_item (plugin.rs), city_context_reader.rs, CityGenerationContext (generator.rs), skeleton_gen consumers. Implement together in ONE pass (one agent), not parallel.
|
||
|
||
---
|
||
Refinement (2026-06-15, /whats-next Si pass) — staleness corrections + locked decision. Original scope authored 2026-06-12, BEFORE T-1077 (RegionProfile→DistrictProfile rename) and T-1078 (region climate tier, merged today). Corrected refs below.
|
||
|
||
STALENESS CORRECTIONS (the description''s code refs are pre-T-1077/T-1078):
|
||
- morphology_zone lives on **DistrictProfile** (server/src/atlas/district_profile.rs:193), NOT on RegionProfile (region_profile.rs:155 is a pure climate carrier — no morphology_zone). The ticket''s "region_profile.rs:180/:499" and "snapshot.layer_region" are wrong.
|
||
- Access path at dispatch: `state.districts.get(&district_pos)` on BodyWorldState.districts (server/src/atlas/body_world_state.rs:102). The cascade snapshot field is `layer_district` (cascade.rs:79), not `layer_region`.
|
||
- Position→DistrictPos: CityPlacement.position is (u16,u16) heightmap-pixel coords (attractor_matching.rs:51). Convert via the cells-per-district factor (currently a LOCAL `CELLS_PER_REGION = 8` in cascade.rs:260 — pre-D-243 naming). Do NOT hardcode 8 in plugin.rs: export a helper/const (prefer reusing server/src/atlas/scale.rs addressing) and call it from the dispatch.
|
||
- Verified current locations: build_skeleton_work_item = plugin.rs:180-213 (founding_orientation override is the threading site); political_archetype stub ~city_context_reader.rs:471-474; political_archetype derivation = attractor_matching.rs:602; CityPlacement fields ~attractor_matching.rs:49-64.
|
||
|
||
DECISION — arrangement_pattern path: **OPTION (b), re-derive. LOCKED.**
|
||
- skeleton_gen re-derives via the single shared pure fn `attractor_matching::arrangement_pattern(&political_archetype, &economic_role)` (attractor_matching.rs:629). Both inputs are available at L4: economic_role is ALREADY threaded (plugin.rs:189 reads it, :209 passes it); political_archetype is threaded by THIS ticket. NO new CityGenerationContext field; NO data-contract amendment.
|
||
- Rationale: arrangement_pattern is a pure TOTAL function (6-way archetype match + the `economic_role=="transit_hub"` override) — no seed/RNG/DB/clock/float. Re-derivation is provably identical to L3; cheaper to compute than to store; aligns with the "DB is only a cache, everything re-derivable from seed" principle (no stored derived spatial verdict).
|
||
- **HARDENING REQUIRED (the drift tripwire):** add a parity test asserting, for representative (archetype, economic_role) pairs, `arrangement_pattern(&placement.political_archetype, &placement.economic_role) == placement.arrangement_pattern` (CityPlacement already stores the L3-computed value at attractor_matching.rs:60). This locks L3≡L4 and trips the instant anyone changes arrangement_pattern''s input set. Optionally debug_assert the same equality in the dispatch. Never inline a second copy of the derivation — both sites call the one function.
|
||
|
||
COORDINATION: T-1039 and T-1043 both edit build_skeleton_work_item (plugin.rs:180-213). Do them as ONE combined branch/PR (single implementer), not two parallel edits to the same function.
|
||
|
||
Acceptance (unchanged): dispatch a FjordWall-region coastal placement in a CorpTerritory province → the generated quarter uses Ribbon topology and CompanyTown-class layout, not the AlluvialPlain mesh + Commission stub path.', 'done', 'high', NULL, 'server', 'D-234', '2026-06-12 10:23:49', '2026-06-16 11:04:51', NULL, 'faf93cbd0ceefe3a8b1052659931de23', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ0381QWDAQABZAY7MRD8M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Cache TerrainAnalysis on Layer1Output — drop the redundant per-body drainage re-run', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
---
|
||
Refinement (2026-06-16, /whats-next Si pass) — READY. Current-tree brief (line refs were ~15 lines off pre-T-1077/T-1078; the PERF/TODO(T-1044) marker pins it).
|
||
|
||
REDUNDANCY: run_layer1 (layer1.rs:44-74) computes drainage::analyze + TerrainAnalysis::analyze, but Layer1Output (layer1.rs:28-41) carries only river_network/drainage_basins/attractors. cascade.rs (~230-255, PERF/TODO(T-1044) at :235) RE-RUNS both from scratch to serve derive_all_districts (district_profile.rs:1356, takes &TerrainAnalysis) and build_road_graph (road_graph.rs:191, takes &TerrainAnalysis). ~45ms/body wasted (D-239 ref).
|
||
|
||
FIX: carry TerrainAnalysis from the run_layer1 pass and reuse it in cascade.rs instead of recomputing.
|
||
SERIALIZE decision: TerrainAnalysis derives Debug+Clone only (features.rs:65); Layer1Output derives Serialize/Deserialize. Per D-203/T-1048 the LRU per-entry size is already a concern (TerrainAnalysis is ~2MB of full-grid Vecs) — so PREFER holding it transiently on CascadeSnapshot (drop after the cascade consumes it) rather than persisting it on the LRU-cached Layer1Output. If it must live on Layer1Output, use #[serde(skip)] + re-derive on deserialize. Do NOT bloat the cached state.
|
||
|
||
COMPOSE WITH T-1047 (same batch): T-1047 aggregates a per-district dominant-D8-direction in the SAME run_layer1 pass — do both together to avoid double-touching layer1.rs/cascade.rs.
|
||
|
||
Acceptance: T-1031 harness cost drops toward ~45ms/body; T-952 golden-seed byte-identity UNCHANGED. Files: layer1.rs, cascade.rs (+ CascadeSnapshot if transient).', 'backlog', 'medium', NULL, 'server', 'D-203', '2026-06-12 10:23:50', '2026-06-16 13:21:25', NULL, '42b619776712ed47b206bb7ed3694ead', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXP5N42SSGW300FEDTS3M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Derive ChunkContext basin_direction from the L1 D8 thalweg; fix the false doc comment', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-36; citations adversarially verified).
|
||
derive_basin_direction (chunk_context.rs:211-231) branches only on ocean_fraction_q then picks a direction from seed bits in both branches; the doc comment (:201-210) falsely claims an elev_q-gradient proxy; the module contract (:12-13, :40-42) claims D8-thalweg derivation. BodyWorldState.river_network exists (body_world_state.rs:79) and is never consulted — chunk-scale water has no guarantee of flowing downhill or connecting across the 16-chunk region-seed boundary. D-239 §8 binding law: respect the D8 thalweg.
|
||
Fix: compute the covering region''s dominant D8 direction during the RegionProfile pass (DrainageResult is in scope there) and thread it into RegionProfile for derive_chunk_context to read; fix the misleading comments either way. Composes with T-1040 (channel anchor) and T-1042 (seam blend).
|
||
|
||
---
|
||
Refinement (2026-06-16, /whats-next Si pass) — staleness corrected + resolution. Original scope pre-T-1077.
|
||
|
||
STALENESS (critical): the ticket says thread basin_direction into "RegionProfile" — WRONG post-T-1077. The per-chunk carrier derive_chunk_context receives is **DistrictProfile** (2km). The new RegionProfile (region_profile.rs) is the 205km climate tier (T-1078) and is NOT passed to derive_chunk_context. Thread basin_direction into **DistrictProfile**.
|
||
|
||
CURRENT LOCATIONS: derive_basin_direction = chunk_context.rs:453-483 (false comment :453-462 claims an elev_q/slope_q D8-gradient proxy but the body branches only on ocean_fraction_q>=15 then picks from seed bits; module header :12-13 claims D8-thalweg). BodyWorldState.river_network = body_world_state.rs:80 (stub, never consulted). fdir (D8 flow-dir grid) is computed in drainage.rs:81 but DROPPED (not on DrainageResult :44-56).
|
||
|
||
RESOLUTION (D-239 §8 BINDS the D8 thalweg → flow_accumulation alone is insufficient; use the true fdir): in run_layer1 (where fdir is still alive, before it''s discarded), aggregate the dominant D8 direction PER DISTRICT and carry that small per-district direction map on Layer1Output — which composes directly with T-1044''s Layer1Output caching. Thread it through derive_all_districts → derive_district_profile → DistrictProfile.basin_direction; derive_chunk_context reads district.basin_direction. Fix the false doc comment + module contract either way. Do NOT expose the full 131KB fdir grid on DrainageResult — aggregate to per-district direction in the pass.
|
||
|
||
COMPOSE WITH T-1044 (same batch, same layer1.rs/cascade.rs flow). Acceptance: chunk-scale channels respect the covering district''s D8 thalweg (flow downhill, connect across the chunk/region-seed boundary); false comment corrected; golden-seed determinism preserved.', 'backlog', 'medium', NULL, 'server', 'D-239', '2026-06-12 10:40:58', '2026-06-16 13:21:25', NULL, '67324ec668b83efda3cce9e0975ad2c7', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPE8FR7TGEM7X6QVPV4M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Refine T-961 into per-asset-class stories, each gated on a written brief', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-43; citations adversarially verified).
|
||
T-961 (two-sentence description, no acceptance criteria, no brief links) is the only asset-production ticket under T-750, while the epic names eight classes; cars, barns, TVs, billboards appear in NO ticket at all (verified against the full corpus). Refine into child stories per class — station walls, rural walls, doors, floors, furniture/props, street furniture (lamp posts), signage/screens (billboards/TVs), rural structures (barns) — each gated on a one-page brief; explicitly record which classes are deferred (cars: see Q-067 audit note). Decide Q-119 (generic-parent placeholder set as first milestone) before sequencing.
|
||
Audit per-class status matrix (verified 2026-06-12):
|
||
# docs/assets/ survey (13 files + downloads/)
|
||
|
||
| File | One-line summary |
|
||
|---|---|
|
||
| README.md | Master index: audio/visual/video pipelines, status vocabulary (planned/in-progress/placeholder/final), structure that promises visual/{sprites,furniture,tilesets,icons,effects}.md |
|
||
| _templates/audio.md | Row + detailed-entry template for audio assets |
|
||
| _templates/sprite.md | Row + detailed-entry template for sprites (ID prefixes SPR/FUR/TILE/ICO/FX, status, method, directions columns) |
|
||
| _templates/video.md | Row + detailed-entry template for video |
|
||
| audio/README.md | ACTIVE production-status catalog — per-category counts table (12 assets tracked), generation tools, bus architecture |
|
||
| audio/palette.md | Sonic style bible |
|
||
| audio/ambient.md / sfx.md / ui.md | Per-category audio asset tables |
|
||
| visual/README.md | STUB — links 5 category files that do not exist, all counts 0 |
|
||
| visual/palette.md | STUB — 4 bullet decisions (D-019/D-033/D-045, "functional warmth"), defers to art-direction workshop |
|
||
| video/README.md / palette.md | Stubs |
|
||
| downloads/ | Purchased character sources (Quaternius Universal Base Characters, Modular Character Outfits FBX) — characters only |
|
||
|
||
# Per-asset-class matrix
|
||
|
||
| Class | Written brief | Style guide | Naming/res conventions | Gen path | Produced assets | Tickets |
|
||
|---|---|---|---|---|---|---|
|
||
| Walls (station) | art-direction workshop-outcomes.md §3.3 (v0.1.1 set, pre-cascade) + docs/design/placeholder-art-spec-v01.md §2.1 | visual-grammar-v01.md §1/§4.3, workshop-outcomes §1.8 era palette (partly superseded by D-235), D-235 WallMaterial vocab | renderer/README.md:80-95 (`<model>_<dir>_<res>.png`, 1024→256→64 chain) | working — renderer/models/wall_structural.tscn rendered | wall_structural ×4 dirs in client/assets/sprites/; wall_bar_green model unrendered; 2 textures | T-961 (backlog), T-988 (token vocab, backlog) |
|
||
| Walls (rural) | none found | D-235 tokens only (timber/rammed-earth etc.) | renderer/README.md (generic) | same path, unused | none | T-961 text mention only |
|
||
| Doors | placeholder-art-spec-v01.md §2.1 (procedural rects, v0.1) + workshop-outcomes §3.3 `door_sliding` | none for generated world | none for open/closed state frames | same path, unused | none | T-979/T-998 (DoorSpec — logical only), T-961 |
|
||
| Floors | placeholder-art-spec-v01.md §2.1 + workshop-outcomes §3.3 (4 floor sprites) | D-228 FloorMaterial axis (open vocab) | 64px visual tile (placeholder-art-spec §1) | same path, unused | none — client/assets/tilesets/ is .gitkeep only | T-959 (tile fill, logical), T-961 |
|
||
| Styled buildings | D-232 + D-235 + wiki/economics/architecture_trait_catalog.toml (T-1005 done, ~35 visual bundles) | D-235 material/color-register grammar — tokens only, no rendered art direction | token→fallback-parent chain (catalog header :34-44) | no model/texture path defined for building exteriors | none | T-977, T-988, T-994, T-1004 (all backlog), T-1005 (done) |
|
||
| Furniture | docs/assets/visual/furniture.md MISSING (linked); workshop-outcomes §3.3 lists 8-10 objects (pre-cascade) | era table §1.8 only | character-asset-organization.md explicitly excludes furniture ("follow Trellis spike conventions") | proven in spike | spikes/3dpipeline/models/furniture/ ×3 GLB (unpromoted); zero in client/assets | T-961, T-995 (ObjectTag vocab, backlog) |
|
||
| Items | docs/design/icon-set-v01.md (HUD/inventory icons only) | D-086 icon constraints | SVG icon_ prefix (client/assets/icons/) | n/a for icons | 13 SVGs in client/assets/icons/ | none for in-world item sprites |
|
||
| Cars/vehicles | none found | none | none | spike only | spikes/3dpipeline/models/props/vw_beetle.glb (spike) | none — Q-067 open ("driveable vs NPC traffic?") |
|
||
| Lamp posts | none found (zero repo hits) | none | none | unused | none | T-961 text mention only |
|
||
| Barns | none found (only T-750 epic text) | none | none | unused | none | none |
|
||
| TVs | none found (only T-750 epic text) | none | none | unused | none | none |
|
||
| Billboards | none found (only T-750 epic text; other hits = LOD impostors) | none | none | unused | none | none |
|
||
| Characters (reference class — the working model) | docs/architecture/character-asset-organization.md + docs/design/character-visuals-spec.md | yes | full (manifest.json, seg_ naming, body-type keys) | proven end-to-end | 1002 files in client/assets/characters/ | done |
|
||
|
||
# Generation path (verified files)
|
||
image-gen (.claude/skills/image-gen/SKILL.md + scripts/image_connector.py, Gemini) → glb-gen (SKILL.md + tooling/db/trellis_connector.py + tooling/trellis-batch.sh + Blender postprocess scripts) → sprite-gen (SKILL.md + scripts/render.sh) → renderer/ (project.godot, render_scene.tscn, render_export.gd; D-019 camera, 3-light rig, 1024/256/64 chain) → client/assets/sprites/. renderer/output/ holds only .gdignore (intermediates gitignored).
|
||
|
||
# Produced assets in client/assets (non-.import files)
|
||
audio 16 · characters 1002 · fonts 3 · icons 13 · planets 7 · sprites 9 (npc_generic ×4, wall_structural ×4, .gitkeep) · theme 1 · tilesets 1 (.gitkeep only)
|
||
|
||
---
|
||
Refinement (2026-06-16, /whats-next Si pass) — READY. This is a PLANNING task: break T-961 into per-class child stories.
|
||
|
||
CLASS LIST (8 stories, parented under T-961, each gated on a one-page brief): station walls, rural walls, doors, floors, furniture/props, street furniture (lamp posts), signage/screens (TVs/billboards), rural structures (barns).
|
||
- CARS (9th class named in T-750): DEFERRED — Q-067 needs a phase decision (Phase-4 deliverable vs Phase-5+) before any car story. File a deferral note, not a story.
|
||
- Q-119 (generic-parent placeholder set as milestone-0): NOT a blocker — sequencing only. On each relevant story note that the generic parents (generic_wall/roof/facade/street + generic_door/floor/furniture; D-235 / wiki/economics/architecture_trait_catalog.toml:33-41) are milestone-0 IF Q-119 resolves "yes".
|
||
|
||
BRIEF TEMPLATE: none exists. Create docs/assets/_templates/asset-brief.md (scope · visual reference · naming/resolution conventions · generation path · acceptance), or adopt docs/_templates/design.md. Each story states where its brief + catalog file live under docs/assets/visual/.
|
||
READ before filing: docs/assets/README.md, docs/design/{placeholder-art-spec-v01,visual-grammar-v01}.md, docs/workshops/art-direction-mood-board/workshop-outcomes.md, D-235/D-228/D-232, docs/architecture/character-asset-organization.md (the reference model).
|
||
NOTE: T-1050 (sibling) owns the catalog + naming conventions these stories reference — sequence T-1049 to consume T-1050''s conventions where they overlap.', 'backlog', 'high', NULL, 'visual', NULL, '2026-06-12 10:40:58', '2026-06-16 13:21:48', NULL, '24db28c07edc3ea2d5daa36db28ff74f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPJ910NNR5T2R9F9NWQR', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Create the visual production-status catalog; fix glb-gen production path + naming conventions', '(description follows in first append)
|
||
|
||
---
|
||
Refinement (2026-06-16, /whats-next Si pass) — FULL scope (user decision). Two deliverables + conventions.
|
||
|
||
(1) CATALOG: instantiate the 5 docs/assets/visual/*.md files (sprites, furniture, tilesets, icons, effects) with per-category status tables. Template: docs/assets/_templates/sprite.md (SPR/FUR/TILE/ICO/FX prefixes); status vocab planned/in-progress/placeholder/final (docs/assets/README.md). Audio side (docs/assets/audio/README.md) is the working model.
|
||
|
||
(2) glb-gen PRODUCTION PATH: SKILL.md:115 names client/assets/models/ which does NOT exist. Create it + furniture/ + props/ subdirs (mirror the spike) + .gitkeep. Define client/assets/models/manifest.json schema MIRRORING the character manifest (docs/architecture/character-asset-organization.md) — per-asset entries: name, category, source-model path, subdirectory. Promotion convention per D-241 (promotion = repo-canonical). Update SKILL.md to point at the new path + reference the manifest.
|
||
|
||
(3) CONVENTIONS (author NOW, full scope): door state-frame suffixes (e.g. <model>_open / <model>_closed), Godot TileSet resource organization (<tileset>/<tile_id>.tres), multi-tile footprint metadata, and renderer/textures/ naming keyed to D-235 tokens (current renderer/README.md:80-95 covers sprites only: <model>_<direction>_<resolution>.png). Author these in docs/assets/visual/conventions.md (single home) and cross-link from the SKILL.
|
||
|
||
OVERLAP: T-1053 (rewrite araminta briefing) softly depends on this catalog — note the edge. T-1049''s per-class stories will reference these conventions — do T-1050 first / concurrently so T-1049 can cite them.', 'backlog', 'high', NULL, 'visual', NULL, '2026-06-12 10:40:59', '2026-06-16 13:21:48', NULL, '546f75f2fa3361ebd0e88026ae90b3e9', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPE8FR7TGEM7X6QVPV4M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Refine T-961 into per-asset-class stories, each gated on a written brief', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-43; citations adversarially verified).
|
||
T-961 (two-sentence description, no acceptance criteria, no brief links) is the only asset-production ticket under T-750, while the epic names eight classes; cars, barns, TVs, billboards appear in NO ticket at all (verified against the full corpus). Refine into child stories per class — station walls, rural walls, doors, floors, furniture/props, street furniture (lamp posts), signage/screens (billboards/TVs), rural structures (barns) — each gated on a one-page brief; explicitly record which classes are deferred (cars: see Q-067 audit note). Decide Q-119 (generic-parent placeholder set as first milestone) before sequencing.
|
||
Audit per-class status matrix (verified 2026-06-12):
|
||
# docs/assets/ survey (13 files + downloads/)
|
||
|
||
| File | One-line summary |
|
||
|---|---|
|
||
| README.md | Master index: audio/visual/video pipelines, status vocabulary (planned/in-progress/placeholder/final), structure that promises visual/{sprites,furniture,tilesets,icons,effects}.md |
|
||
| _templates/audio.md | Row + detailed-entry template for audio assets |
|
||
| _templates/sprite.md | Row + detailed-entry template for sprites (ID prefixes SPR/FUR/TILE/ICO/FX, status, method, directions columns) |
|
||
| _templates/video.md | Row + detailed-entry template for video |
|
||
| audio/README.md | ACTIVE production-status catalog — per-category counts table (12 assets tracked), generation tools, bus architecture |
|
||
| audio/palette.md | Sonic style bible |
|
||
| audio/ambient.md / sfx.md / ui.md | Per-category audio asset tables |
|
||
| visual/README.md | STUB — links 5 category files that do not exist, all counts 0 |
|
||
| visual/palette.md | STUB — 4 bullet decisions (D-019/D-033/D-045, "functional warmth"), defers to art-direction workshop |
|
||
| video/README.md / palette.md | Stubs |
|
||
| downloads/ | Purchased character sources (Quaternius Universal Base Characters, Modular Character Outfits FBX) — characters only |
|
||
|
||
# Per-asset-class matrix
|
||
|
||
| Class | Written brief | Style guide | Naming/res conventions | Gen path | Produced assets | Tickets |
|
||
|---|---|---|---|---|---|---|
|
||
| Walls (station) | art-direction workshop-outcomes.md §3.3 (v0.1.1 set, pre-cascade) + docs/design/placeholder-art-spec-v01.md §2.1 | visual-grammar-v01.md §1/§4.3, workshop-outcomes §1.8 era palette (partly superseded by D-235), D-235 WallMaterial vocab | renderer/README.md:80-95 (`<model>_<dir>_<res>.png`, 1024→256→64 chain) | working — renderer/models/wall_structural.tscn rendered | wall_structural ×4 dirs in client/assets/sprites/; wall_bar_green model unrendered; 2 textures | T-961 (backlog), T-988 (token vocab, backlog) |
|
||
| Walls (rural) | none found | D-235 tokens only (timber/rammed-earth etc.) | renderer/README.md (generic) | same path, unused | none | T-961 text mention only |
|
||
| Doors | placeholder-art-spec-v01.md §2.1 (procedural rects, v0.1) + workshop-outcomes §3.3 `door_sliding` | none for generated world | none for open/closed state frames | same path, unused | none | T-979/T-998 (DoorSpec — logical only), T-961 |
|
||
| Floors | placeholder-art-spec-v01.md §2.1 + workshop-outcomes §3.3 (4 floor sprites) | D-228 FloorMaterial axis (open vocab) | 64px visual tile (placeholder-art-spec §1) | same path, unused | none — client/assets/tilesets/ is .gitkeep only | T-959 (tile fill, logical), T-961 |
|
||
| Styled buildings | D-232 + D-235 + wiki/economics/architecture_trait_catalog.toml (T-1005 done, ~35 visual bundles) | D-235 material/color-register grammar — tokens only, no rendered art direction | token→fallback-parent chain (catalog header :34-44) | no model/texture path defined for building exteriors | none | T-977, T-988, T-994, T-1004 (all backlog), T-1005 (done) |
|
||
| Furniture | docs/assets/visual/furniture.md MISSING (linked); workshop-outcomes §3.3 lists 8-10 objects (pre-cascade) | era table §1.8 only | character-asset-organization.md explicitly excludes furniture ("follow Trellis spike conventions") | proven in spike | spikes/3dpipeline/models/furniture/ ×3 GLB (unpromoted); zero in client/assets | T-961, T-995 (ObjectTag vocab, backlog) |
|
||
| Items | docs/design/icon-set-v01.md (HUD/inventory icons only) | D-086 icon constraints | SVG icon_ prefix (client/assets/icons/) | n/a for icons | 13 SVGs in client/assets/icons/ | none for in-world item sprites |
|
||
| Cars/vehicles | none found | none | none | spike only | spikes/3dpipeline/models/props/vw_beetle.glb (spike) | none — Q-067 open ("driveable vs NPC traffic?") |
|
||
| Lamp posts | none found (zero repo hits) | none | none | unused | none | T-961 text mention only |
|
||
| Barns | none found (only T-750 epic text) | none | none | unused | none | none |
|
||
| TVs | none found (only T-750 epic text) | none | none | unused | none | none |
|
||
| Billboards | none found (only T-750 epic text; other hits = LOD impostors) | none | none | unused | none | none |
|
||
| Characters (reference class — the working model) | docs/architecture/character-asset-organization.md + docs/design/character-visuals-spec.md | yes | full (manifest.json, seg_ naming, body-type keys) | proven end-to-end | 1002 files in client/assets/characters/ | done |
|
||
|
||
# Generation path (verified files)
|
||
image-gen (.claude/skills/image-gen/SKILL.md + scripts/image_connector.py, Gemini) → glb-gen (SKILL.md + tooling/db/trellis_connector.py + tooling/trellis-batch.sh + Blender postprocess scripts) → sprite-gen (SKILL.md + scripts/render.sh) → renderer/ (project.godot, render_scene.tscn, render_export.gd; D-019 camera, 3-light rig, 1024/256/64 chain) → client/assets/sprites/. renderer/output/ holds only .gdignore (intermediates gitignored).
|
||
|
||
# Produced assets in client/assets (non-.import files)
|
||
audio 16 · characters 1002 · fonts 3 · icons 13 · planets 7 · sprites 9 (npc_generic ×4, wall_structural ×4, .gitkeep) · theme 1 · tilesets 1 (.gitkeep only)
|
||
|
||
---
|
||
Refinement (2026-06-16, /whats-next Si pass) — READY. This is a PLANNING task: break T-961 into per-class child stories.
|
||
|
||
CLASS LIST (8 stories, parented under T-961, each gated on a one-page brief): station walls, rural walls, doors, floors, furniture/props, street furniture (lamp posts), signage/screens (TVs/billboards), rural structures (barns).
|
||
- CARS (9th class named in T-750): DEFERRED — Q-067 needs a phase decision (Phase-4 deliverable vs Phase-5+) before any car story. File a deferral note, not a story.
|
||
- Q-119 (generic-parent placeholder set as milestone-0): NOT a blocker — sequencing only. On each relevant story note that the generic parents (generic_wall/roof/facade/street + generic_door/floor/furniture; D-235 / wiki/economics/architecture_trait_catalog.toml:33-41) are milestone-0 IF Q-119 resolves "yes".
|
||
|
||
BRIEF TEMPLATE: none exists. Create docs/assets/_templates/asset-brief.md (scope · visual reference · naming/resolution conventions · generation path · acceptance), or adopt docs/_templates/design.md. Each story states where its brief + catalog file live under docs/assets/visual/.
|
||
READ before filing: docs/assets/README.md, docs/design/{placeholder-art-spec-v01,visual-grammar-v01}.md, docs/workshops/art-direction-mood-board/workshop-outcomes.md, D-235/D-228/D-232, docs/architecture/character-asset-organization.md (the reference model).
|
||
NOTE: T-1050 (sibling) owns the catalog + naming conventions these stories reference — sequence T-1049 to consume T-1050''s conventions where they overlap.', 'in_progress', 'high', NULL, 'visual', NULL, '2026-06-12 10:40:58', '2026-06-16 13:42:26', NULL, '4ab36440ca481dfd0b8ec757119219ad', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPJ910NNR5T2R9F9NWQR', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Create the visual production-status catalog; fix glb-gen production path + naming conventions', '(description follows in first append)
|
||
|
||
---
|
||
Refinement (2026-06-16, /whats-next Si pass) — FULL scope (user decision). Two deliverables + conventions.
|
||
|
||
(1) CATALOG: instantiate the 5 docs/assets/visual/*.md files (sprites, furniture, tilesets, icons, effects) with per-category status tables. Template: docs/assets/_templates/sprite.md (SPR/FUR/TILE/ICO/FX prefixes); status vocab planned/in-progress/placeholder/final (docs/assets/README.md). Audio side (docs/assets/audio/README.md) is the working model.
|
||
|
||
(2) glb-gen PRODUCTION PATH: SKILL.md:115 names client/assets/models/ which does NOT exist. Create it + furniture/ + props/ subdirs (mirror the spike) + .gitkeep. Define client/assets/models/manifest.json schema MIRRORING the character manifest (docs/architecture/character-asset-organization.md) — per-asset entries: name, category, source-model path, subdirectory. Promotion convention per D-241 (promotion = repo-canonical). Update SKILL.md to point at the new path + reference the manifest.
|
||
|
||
(3) CONVENTIONS (author NOW, full scope): door state-frame suffixes (e.g. <model>_open / <model>_closed), Godot TileSet resource organization (<tileset>/<tile_id>.tres), multi-tile footprint metadata, and renderer/textures/ naming keyed to D-235 tokens (current renderer/README.md:80-95 covers sprites only: <model>_<direction>_<resolution>.png). Author these in docs/assets/visual/conventions.md (single home) and cross-link from the SKILL.
|
||
|
||
OVERLAP: T-1053 (rewrite araminta briefing) softly depends on this catalog — note the edge. T-1049''s per-class stories will reference these conventions — do T-1050 first / concurrently so T-1049 can cite them.', 'in_progress', 'high', NULL, 'visual', NULL, '2026-06-12 10:40:59', '2026-06-16 13:42:26', NULL, '54f99e24429bfd5b5ef93327759619d5', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXP5N42SSGW300FEDTS3M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Derive ChunkContext basin_direction from the L1 D8 thalweg; fix the false doc comment', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-36; citations adversarially verified).
|
||
derive_basin_direction (chunk_context.rs:211-231) branches only on ocean_fraction_q then picks a direction from seed bits in both branches; the doc comment (:201-210) falsely claims an elev_q-gradient proxy; the module contract (:12-13, :40-42) claims D8-thalweg derivation. BodyWorldState.river_network exists (body_world_state.rs:79) and is never consulted — chunk-scale water has no guarantee of flowing downhill or connecting across the 16-chunk region-seed boundary. D-239 §8 binding law: respect the D8 thalweg.
|
||
Fix: compute the covering region''s dominant D8 direction during the RegionProfile pass (DrainageResult is in scope there) and thread it into RegionProfile for derive_chunk_context to read; fix the misleading comments either way. Composes with T-1040 (channel anchor) and T-1042 (seam blend).
|
||
|
||
---
|
||
Refinement (2026-06-16, /whats-next Si pass) — staleness corrected + resolution. Original scope pre-T-1077.
|
||
|
||
STALENESS (critical): the ticket says thread basin_direction into "RegionProfile" — WRONG post-T-1077. The per-chunk carrier derive_chunk_context receives is **DistrictProfile** (2km). The new RegionProfile (region_profile.rs) is the 205km climate tier (T-1078) and is NOT passed to derive_chunk_context. Thread basin_direction into **DistrictProfile**.
|
||
|
||
CURRENT LOCATIONS: derive_basin_direction = chunk_context.rs:453-483 (false comment :453-462 claims an elev_q/slope_q D8-gradient proxy but the body branches only on ocean_fraction_q>=15 then picks from seed bits; module header :12-13 claims D8-thalweg). BodyWorldState.river_network = body_world_state.rs:80 (stub, never consulted). fdir (D8 flow-dir grid) is computed in drainage.rs:81 but DROPPED (not on DrainageResult :44-56).
|
||
|
||
RESOLUTION (D-239 §8 BINDS the D8 thalweg → flow_accumulation alone is insufficient; use the true fdir): in run_layer1 (where fdir is still alive, before it''s discarded), aggregate the dominant D8 direction PER DISTRICT and carry that small per-district direction map on Layer1Output — which composes directly with T-1044''s Layer1Output caching. Thread it through derive_all_districts → derive_district_profile → DistrictProfile.basin_direction; derive_chunk_context reads district.basin_direction. Fix the false doc comment + module contract either way. Do NOT expose the full 131KB fdir grid on DrainageResult — aggregate to per-district direction in the pass.
|
||
|
||
COMPOSE WITH T-1044 (same batch, same layer1.rs/cascade.rs flow). Acceptance: chunk-scale channels respect the covering district''s D8 thalweg (flow downhill, connect across the chunk/region-seed boundary); false comment corrected; golden-seed determinism preserved.', 'in_progress', 'medium', NULL, 'server', 'D-239', '2026-06-12 10:40:58', '2026-06-16 13:42:26', NULL, 'a1c329e777e2f9b0465ecdb645693a5a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ0381QWDAQABZAY7MRD8M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Cache TerrainAnalysis on Layer1Output — drop the redundant per-body drainage re-run', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
---
|
||
Refinement (2026-06-16, /whats-next Si pass) — READY. Current-tree brief (line refs were ~15 lines off pre-T-1077/T-1078; the PERF/TODO(T-1044) marker pins it).
|
||
|
||
REDUNDANCY: run_layer1 (layer1.rs:44-74) computes drainage::analyze + TerrainAnalysis::analyze, but Layer1Output (layer1.rs:28-41) carries only river_network/drainage_basins/attractors. cascade.rs (~230-255, PERF/TODO(T-1044) at :235) RE-RUNS both from scratch to serve derive_all_districts (district_profile.rs:1356, takes &TerrainAnalysis) and build_road_graph (road_graph.rs:191, takes &TerrainAnalysis). ~45ms/body wasted (D-239 ref).
|
||
|
||
FIX: carry TerrainAnalysis from the run_layer1 pass and reuse it in cascade.rs instead of recomputing.
|
||
SERIALIZE decision: TerrainAnalysis derives Debug+Clone only (features.rs:65); Layer1Output derives Serialize/Deserialize. Per D-203/T-1048 the LRU per-entry size is already a concern (TerrainAnalysis is ~2MB of full-grid Vecs) — so PREFER holding it transiently on CascadeSnapshot (drop after the cascade consumes it) rather than persisting it on the LRU-cached Layer1Output. If it must live on Layer1Output, use #[serde(skip)] + re-derive on deserialize. Do NOT bloat the cached state.
|
||
|
||
COMPOSE WITH T-1047 (same batch): T-1047 aggregates a per-district dominant-D8-direction in the SAME run_layer1 pass — do both together to avoid double-touching layer1.rs/cascade.rs.
|
||
|
||
Acceptance: T-1031 harness cost drops toward ~45ms/body; T-952 golden-seed byte-identity UNCHANGED. Files: layer1.rs, cascade.rs (+ CascadeSnapshot if transient).', 'in_progress', 'medium', NULL, 'server', 'D-203', '2026-06-12 10:23:50', '2026-06-16 13:42:26', NULL, 'acb7bf02efc3a7d7f4418f7d6c151204', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPE8FR7TGEM7X6QVPV4M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Refine T-961 into per-asset-class stories, each gated on a written brief', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-43; citations adversarially verified).
|
||
T-961 (two-sentence description, no acceptance criteria, no brief links) is the only asset-production ticket under T-750, while the epic names eight classes; cars, barns, TVs, billboards appear in NO ticket at all (verified against the full corpus). Refine into child stories per class — station walls, rural walls, doors, floors, furniture/props, street furniture (lamp posts), signage/screens (billboards/TVs), rural structures (barns) — each gated on a one-page brief; explicitly record which classes are deferred (cars: see Q-067 audit note). Decide Q-119 (generic-parent placeholder set as first milestone) before sequencing.
|
||
Audit per-class status matrix (verified 2026-06-12):
|
||
# docs/assets/ survey (13 files + downloads/)
|
||
|
||
| File | One-line summary |
|
||
|---|---|
|
||
| README.md | Master index: audio/visual/video pipelines, status vocabulary (planned/in-progress/placeholder/final), structure that promises visual/{sprites,furniture,tilesets,icons,effects}.md |
|
||
| _templates/audio.md | Row + detailed-entry template for audio assets |
|
||
| _templates/sprite.md | Row + detailed-entry template for sprites (ID prefixes SPR/FUR/TILE/ICO/FX, status, method, directions columns) |
|
||
| _templates/video.md | Row + detailed-entry template for video |
|
||
| audio/README.md | ACTIVE production-status catalog — per-category counts table (12 assets tracked), generation tools, bus architecture |
|
||
| audio/palette.md | Sonic style bible |
|
||
| audio/ambient.md / sfx.md / ui.md | Per-category audio asset tables |
|
||
| visual/README.md | STUB — links 5 category files that do not exist, all counts 0 |
|
||
| visual/palette.md | STUB — 4 bullet decisions (D-019/D-033/D-045, "functional warmth"), defers to art-direction workshop |
|
||
| video/README.md / palette.md | Stubs |
|
||
| downloads/ | Purchased character sources (Quaternius Universal Base Characters, Modular Character Outfits FBX) — characters only |
|
||
|
||
# Per-asset-class matrix
|
||
|
||
| Class | Written brief | Style guide | Naming/res conventions | Gen path | Produced assets | Tickets |
|
||
|---|---|---|---|---|---|---|
|
||
| Walls (station) | art-direction workshop-outcomes.md §3.3 (v0.1.1 set, pre-cascade) + docs/design/placeholder-art-spec-v01.md §2.1 | visual-grammar-v01.md §1/§4.3, workshop-outcomes §1.8 era palette (partly superseded by D-235), D-235 WallMaterial vocab | renderer/README.md:80-95 (`<model>_<dir>_<res>.png`, 1024→256→64 chain) | working — renderer/models/wall_structural.tscn rendered | wall_structural ×4 dirs in client/assets/sprites/; wall_bar_green model unrendered; 2 textures | T-961 (backlog), T-988 (token vocab, backlog) |
|
||
| Walls (rural) | none found | D-235 tokens only (timber/rammed-earth etc.) | renderer/README.md (generic) | same path, unused | none | T-961 text mention only |
|
||
| Doors | placeholder-art-spec-v01.md §2.1 (procedural rects, v0.1) + workshop-outcomes §3.3 `door_sliding` | none for generated world | none for open/closed state frames | same path, unused | none | T-979/T-998 (DoorSpec — logical only), T-961 |
|
||
| Floors | placeholder-art-spec-v01.md §2.1 + workshop-outcomes §3.3 (4 floor sprites) | D-228 FloorMaterial axis (open vocab) | 64px visual tile (placeholder-art-spec §1) | same path, unused | none — client/assets/tilesets/ is .gitkeep only | T-959 (tile fill, logical), T-961 |
|
||
| Styled buildings | D-232 + D-235 + wiki/economics/architecture_trait_catalog.toml (T-1005 done, ~35 visual bundles) | D-235 material/color-register grammar — tokens only, no rendered art direction | token→fallback-parent chain (catalog header :34-44) | no model/texture path defined for building exteriors | none | T-977, T-988, T-994, T-1004 (all backlog), T-1005 (done) |
|
||
| Furniture | docs/assets/visual/furniture.md MISSING (linked); workshop-outcomes §3.3 lists 8-10 objects (pre-cascade) | era table §1.8 only | character-asset-organization.md explicitly excludes furniture ("follow Trellis spike conventions") | proven in spike | spikes/3dpipeline/models/furniture/ ×3 GLB (unpromoted); zero in client/assets | T-961, T-995 (ObjectTag vocab, backlog) |
|
||
| Items | docs/design/icon-set-v01.md (HUD/inventory icons only) | D-086 icon constraints | SVG icon_ prefix (client/assets/icons/) | n/a for icons | 13 SVGs in client/assets/icons/ | none for in-world item sprites |
|
||
| Cars/vehicles | none found | none | none | spike only | spikes/3dpipeline/models/props/vw_beetle.glb (spike) | none — Q-067 open ("driveable vs NPC traffic?") |
|
||
| Lamp posts | none found (zero repo hits) | none | none | unused | none | T-961 text mention only |
|
||
| Barns | none found (only T-750 epic text) | none | none | unused | none | none |
|
||
| TVs | none found (only T-750 epic text) | none | none | unused | none | none |
|
||
| Billboards | none found (only T-750 epic text; other hits = LOD impostors) | none | none | unused | none | none |
|
||
| Characters (reference class — the working model) | docs/architecture/character-asset-organization.md + docs/design/character-visuals-spec.md | yes | full (manifest.json, seg_ naming, body-type keys) | proven end-to-end | 1002 files in client/assets/characters/ | done |
|
||
|
||
# Generation path (verified files)
|
||
image-gen (.claude/skills/image-gen/SKILL.md + scripts/image_connector.py, Gemini) → glb-gen (SKILL.md + tooling/db/trellis_connector.py + tooling/trellis-batch.sh + Blender postprocess scripts) → sprite-gen (SKILL.md + scripts/render.sh) → renderer/ (project.godot, render_scene.tscn, render_export.gd; D-019 camera, 3-light rig, 1024/256/64 chain) → client/assets/sprites/. renderer/output/ holds only .gdignore (intermediates gitignored).
|
||
|
||
# Produced assets in client/assets (non-.import files)
|
||
audio 16 · characters 1002 · fonts 3 · icons 13 · planets 7 · sprites 9 (npc_generic ×4, wall_structural ×4, .gitkeep) · theme 1 · tilesets 1 (.gitkeep only)
|
||
|
||
---
|
||
Refinement (2026-06-16, /whats-next Si pass) — READY. This is a PLANNING task: break T-961 into per-class child stories.
|
||
|
||
CLASS LIST (8 stories, parented under T-961, each gated on a one-page brief): station walls, rural walls, doors, floors, furniture/props, street furniture (lamp posts), signage/screens (TVs/billboards), rural structures (barns).
|
||
- CARS (9th class named in T-750): DEFERRED — Q-067 needs a phase decision (Phase-4 deliverable vs Phase-5+) before any car story. File a deferral note, not a story.
|
||
- Q-119 (generic-parent placeholder set as milestone-0): NOT a blocker — sequencing only. On each relevant story note that the generic parents (generic_wall/roof/facade/street + generic_door/floor/furniture; D-235 / wiki/economics/architecture_trait_catalog.toml:33-41) are milestone-0 IF Q-119 resolves "yes".
|
||
|
||
BRIEF TEMPLATE: none exists. Create docs/assets/_templates/asset-brief.md (scope · visual reference · naming/resolution conventions · generation path · acceptance), or adopt docs/_templates/design.md. Each story states where its brief + catalog file live under docs/assets/visual/.
|
||
READ before filing: docs/assets/README.md, docs/design/{placeholder-art-spec-v01,visual-grammar-v01}.md, docs/workshops/art-direction-mood-board/workshop-outcomes.md, D-235/D-228/D-232, docs/architecture/character-asset-organization.md (the reference model).
|
||
NOTE: T-1050 (sibling) owns the catalog + naming conventions these stories reference — sequence T-1049 to consume T-1050''s conventions where they overlap.
|
||
|
||
---
|
||
HELD 2026-06-16 (separated from the cascade batch; needs re-scoping before resuming).
|
||
The asset pipeline this ticket assumes is sprite-centric (docs/assets/visual/sprites.md
|
||
"Entities", _templates/sprite.md, SPR/FUR/TILE/ICO/FX prefixes, the /sprite-gen
|
||
render-3D->2D-sprites step). Direction correction: we are NOT producing sprites — Trellis
|
||
produces 3D objects (.glb) displayed in-world; the only flattened 2D content is TEXTURES.
|
||
Re-scope this ticket around a 3D-model + texture catalog (not a sprite catalog) before
|
||
activating. See the sprite-vs-3D root-cause note (this session).', 'in_progress', 'high', NULL, 'visual', NULL, '2026-06-12 10:40:58', '2026-06-16 14:01:36.325', NULL, '038b6bd5130fced6f3038983a03a709b', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPJ910NNR5T2R9F9NWQR', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Create the visual production-status catalog; fix glb-gen production path + naming conventions', '(description follows in first append)
|
||
|
||
---
|
||
Refinement (2026-06-16, /whats-next Si pass) — FULL scope (user decision). Two deliverables + conventions.
|
||
|
||
(1) CATALOG: instantiate the 5 docs/assets/visual/*.md files (sprites, furniture, tilesets, icons, effects) with per-category status tables. Template: docs/assets/_templates/sprite.md (SPR/FUR/TILE/ICO/FX prefixes); status vocab planned/in-progress/placeholder/final (docs/assets/README.md). Audio side (docs/assets/audio/README.md) is the working model.
|
||
|
||
(2) glb-gen PRODUCTION PATH: SKILL.md:115 names client/assets/models/ which does NOT exist. Create it + furniture/ + props/ subdirs (mirror the spike) + .gitkeep. Define client/assets/models/manifest.json schema MIRRORING the character manifest (docs/architecture/character-asset-organization.md) — per-asset entries: name, category, source-model path, subdirectory. Promotion convention per D-241 (promotion = repo-canonical). Update SKILL.md to point at the new path + reference the manifest.
|
||
|
||
(3) CONVENTIONS (author NOW, full scope): door state-frame suffixes (e.g. <model>_open / <model>_closed), Godot TileSet resource organization (<tileset>/<tile_id>.tres), multi-tile footprint metadata, and renderer/textures/ naming keyed to D-235 tokens (current renderer/README.md:80-95 covers sprites only: <model>_<direction>_<resolution>.png). Author these in docs/assets/visual/conventions.md (single home) and cross-link from the SKILL.
|
||
|
||
OVERLAP: T-1053 (rewrite araminta briefing) softly depends on this catalog — note the edge. T-1049''s per-class stories will reference these conventions — do T-1050 first / concurrently so T-1049 can cite them.
|
||
|
||
---
|
||
HELD 2026-06-16 (separated from the cascade batch; needs re-scoping before resuming).
|
||
The asset pipeline this ticket assumes is sprite-centric (docs/assets/visual/sprites.md
|
||
"Entities", _templates/sprite.md, SPR/FUR/TILE/ICO/FX prefixes, the /sprite-gen
|
||
render-3D->2D-sprites step). Direction correction: we are NOT producing sprites — Trellis
|
||
produces 3D objects (.glb) displayed in-world; the only flattened 2D content is TEXTURES.
|
||
Re-scope this ticket around a 3D-model + texture catalog (not a sprite catalog) before
|
||
activating. See the sprite-vs-3D root-cause note (this session).', 'in_progress', 'high', NULL, 'visual', NULL, '2026-06-12 10:40:59', '2026-06-16 14:01:36.350', NULL, 'f6a5625e47450d6e4a37c65e3165c904', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPE8FR7TGEM7X6QVPV4M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Refine T-961 into per-asset-class stories, each gated on a written brief', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-43; citations adversarially verified).
|
||
T-961 (two-sentence description, no acceptance criteria, no brief links) is the only asset-production ticket under T-750, while the epic names eight classes; cars, barns, TVs, billboards appear in NO ticket at all (verified against the full corpus). Refine into child stories per class — station walls, rural walls, doors, floors, furniture/props, street furniture (lamp posts), signage/screens (billboards/TVs), rural structures (barns) — each gated on a one-page brief; explicitly record which classes are deferred (cars: see Q-067 audit note). Decide Q-119 (generic-parent placeholder set as first milestone) before sequencing.
|
||
Audit per-class status matrix (verified 2026-06-12):
|
||
# docs/assets/ survey (13 files + downloads/)
|
||
|
||
| File | One-line summary |
|
||
|---|---|
|
||
| README.md | Master index: audio/visual/video pipelines, status vocabulary (planned/in-progress/placeholder/final), structure that promises visual/{sprites,furniture,tilesets,icons,effects}.md |
|
||
| _templates/audio.md | Row + detailed-entry template for audio assets |
|
||
| _templates/sprite.md | Row + detailed-entry template for sprites (ID prefixes SPR/FUR/TILE/ICO/FX, status, method, directions columns) |
|
||
| _templates/video.md | Row + detailed-entry template for video |
|
||
| audio/README.md | ACTIVE production-status catalog — per-category counts table (12 assets tracked), generation tools, bus architecture |
|
||
| audio/palette.md | Sonic style bible |
|
||
| audio/ambient.md / sfx.md / ui.md | Per-category audio asset tables |
|
||
| visual/README.md | STUB — links 5 category files that do not exist, all counts 0 |
|
||
| visual/palette.md | STUB — 4 bullet decisions (D-019/D-033/D-045, "functional warmth"), defers to art-direction workshop |
|
||
| video/README.md / palette.md | Stubs |
|
||
| downloads/ | Purchased character sources (Quaternius Universal Base Characters, Modular Character Outfits FBX) — characters only |
|
||
|
||
# Per-asset-class matrix
|
||
|
||
| Class | Written brief | Style guide | Naming/res conventions | Gen path | Produced assets | Tickets |
|
||
|---|---|---|---|---|---|---|
|
||
| Walls (station) | art-direction workshop-outcomes.md §3.3 (v0.1.1 set, pre-cascade) + docs/design/placeholder-art-spec-v01.md §2.1 | visual-grammar-v01.md §1/§4.3, workshop-outcomes §1.8 era palette (partly superseded by D-235), D-235 WallMaterial vocab | renderer/README.md:80-95 (`<model>_<dir>_<res>.png`, 1024→256→64 chain) | working — renderer/models/wall_structural.tscn rendered | wall_structural ×4 dirs in client/assets/sprites/; wall_bar_green model unrendered; 2 textures | T-961 (backlog), T-988 (token vocab, backlog) |
|
||
| Walls (rural) | none found | D-235 tokens only (timber/rammed-earth etc.) | renderer/README.md (generic) | same path, unused | none | T-961 text mention only |
|
||
| Doors | placeholder-art-spec-v01.md §2.1 (procedural rects, v0.1) + workshop-outcomes §3.3 `door_sliding` | none for generated world | none for open/closed state frames | same path, unused | none | T-979/T-998 (DoorSpec — logical only), T-961 |
|
||
| Floors | placeholder-art-spec-v01.md §2.1 + workshop-outcomes §3.3 (4 floor sprites) | D-228 FloorMaterial axis (open vocab) | 64px visual tile (placeholder-art-spec §1) | same path, unused | none — client/assets/tilesets/ is .gitkeep only | T-959 (tile fill, logical), T-961 |
|
||
| Styled buildings | D-232 + D-235 + wiki/economics/architecture_trait_catalog.toml (T-1005 done, ~35 visual bundles) | D-235 material/color-register grammar — tokens only, no rendered art direction | token→fallback-parent chain (catalog header :34-44) | no model/texture path defined for building exteriors | none | T-977, T-988, T-994, T-1004 (all backlog), T-1005 (done) |
|
||
| Furniture | docs/assets/visual/furniture.md MISSING (linked); workshop-outcomes §3.3 lists 8-10 objects (pre-cascade) | era table §1.8 only | character-asset-organization.md explicitly excludes furniture ("follow Trellis spike conventions") | proven in spike | spikes/3dpipeline/models/furniture/ ×3 GLB (unpromoted); zero in client/assets | T-961, T-995 (ObjectTag vocab, backlog) |
|
||
| Items | docs/design/icon-set-v01.md (HUD/inventory icons only) | D-086 icon constraints | SVG icon_ prefix (client/assets/icons/) | n/a for icons | 13 SVGs in client/assets/icons/ | none for in-world item sprites |
|
||
| Cars/vehicles | none found | none | none | spike only | spikes/3dpipeline/models/props/vw_beetle.glb (spike) | none — Q-067 open ("driveable vs NPC traffic?") |
|
||
| Lamp posts | none found (zero repo hits) | none | none | unused | none | T-961 text mention only |
|
||
| Barns | none found (only T-750 epic text) | none | none | unused | none | none |
|
||
| TVs | none found (only T-750 epic text) | none | none | unused | none | none |
|
||
| Billboards | none found (only T-750 epic text; other hits = LOD impostors) | none | none | unused | none | none |
|
||
| Characters (reference class — the working model) | docs/architecture/character-asset-organization.md + docs/design/character-visuals-spec.md | yes | full (manifest.json, seg_ naming, body-type keys) | proven end-to-end | 1002 files in client/assets/characters/ | done |
|
||
|
||
# Generation path (verified files)
|
||
image-gen (.claude/skills/image-gen/SKILL.md + scripts/image_connector.py, Gemini) → glb-gen (SKILL.md + tooling/db/trellis_connector.py + tooling/trellis-batch.sh + Blender postprocess scripts) → sprite-gen (SKILL.md + scripts/render.sh) → renderer/ (project.godot, render_scene.tscn, render_export.gd; D-019 camera, 3-light rig, 1024/256/64 chain) → client/assets/sprites/. renderer/output/ holds only .gdignore (intermediates gitignored).
|
||
|
||
# Produced assets in client/assets (non-.import files)
|
||
audio 16 · characters 1002 · fonts 3 · icons 13 · planets 7 · sprites 9 (npc_generic ×4, wall_structural ×4, .gitkeep) · theme 1 · tilesets 1 (.gitkeep only)
|
||
|
||
---
|
||
Refinement (2026-06-16, /whats-next Si pass) — READY. This is a PLANNING task: break T-961 into per-class child stories.
|
||
|
||
CLASS LIST (8 stories, parented under T-961, each gated on a one-page brief): station walls, rural walls, doors, floors, furniture/props, street furniture (lamp posts), signage/screens (TVs/billboards), rural structures (barns).
|
||
- CARS (9th class named in T-750): DEFERRED — Q-067 needs a phase decision (Phase-4 deliverable vs Phase-5+) before any car story. File a deferral note, not a story.
|
||
- Q-119 (generic-parent placeholder set as milestone-0): NOT a blocker — sequencing only. On each relevant story note that the generic parents (generic_wall/roof/facade/street + generic_door/floor/furniture; D-235 / wiki/economics/architecture_trait_catalog.toml:33-41) are milestone-0 IF Q-119 resolves "yes".
|
||
|
||
BRIEF TEMPLATE: none exists. Create docs/assets/_templates/asset-brief.md (scope · visual reference · naming/resolution conventions · generation path · acceptance), or adopt docs/_templates/design.md. Each story states where its brief + catalog file live under docs/assets/visual/.
|
||
READ before filing: docs/assets/README.md, docs/design/{placeholder-art-spec-v01,visual-grammar-v01}.md, docs/workshops/art-direction-mood-board/workshop-outcomes.md, D-235/D-228/D-232, docs/architecture/character-asset-organization.md (the reference model).
|
||
NOTE: T-1050 (sibling) owns the catalog + naming conventions these stories reference — sequence T-1049 to consume T-1050''s conventions where they overlap.
|
||
|
||
---
|
||
HELD 2026-06-16 (separated from the cascade batch; needs re-scoping before resuming).
|
||
The asset pipeline this ticket assumes is sprite-centric (docs/assets/visual/sprites.md
|
||
"Entities", _templates/sprite.md, SPR/FUR/TILE/ICO/FX prefixes, the /sprite-gen
|
||
render-3D->2D-sprites step). Direction correction: we are NOT producing sprites — Trellis
|
||
produces 3D objects (.glb) displayed in-world; the only flattened 2D content is TEXTURES.
|
||
Re-scope this ticket around a 3D-model + texture catalog (not a sprite catalog) before
|
||
activating. See the sprite-vs-3D root-cause note (this session).', 'backlog', 'high', NULL, 'visual', NULL, '2026-06-12 10:40:58', '2026-06-16 14:01:36.369', NULL, '24d0abe148f4ebd5536619cc12c94c06', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPJ910NNR5T2R9F9NWQR', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Create the visual production-status catalog; fix glb-gen production path + naming conventions', '(description follows in first append)
|
||
|
||
---
|
||
Refinement (2026-06-16, /whats-next Si pass) — FULL scope (user decision). Two deliverables + conventions.
|
||
|
||
(1) CATALOG: instantiate the 5 docs/assets/visual/*.md files (sprites, furniture, tilesets, icons, effects) with per-category status tables. Template: docs/assets/_templates/sprite.md (SPR/FUR/TILE/ICO/FX prefixes); status vocab planned/in-progress/placeholder/final (docs/assets/README.md). Audio side (docs/assets/audio/README.md) is the working model.
|
||
|
||
(2) glb-gen PRODUCTION PATH: SKILL.md:115 names client/assets/models/ which does NOT exist. Create it + furniture/ + props/ subdirs (mirror the spike) + .gitkeep. Define client/assets/models/manifest.json schema MIRRORING the character manifest (docs/architecture/character-asset-organization.md) — per-asset entries: name, category, source-model path, subdirectory. Promotion convention per D-241 (promotion = repo-canonical). Update SKILL.md to point at the new path + reference the manifest.
|
||
|
||
(3) CONVENTIONS (author NOW, full scope): door state-frame suffixes (e.g. <model>_open / <model>_closed), Godot TileSet resource organization (<tileset>/<tile_id>.tres), multi-tile footprint metadata, and renderer/textures/ naming keyed to D-235 tokens (current renderer/README.md:80-95 covers sprites only: <model>_<direction>_<resolution>.png). Author these in docs/assets/visual/conventions.md (single home) and cross-link from the SKILL.
|
||
|
||
OVERLAP: T-1053 (rewrite araminta briefing) softly depends on this catalog — note the edge. T-1049''s per-class stories will reference these conventions — do T-1050 first / concurrently so T-1049 can cite them.
|
||
|
||
---
|
||
HELD 2026-06-16 (separated from the cascade batch; needs re-scoping before resuming).
|
||
The asset pipeline this ticket assumes is sprite-centric (docs/assets/visual/sprites.md
|
||
"Entities", _templates/sprite.md, SPR/FUR/TILE/ICO/FX prefixes, the /sprite-gen
|
||
render-3D->2D-sprites step). Direction correction: we are NOT producing sprites — Trellis
|
||
produces 3D objects (.glb) displayed in-world; the only flattened 2D content is TEXTURES.
|
||
Re-scope this ticket around a 3D-model + texture catalog (not a sprite catalog) before
|
||
activating. See the sprite-vs-3D root-cause note (this session).', 'backlog', 'high', NULL, 'visual', NULL, '2026-06-12 10:40:59', '2026-06-16 14:01:36.371', NULL, '21d429fe79add1fb53ca64a8113c8a82', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ0381QWDAQABZAY7MRD8M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Cache TerrainAnalysis on Layer1Output — drop the redundant per-body drainage re-run', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
---
|
||
Refinement (2026-06-16, /whats-next Si pass) — READY. Current-tree brief (line refs were ~15 lines off pre-T-1077/T-1078; the PERF/TODO(T-1044) marker pins it).
|
||
|
||
REDUNDANCY: run_layer1 (layer1.rs:44-74) computes drainage::analyze + TerrainAnalysis::analyze, but Layer1Output (layer1.rs:28-41) carries only river_network/drainage_basins/attractors. cascade.rs (~230-255, PERF/TODO(T-1044) at :235) RE-RUNS both from scratch to serve derive_all_districts (district_profile.rs:1356, takes &TerrainAnalysis) and build_road_graph (road_graph.rs:191, takes &TerrainAnalysis). ~45ms/body wasted (D-239 ref).
|
||
|
||
FIX: carry TerrainAnalysis from the run_layer1 pass and reuse it in cascade.rs instead of recomputing.
|
||
SERIALIZE decision: TerrainAnalysis derives Debug+Clone only (features.rs:65); Layer1Output derives Serialize/Deserialize. Per D-203/T-1048 the LRU per-entry size is already a concern (TerrainAnalysis is ~2MB of full-grid Vecs) — so PREFER holding it transiently on CascadeSnapshot (drop after the cascade consumes it) rather than persisting it on the LRU-cached Layer1Output. If it must live on Layer1Output, use #[serde(skip)] + re-derive on deserialize. Do NOT bloat the cached state.
|
||
|
||
COMPOSE WITH T-1047 (same batch): T-1047 aggregates a per-district dominant-D8-direction in the SAME run_layer1 pass — do both together to avoid double-touching layer1.rs/cascade.rs.
|
||
|
||
Acceptance: T-1031 harness cost drops toward ~45ms/body; T-952 golden-seed byte-identity UNCHANGED. Files: layer1.rs, cascade.rs (+ CascadeSnapshot if transient).', 'review', 'medium', NULL, 'server', 'D-203', '2026-06-12 10:23:50', '2026-06-17 07:48:14.916', NULL, '00965d9d3a6244baf5af1e8bc1e0641c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXP5N42SSGW300FEDTS3M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Derive ChunkContext basin_direction from the L1 D8 thalweg; fix the false doc comment', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-36; citations adversarially verified).
|
||
derive_basin_direction (chunk_context.rs:211-231) branches only on ocean_fraction_q then picks a direction from seed bits in both branches; the doc comment (:201-210) falsely claims an elev_q-gradient proxy; the module contract (:12-13, :40-42) claims D8-thalweg derivation. BodyWorldState.river_network exists (body_world_state.rs:79) and is never consulted — chunk-scale water has no guarantee of flowing downhill or connecting across the 16-chunk region-seed boundary. D-239 §8 binding law: respect the D8 thalweg.
|
||
Fix: compute the covering region''s dominant D8 direction during the RegionProfile pass (DrainageResult is in scope there) and thread it into RegionProfile for derive_chunk_context to read; fix the misleading comments either way. Composes with T-1040 (channel anchor) and T-1042 (seam blend).
|
||
|
||
---
|
||
Refinement (2026-06-16, /whats-next Si pass) — staleness corrected + resolution. Original scope pre-T-1077.
|
||
|
||
STALENESS (critical): the ticket says thread basin_direction into "RegionProfile" — WRONG post-T-1077. The per-chunk carrier derive_chunk_context receives is **DistrictProfile** (2km). The new RegionProfile (region_profile.rs) is the 205km climate tier (T-1078) and is NOT passed to derive_chunk_context. Thread basin_direction into **DistrictProfile**.
|
||
|
||
CURRENT LOCATIONS: derive_basin_direction = chunk_context.rs:453-483 (false comment :453-462 claims an elev_q/slope_q D8-gradient proxy but the body branches only on ocean_fraction_q>=15 then picks from seed bits; module header :12-13 claims D8-thalweg). BodyWorldState.river_network = body_world_state.rs:80 (stub, never consulted). fdir (D8 flow-dir grid) is computed in drainage.rs:81 but DROPPED (not on DrainageResult :44-56).
|
||
|
||
RESOLUTION (D-239 §8 BINDS the D8 thalweg → flow_accumulation alone is insufficient; use the true fdir): in run_layer1 (where fdir is still alive, before it''s discarded), aggregate the dominant D8 direction PER DISTRICT and carry that small per-district direction map on Layer1Output — which composes directly with T-1044''s Layer1Output caching. Thread it through derive_all_districts → derive_district_profile → DistrictProfile.basin_direction; derive_chunk_context reads district.basin_direction. Fix the false doc comment + module contract either way. Do NOT expose the full 131KB fdir grid on DrainageResult — aggregate to per-district direction in the pass.
|
||
|
||
COMPOSE WITH T-1044 (same batch, same layer1.rs/cascade.rs flow). Acceptance: chunk-scale channels respect the covering district''s D8 thalweg (flow downhill, connect across the chunk/region-seed boundary); false comment corrected; golden-seed determinism preserved.', 'review', 'medium', NULL, 'server', 'D-239', '2026-06-12 10:40:58', '2026-06-17 07:48:14.919', NULL, 'd23b3a339e46f292dbf6b65c9018ead0', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPQ0381QWDAQABZAY7MRD8M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Cache TerrainAnalysis on Layer1Output — drop the redundant per-body drainage re-run', 'Workshopped-but-unticketed cascade work captured 2026-06-12 (cascade-refocus grounding pass). Full grounded scope follows.
|
||
|
||
---
|
||
Refinement (2026-06-16, /whats-next Si pass) — READY. Current-tree brief (line refs were ~15 lines off pre-T-1077/T-1078; the PERF/TODO(T-1044) marker pins it).
|
||
|
||
REDUNDANCY: run_layer1 (layer1.rs:44-74) computes drainage::analyze + TerrainAnalysis::analyze, but Layer1Output (layer1.rs:28-41) carries only river_network/drainage_basins/attractors. cascade.rs (~230-255, PERF/TODO(T-1044) at :235) RE-RUNS both from scratch to serve derive_all_districts (district_profile.rs:1356, takes &TerrainAnalysis) and build_road_graph (road_graph.rs:191, takes &TerrainAnalysis). ~45ms/body wasted (D-239 ref).
|
||
|
||
FIX: carry TerrainAnalysis from the run_layer1 pass and reuse it in cascade.rs instead of recomputing.
|
||
SERIALIZE decision: TerrainAnalysis derives Debug+Clone only (features.rs:65); Layer1Output derives Serialize/Deserialize. Per D-203/T-1048 the LRU per-entry size is already a concern (TerrainAnalysis is ~2MB of full-grid Vecs) — so PREFER holding it transiently on CascadeSnapshot (drop after the cascade consumes it) rather than persisting it on the LRU-cached Layer1Output. If it must live on Layer1Output, use #[serde(skip)] + re-derive on deserialize. Do NOT bloat the cached state.
|
||
|
||
COMPOSE WITH T-1047 (same batch): T-1047 aggregates a per-district dominant-D8-direction in the SAME run_layer1 pass — do both together to avoid double-touching layer1.rs/cascade.rs.
|
||
|
||
Acceptance: T-1031 harness cost drops toward ~45ms/body; T-952 golden-seed byte-identity UNCHANGED. Files: layer1.rs, cascade.rs (+ CascadeSnapshot if transient).', 'done', 'medium', NULL, 'server', 'D-203', '2026-06-12 10:23:50', '2026-06-17 08:14:43.302', NULL, 'feb5cd321c4a3e079f1f85fac6e79450', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXP5N42SSGW300FEDTS3M', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Derive ChunkContext basin_direction from the L1 D8 thalweg; fix the false doc comment', '(description follows in first append)
|
||
|
||
Filed 2026-06-12 from the fable-ous.md audit (S-36; citations adversarially verified).
|
||
derive_basin_direction (chunk_context.rs:211-231) branches only on ocean_fraction_q then picks a direction from seed bits in both branches; the doc comment (:201-210) falsely claims an elev_q-gradient proxy; the module contract (:12-13, :40-42) claims D8-thalweg derivation. BodyWorldState.river_network exists (body_world_state.rs:79) and is never consulted — chunk-scale water has no guarantee of flowing downhill or connecting across the 16-chunk region-seed boundary. D-239 §8 binding law: respect the D8 thalweg.
|
||
Fix: compute the covering region''s dominant D8 direction during the RegionProfile pass (DrainageResult is in scope there) and thread it into RegionProfile for derive_chunk_context to read; fix the misleading comments either way. Composes with T-1040 (channel anchor) and T-1042 (seam blend).
|
||
|
||
---
|
||
Refinement (2026-06-16, /whats-next Si pass) — staleness corrected + resolution. Original scope pre-T-1077.
|
||
|
||
STALENESS (critical): the ticket says thread basin_direction into "RegionProfile" — WRONG post-T-1077. The per-chunk carrier derive_chunk_context receives is **DistrictProfile** (2km). The new RegionProfile (region_profile.rs) is the 205km climate tier (T-1078) and is NOT passed to derive_chunk_context. Thread basin_direction into **DistrictProfile**.
|
||
|
||
CURRENT LOCATIONS: derive_basin_direction = chunk_context.rs:453-483 (false comment :453-462 claims an elev_q/slope_q D8-gradient proxy but the body branches only on ocean_fraction_q>=15 then picks from seed bits; module header :12-13 claims D8-thalweg). BodyWorldState.river_network = body_world_state.rs:80 (stub, never consulted). fdir (D8 flow-dir grid) is computed in drainage.rs:81 but DROPPED (not on DrainageResult :44-56).
|
||
|
||
RESOLUTION (D-239 §8 BINDS the D8 thalweg → flow_accumulation alone is insufficient; use the true fdir): in run_layer1 (where fdir is still alive, before it''s discarded), aggregate the dominant D8 direction PER DISTRICT and carry that small per-district direction map on Layer1Output — which composes directly with T-1044''s Layer1Output caching. Thread it through derive_all_districts → derive_district_profile → DistrictProfile.basin_direction; derive_chunk_context reads district.basin_direction. Fix the false doc comment + module contract either way. Do NOT expose the full 131KB fdir grid on DrainageResult — aggregate to per-district direction in the pass.
|
||
|
||
COMPOSE WITH T-1044 (same batch, same layer1.rs/cascade.rs flow). Acceptance: chunk-scale channels respect the covering district''s D8 thalweg (flow downhill, connect across the chunk/region-seed boundary); false comment corrected; golden-seed determinism preserved.', 'done', 'medium', NULL, 'server', 'D-239', '2026-06-12 10:40:58', '2026-06-17 08:14:43.306', NULL, 'e221e440c3be0db6d0de73a2544dfb9d', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJNP8YM537DJCC82ZD6544', 'epic', '06FB0TNSRZXCHGS16BFHSSGSV4', 'World believability — generated terrain reads uniform / incoherent', 'Surfaced by the aliveness probe (server/src/bin/aliveness_probe.rs, branch fillchunk-shell-derive) run on Arbour (GJ338Bd — temperate, ocean hydrosphere) at seed ''yolo'' (u64 15217401773476501448). The deterministic cascade produces 2048 districts; the D-239 derivation LAWS fire correctly, yet the generated surface does not read as a living, real place. Across 6 probes (1 anchored ~150 chunks west of the principal city ''Arbour'' + 5 random districts) the world is uniform wet forest with the sea rendered as dry land. Key insight: this is the ''passes every binding law yet reads dead'' case — the lever is input-field VARIANCE + missing water rendering, not the laws. This epic groups the believability gaps (children) + the repeatable test protocol that found them, as a direction to discuss improvements. Sibling to T-974 (Atlas-to-tile derivation, the laws) and T-1031 (law-correctness harness).', 'backlog', 'high', NULL, 'server', 'D-239', '2026-06-28 05:53:59.367', '2026-06-28 05:53:59.367', NULL, 'c09388c27f79ef43cfe8d9fe9d8fc59c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJTXTADJRHYEE1WTAENYAG', 'story', '06FGSJNP8YM537DJCC82ZD6544', 'District climate fields lack spatial gradient — uniform moisture/precip/vegetation yields monotone terrain', 'Probe evidence (Arbour @ yolo): moisture_q=80, precip=SuperHumid, veg_class=Forest in ~every one of 2048 districts; the voxel layer then derives terrain=Wetland 100% everywhere. The derivation is LAW-CORRECT (flat + wet -> Wetland, D-239 section 8) — the defect is upstream: the district-scale climate/moisture field has near-zero cross-district variance, so there is no gradient to drive ecotones, material variety, or vegetation bands. Without gradient the ''edge-fuzzed climate'' promise is invisible (nothing to fuzz). Direction to discuss: where moisture/precip SHOULD vary (latitude, orography/rain-shadow, continentality, distance-to-water) and how to introduce believable spatial gradient into the district derivation. Believability gap, not a crash.', 'backlog', 'high', NULL, 'server', 'D-239', '2026-06-28 05:54:42.258', '2026-06-28 05:54:42.258', NULL, 'aaddcb91ab512b3ad4c6082e2eac7a7a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJVW30PSP8K0XAWV02X7M0', 'story', '06FGSJNP8YM537DJCC82ZD6544', 'Near-zero voxel relief (0-3 m) — generated terrain has no hills or landmarks', 'Probe evidence (Arbour @ yolo): voxel elevation 0-3 m across nearly all sampled districts (only one snow upland reached 42-49 m). Flat terrain => nothing to navigate by, no landmarks, no ''specificity of place''. Either the heightmap relief is being flattened by the 512x256 working downsample + district derivation, or detail-scatter (D-227, derive-don''t-store) is not producing the mid-scale relief it is supposed to invent at the voxel tier. Direction to discuss: the relief envelope taken from the heightmap, detail-scatter amplitude, and whether the elev_q -> elevation_m mapping is collapsing the range. Believability gap.', 'backlog', 'high', NULL, 'server', 'D-227', '2026-06-28 05:54:50.008', '2026-06-28 05:54:50.008', NULL, '9f28b4d0b936b41704fe0050ade0c0de', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJWWZNWYT3C4T828ZF1QCG', 'story', '06FGSJNP8YM537DJCC82ZD6544', 'No water-body voxel generator — OpenOcean/Lake/TidalFlat render as dry land', 'Probe evidence (Arbour @ yolo, an OCEAN world): OpenOcean districts derive water=Dry 100% with vegetation Forest 62% on Wetland substrate — i.e. the sea is painted as dry forested land. Root cause (voxel.rs zone_to_family): OpenOcean/Lake/TidalFlat/Wetland fall back to the AlluvialPlain (dry-land) generator; there is no water-body generator that lays Water::Deep/Shallow for water zones, sets a sea/lake surface elevation, or forms coastlines. On an ocean world this means the majority of the surface renders wrong. Known incompleteness (the fallback is documented), filed so it has a home. Direction to discuss: a water-body morphology family (ocean / lake / tidal-flat) that sets Deep/Shallow water + substrate + coast, and how sea level (heightmap sea_level threshold) feeds it.', 'backlog', 'high', NULL, 'server', 'D-239', '2026-06-28 05:54:58.429', '2026-06-28 05:54:58.429', NULL, '32335455bf6a4aa3594d9608ffcc36f4', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJZG3WFPQ3VXBFQFM4YEWW', 'story', '06FGSJNP8YM537DJCC82ZD6544', 'Repeatable believability test protocol — cross-district contrast + coherence metrics (promote aliveness_probe)', 'Promote the throwaway probe (server/src/bin/aliveness_probe.rs) into a committed, repeatable believability test protocol — the instrument that found T-1080/T-1081/T-1082. For a body+seed it runs the deterministic cascade and emits: (1) cross-district CONTRAST/variance metrics — moisture, elevation/relief, slope, morphology-zone diversity, terrain-material diversity, vegetation gradient — the screen that catches ''uniform/dead'' worlds; (2) COHERENCE checks with pass/fail — water zones must render wet, vegetation must correlate with moisture/water-distance/slope/aspect, drainage monotonic; (3) optional per-layer PNG maps (a stopgap for the T-960 Atlas viewer). LESSON BAKED IN: the first naive ''is it vegetated'' metric reported a broken uniform world as ALIVE — so the protocol MUST measure CONTRAST + COHERENCE across samples, never marginal per-tile counts. Make it runnable per-body, deterministic (string seed -> u64), snapshot a baseline for regression. This is the D-245 ENFORCER. NOTE: today it samples at the DISTRICT tier because no production code maps a world chunk -> covering DistrictProfile yet (voxel layer is a walking skeleton). Distinct from T-1031 (binding-LAW harness); believability sibling. Relates to T-960.', 'backlog', 'high', NULL, 'server', 'D-239', '2026-06-28 05:55:19.712', '2026-06-28 05:55:19.712', NULL, '3e1032301c73c7f67834767c2a12261a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSK19FGZAC3H25VRAV4JRFW', 'story', '06FGSJNP8YM537DJCC82ZD6544', 'Intra-class micro-habitat mosaic — seed-scattered sub-features within every terrain type', 'A third believability lever, distinct from T-1080 (macro field gradient) and T-1081 (relief): within a SINGLE terrain class the sub-chunk seed should paint a spatially-coherent mosaic of micro-habitats, generalized to ALL terrain types. Motivating case: the probe''s ''Wetland 100%'' should resolve into clearings, copses, creeks, meadows, bogs, marshes — and likewise for every other class. NOT D-210/T-948: D-210 SubBiomeVariant is a MACRO biome tag per attractor (Tundra vs TemperateForest vs Wetland) — ''which biome''. THIS is finer: the intra-class MICRO-mosaic (''texture within a class''), at sub-chunk (<64 m) scale. MECHANIC: district/biome picks the PALETTE; the sub-chunk seed (SeedDomain::Voxel) paints the MOSAIC, reusing the derive-don''t-store tier (detail_scatter.rs, domain_warp, D-227). Three properties: (1) spatially COHERENT — patches (copse/clearing/bog/meadow) are blobs via low-frequency noise; creeks are lines following micro-drainage; never per-tile salt-and-pepper. (2) causally CONDITIONED on micro-relief/micro-drainage/moisture/slope/aspect (bogs in wettest lows, meadows on drier rises, copses where drainage improves, creeks along micro-thalwegs) — legible, not random. (3) MODULATES the existing D-228 axes, not a new axis. PER-CLASS VOCAB (one mechanism, per-class data): Wetland: clearing/copse/creek/meadow/bog/marsh; Forest: glade/dense stand/deadfall/brook/fern undergrowth; Grassland: tussock/scrub island/wildflower/dry wash; Sand: dune crest/slack/hardpan/oasis/scrub clump; Rock: outcrop/scree/ledge/lichen/talus; Gravel: bar/active channel/vegetated island; Lava: fresh sheet/weathered crust/tube collapse/pioneer scrub. Needs a Q/D-record before implementation. Relates to T-948 (D-210 macro), T-1081 (relief, a conditioning input), T-1083 (protocol must measure intra-class mosaic diversity).', 'backlog', 'high', NULL, 'server', 'D-227', '2026-06-28 05:55:34.396', '2026-06-28 05:55:34.396', NULL, '07753cff879301374f7dd5c6bd343b83', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJNP8YM537DJCC82ZD6544', 'epic', '06FB0TNSRZXCHGS16BFHSSGSV4', 'World believability — generated terrain reads uniform / incoherent', 'Surfaced by the aliveness probe (server/src/bin/aliveness_probe.rs, branch fillchunk-shell-derive) run on Arbour (GJ338Bd — temperate, ocean hydrosphere) at seed ''yolo'' (u64 15217401773476501448). The deterministic cascade produces 2048 districts; the D-239 derivation LAWS fire correctly, yet the generated surface does not read as a living, real place. Across 6 probes (1 anchored ~150 chunks west of the principal city ''Arbour'' + 5 random districts) the world is uniform wet forest with the sea rendered as dry land. Key insight: this is the ''passes every binding law yet reads dead'' case — the lever is input-field VARIANCE + missing water rendering, not the laws. This epic groups the believability gaps (children) + the repeatable test protocol that found them, as a direction to discuss improvements. Sibling to T-974 (Atlas-to-tile derivation, the laws) and T-1031 (law-correctness harness).
|
||
|
||
---
|
||
UNIFYING PRINCIPLE (added during design discussion): multi-scale, never-repeating realization.
|
||
|
||
Real-world anchor: the entire Netherlands is ONE macro class (river delta / marshland) — coherent regional identity — yet it realizes as dunes, peat bogs, tidal flats, river-clay, heath, fen, reed marsh, polder, wet woodland, and NO TWO km^2 ARE THE SAME. Macro coherence and local non-stationarity are both required and are not in tension.
|
||
|
||
This reframes the epic as a multi-scale model:
|
||
- MACRO (region/body): identity — "this is a delta" (coherent). -> D-210 / T-948 (SubBiomeVariant macro tag).
|
||
- MESO (~km^2, between AND within districts): the sub-biome DISTRIBUTION drifts — same class, different mix every km^2. -> T-1080 (this is the real shape of that fix).
|
||
- MICRO (sub-chunk <64 m): the habitat mosaic within a patch. -> T-1084.
|
||
|
||
Two design implications:
|
||
1. Sub-biome must be a spatially-varying DISTRIBUTION, not a single tag. "Delta" resolves to a blend {tidal flat, peat bog, river-clay, reed marsh, ...} whose proportions drift across space; the micro-mosaic (T-1084) draws from the LOCAL blend. One label, many local realizations.
|
||
2. The enemy is the visible tile-repeat. "Every km^2 differs" = non-stationarity via multi-octave, domain-warped noise (extend the existing domain_warp "seam cannot align to the chunk edge" property up to the sub-biome tier). The fix for T-1080 is therefore non-repeating multi-octave VARIATION, not merely a smooth gradient (a gradient alone is still locally bland).
|
||
|
||
Test-protocol consequence (T-1083): the believability screen must measure NON-STATIONARITY — e.g. that two same-class km^2 are not identical, and that local sub-biome mix drifts — not just class-label diversity.', 'backlog', 'high', NULL, 'server', 'D-239', '2026-06-28 05:53:59.367', '2026-06-28 05:55:45.024', NULL, '57f128e1897b024f8dd6700b44f14564', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJNP8YM537DJCC82ZD6544', 'epic', '06FB0TNSRZXCHGS16BFHSSGSV4', 'World believability — generated terrain reads uniform / incoherent', 'Surfaced by the aliveness probe (server/src/bin/aliveness_probe.rs, branch fillchunk-shell-derive) run on Arbour (GJ338Bd — temperate, ocean hydrosphere) at seed ''yolo'' (u64 15217401773476501448). The deterministic cascade produces 2048 districts; the D-239 derivation LAWS fire correctly, yet the generated surface does not read as a living, real place. Across 6 probes (1 anchored ~150 chunks west of the principal city ''Arbour'' + 5 random districts) the world is uniform wet forest with the sea rendered as dry land. Key insight: this is the ''passes every binding law yet reads dead'' case — the lever is input-field VARIANCE + missing water rendering, not the laws. This epic groups the believability gaps (children) + the repeatable test protocol that found them, as a direction to discuss improvements. Sibling to T-974 (Atlas-to-tile derivation, the laws) and T-1031 (law-correctness harness).
|
||
|
||
---
|
||
UNIFYING PRINCIPLE (added during design discussion): multi-scale, never-repeating realization.
|
||
|
||
Real-world anchor: the entire Netherlands is ONE macro class (river delta / marshland) — coherent regional identity — yet it realizes as dunes, peat bogs, tidal flats, river-clay, heath, fen, reed marsh, polder, wet woodland, and NO TWO km^2 ARE THE SAME. Macro coherence and local non-stationarity are both required and are not in tension.
|
||
|
||
This reframes the epic as a multi-scale model:
|
||
- MACRO (region/body): identity — "this is a delta" (coherent). -> D-210 / T-948 (SubBiomeVariant macro tag).
|
||
- MESO (~km^2, between AND within districts): the sub-biome DISTRIBUTION drifts — same class, different mix every km^2. -> T-1080 (this is the real shape of that fix).
|
||
- MICRO (sub-chunk <64 m): the habitat mosaic within a patch. -> T-1084.
|
||
|
||
Two design implications:
|
||
1. Sub-biome must be a spatially-varying DISTRIBUTION, not a single tag. "Delta" resolves to a blend {tidal flat, peat bog, river-clay, reed marsh, ...} whose proportions drift across space; the micro-mosaic (T-1084) draws from the LOCAL blend. One label, many local realizations.
|
||
2. The enemy is the visible tile-repeat. "Every km^2 differs" = non-stationarity via multi-octave, domain-warped noise (extend the existing domain_warp "seam cannot align to the chunk edge" property up to the sub-biome tier). The fix for T-1080 is therefore non-repeating multi-octave VARIATION, not merely a smooth gradient (a gradient alone is still locally bland).
|
||
|
||
Test-protocol consequence (T-1083): the believability screen must measure NON-STATIONARITY — e.g. that two same-class km^2 are not identical, and that local sub-biome mix drifts — not just class-label diversity.
|
||
|
||
---
|
||
DELIVERABLE / DEFINITION OF DONE (D-245 — the holy grail): this epic is "done" when the cascade''s nature layers pass the believability litmus at RANDOMLY-SAMPLED locations across all habitable bodies and world seeds ("anywhere", not curated spots). Multi-scale + never-repeating: macro identity, meso non-stationarity (no two same-class km^2 alike), micro mosaic. Automated necessary-conditions screen — coherence, non-stationarity, intra-class variety, relief/landmark, climate-appropriateness — under a human narrate-the-natural-history sign-off (necessary != sufficient). Enforced by T-1083; strictness ramps budgeted+advisory -> strict as thresholds calibrate. D-245 (architecture) records this as the acceptance gate for the cascade''s nature half.', 'backlog', 'high', NULL, 'server', 'D-239', '2026-06-28 05:53:59.367', '2026-06-28 05:55:49.763', NULL, 'f44dd0ce875c225d366064a218753165', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYAE6MPE7720360WM4', 'task', '06FB0TNSRZKXHAYMT7Q6WW3XDC', 'FillChunk shell derivation <5ms (Void/Wall/FloorSlab/Roof from cached tags)', 'On-demand derive phase: read cached DistrictWorldState; per tag, shell_derive(seed, footprint, extent, z) -> Void|Wall|FloorSlab|Roof per voxel. Pre-condition: only after SkeletonGenerated; re-enqueue High if block_tags absent. Budget ~0.4-0.6ms/chunk.', 'in_progress', 'high', NULL, 'server', 'D-230', '2026-05-25 19:11:17', '2026-06-27 19:17:27.756', NULL, 'c3f6dbae1f1cc01e40bfb703411b170f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYAE6MPE7720360WM4', 'task', '06FB0TNSRZKXHAYMT7Q6WW3XDC', 'FillChunk shell derivation <5ms (Void/Wall/FloorSlab/Roof from cached tags)', 'On-demand derive phase: read cached DistrictWorldState; per tag, shell_derive(seed, footprint, extent, z) -> Void|Wall|FloorSlab|Roof per voxel. Pre-condition: only after SkeletonGenerated; re-enqueue High if block_tags absent. Budget ~0.4-0.6ms/chunk.
|
||
|
||
---
|
||
Implemented 2026-06-27 (branch fillchunk-shell-derive) as the DATA-PRODUCTION half of the D-230 on-demand derive phase:
|
||
|
||
- server/src/atlas/shell.rs (new): ShellVoxel{Void,Wall,FloorSlab,Roof} (repr(u8), append-only D-010) + FilledChunk (sparse BTreeMap, only non-Void stored) + pure fill_chunk(). Rectangle-containment (footprint ∩ chunk) × z-range (per-floor voxel bands from FloorExtent). Quarter-ground z origin (D-110: ground floor bottom = 0, basements negative). Walls on footprint perimeter, FloorSlab on interior floor bases, Roof one voxel above top floor.
|
||
- gen_queue.rs: GenWorkItem::FillChunk now carries pre-resolved block_tags + block_pos + sub_chunk (run_work_item is cache-free, mirrors GenerateSkeleton); GenCompletion::ChunkFilled carries Box<FilledChunk>; arm calls fill_chunk; added pure build_fill_chunk_item(&QuarterWorldState,..).
|
||
- plugin.rs: ChunkFilled handler accepts the shell (trace-only — no Phase-5 consumer yet).
|
||
|
||
SCOPE DECISION (deviates from the stale T-959 refinement note): the on-demand streaming DISPATCH TRIGGER ("wire chunk_streaming.rs to enqueue FillChunk") is DEFERRED to Phase 5. chunk_streaming.rs is the legacy Phase-5 rendering path (32-tile WalkabilityMap chunks); CLAUDE.md forbids building on the in-world rendering code before Phase 5, and the trigger is gated by T-962. fill_chunk is re-derivable (D-227) so no storage/consumer is required now.
|
||
|
||
OUT OF SCOPE (other T-959 children): interstitial street/open-space fill + D-235 surface material vocabulary (WallMaterial/RoofForm/StreetSurface) = T-988; condition overlay = T-999.
|
||
|
||
Tests: determinism, sparsity-vs-dense-volume (budget proxy — no flaky wall-clock asserts), wall/floor/roof correctness, basement z-origin, sub-chunk clipping, full submit→drain→ChunkFilled round-trip. cargo test (1571 lib) + clippy -D warnings + fmt all green.', 'in_progress', 'high', NULL, 'server', 'D-230', '2026-05-25 19:11:17', '2026-06-27 21:34:18.368', NULL, '558c202a0f38cd43859bd807a5793265', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYAE6MPE7720360WM4', 'task', '06FB0TNSRZKXHAYMT7Q6WW3XDC', 'FillChunk shell derivation <5ms (Void/Wall/FloorSlab/Roof from cached tags)', 'On-demand derive phase: read cached DistrictWorldState; per tag, shell_derive(seed, footprint, extent, z) -> Void|Wall|FloorSlab|Roof per voxel. Pre-condition: only after SkeletonGenerated; re-enqueue High if block_tags absent. Budget ~0.4-0.6ms/chunk.
|
||
|
||
---
|
||
Implemented 2026-06-27 (branch fillchunk-shell-derive) as the DATA-PRODUCTION half of the D-230 on-demand derive phase:
|
||
|
||
- server/src/atlas/shell.rs (new): ShellVoxel{Void,Wall,FloorSlab,Roof} (repr(u8), append-only D-010) + FilledChunk (sparse BTreeMap, only non-Void stored) + pure fill_chunk(). Rectangle-containment (footprint ∩ chunk) × z-range (per-floor voxel bands from FloorExtent). Quarter-ground z origin (D-110: ground floor bottom = 0, basements negative). Walls on footprint perimeter, FloorSlab on interior floor bases, Roof one voxel above top floor.
|
||
- gen_queue.rs: GenWorkItem::FillChunk now carries pre-resolved block_tags + block_pos + sub_chunk (run_work_item is cache-free, mirrors GenerateSkeleton); GenCompletion::ChunkFilled carries Box<FilledChunk>; arm calls fill_chunk; added pure build_fill_chunk_item(&QuarterWorldState,..).
|
||
- plugin.rs: ChunkFilled handler accepts the shell (trace-only — no Phase-5 consumer yet).
|
||
|
||
SCOPE DECISION (deviates from the stale T-959 refinement note): the on-demand streaming DISPATCH TRIGGER ("wire chunk_streaming.rs to enqueue FillChunk") is DEFERRED to Phase 5. chunk_streaming.rs is the legacy Phase-5 rendering path (32-tile WalkabilityMap chunks); CLAUDE.md forbids building on the in-world rendering code before Phase 5, and the trigger is gated by T-962. fill_chunk is re-derivable (D-227) so no storage/consumer is required now.
|
||
|
||
OUT OF SCOPE (other T-959 children): interstitial street/open-space fill + D-235 surface material vocabulary (WallMaterial/RoofForm/StreetSurface) = T-988; condition overlay = T-999.
|
||
|
||
Tests: determinism, sparsity-vs-dense-volume (budget proxy — no flaky wall-clock asserts), wall/floor/roof correctness, basement z-origin, sub-chunk clipping, full submit→drain→ChunkFilled round-trip. cargo test (1571 lib) + clippy -D warnings + fmt all green.', 'review', 'high', NULL, 'server', 'D-230', '2026-05-25 19:11:17', '2026-06-28 06:28:50.937', NULL, 'e49a948a5bfda49269a7cc64979d13bb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYAE6MPE7720360WM4', 'task', '06FB0TNSRZKXHAYMT7Q6WW3XDC', 'FillChunk shell derivation <5ms (Void/Wall/FloorSlab/Roof from cached tags)', 'On-demand derive phase: read cached DistrictWorldState; per tag, shell_derive(seed, footprint, extent, z) -> Void|Wall|FloorSlab|Roof per voxel. Pre-condition: only after SkeletonGenerated; re-enqueue High if block_tags absent. Budget ~0.4-0.6ms/chunk.
|
||
|
||
---
|
||
Implemented 2026-06-27 (branch fillchunk-shell-derive) as the DATA-PRODUCTION half of the D-230 on-demand derive phase:
|
||
|
||
- server/src/atlas/shell.rs (new): ShellVoxel{Void,Wall,FloorSlab,Roof} (repr(u8), append-only D-010) + FilledChunk (sparse BTreeMap, only non-Void stored) + pure fill_chunk(). Rectangle-containment (footprint ∩ chunk) × z-range (per-floor voxel bands from FloorExtent). Quarter-ground z origin (D-110: ground floor bottom = 0, basements negative). Walls on footprint perimeter, FloorSlab on interior floor bases, Roof one voxel above top floor.
|
||
- gen_queue.rs: GenWorkItem::FillChunk now carries pre-resolved block_tags + block_pos + sub_chunk (run_work_item is cache-free, mirrors GenerateSkeleton); GenCompletion::ChunkFilled carries Box<FilledChunk>; arm calls fill_chunk; added pure build_fill_chunk_item(&QuarterWorldState,..).
|
||
- plugin.rs: ChunkFilled handler accepts the shell (trace-only — no Phase-5 consumer yet).
|
||
|
||
SCOPE DECISION (deviates from the stale T-959 refinement note): the on-demand streaming DISPATCH TRIGGER ("wire chunk_streaming.rs to enqueue FillChunk") is DEFERRED to Phase 5. chunk_streaming.rs is the legacy Phase-5 rendering path (32-tile WalkabilityMap chunks); CLAUDE.md forbids building on the in-world rendering code before Phase 5, and the trigger is gated by T-962. fill_chunk is re-derivable (D-227) so no storage/consumer is required now.
|
||
|
||
OUT OF SCOPE (other T-959 children): interstitial street/open-space fill + D-235 surface material vocabulary (WallMaterial/RoofForm/StreetSurface) = T-988; condition overlay = T-999.
|
||
|
||
Tests: determinism, sparsity-vs-dense-volume (budget proxy — no flaky wall-clock asserts), wall/floor/roof correctness, basement z-origin, sub-chunk clipping, full submit→drain→ChunkFilled round-trip. cargo test (1571 lib) + clippy -D warnings + fmt all green.', 'done', 'high', NULL, 'server', 'D-230', '2026-05-25 19:11:17', '2026-06-28 09:12:18.667', NULL, 'b56566b00340780e24ed21cdb69026d1', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJZG3WFPQ3VXBFQFM4YEWW', 'story', '06FGSJNP8YM537DJCC82ZD6544', 'Repeatable believability test protocol — cross-district contrast + coherence metrics (promote aliveness_probe)', 'Promote the throwaway probe (server/src/bin/aliveness_probe.rs) into a committed, repeatable believability test protocol — the instrument that found T-1080/T-1081/T-1082. For a body+seed it runs the deterministic cascade and emits: (1) cross-district CONTRAST/variance metrics — moisture, elevation/relief, slope, morphology-zone diversity, terrain-material diversity, vegetation gradient — the screen that catches ''uniform/dead'' worlds; (2) COHERENCE checks with pass/fail — water zones must render wet, vegetation must correlate with moisture/water-distance/slope/aspect, drainage monotonic; (3) optional per-layer PNG maps (a stopgap for the T-960 Atlas viewer). LESSON BAKED IN: the first naive ''is it vegetated'' metric reported a broken uniform world as ALIVE — so the protocol MUST measure CONTRAST + COHERENCE across samples, never marginal per-tile counts. Make it runnable per-body, deterministic (string seed -> u64), snapshot a baseline for regression. This is the D-245 ENFORCER. NOTE: today it samples at the DISTRICT tier because no production code maps a world chunk -> covering DistrictProfile yet (voxel layer is a walking skeleton). Distinct from T-1031 (binding-LAW harness); believability sibling. Relates to T-960.', 'in_progress', 'high', NULL, 'server', 'D-239', '2026-06-28 05:55:19.712', '2026-06-28 09:13:25.900', NULL, 'bea5cbfc4e768e6e3188544f4dd9535c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJZG3WFPQ3VXBFQFM4YEWW', 'story', '06FGSJNP8YM537DJCC82ZD6544', 'Repeatable believability test protocol — cross-district contrast + coherence metrics (promote aliveness_probe)', 'Promote the throwaway probe (server/src/bin/aliveness_probe.rs) into a committed, repeatable believability test protocol — the instrument that found T-1080/T-1081/T-1082. For a body+seed it runs the deterministic cascade and emits: (1) cross-district CONTRAST/variance metrics — moisture, elevation/relief, slope, morphology-zone diversity, terrain-material diversity, vegetation gradient — the screen that catches ''uniform/dead'' worlds; (2) COHERENCE checks with pass/fail — water zones must render wet, vegetation must correlate with moisture/water-distance/slope/aspect, drainage monotonic; (3) optional per-layer PNG maps (a stopgap for the T-960 Atlas viewer). LESSON BAKED IN: the first naive ''is it vegetated'' metric reported a broken uniform world as ALIVE — so the protocol MUST measure CONTRAST + COHERENCE across samples, never marginal per-tile counts. Make it runnable per-body, deterministic (string seed -> u64), snapshot a baseline for regression. This is the D-245 ENFORCER. NOTE: today it samples at the DISTRICT tier because no production code maps a world chunk -> covering DistrictProfile yet (voxel layer is a walking skeleton). Distinct from T-1031 (binding-LAW harness); believability sibling. Relates to T-960.', 'in_progress', 'high', NULL, 'server', 'D-239', '2026-06-28 05:55:19.712', '2026-06-28 09:15:04.069', NULL, 'a4a2d68ab98dec38c833616b5e7b14e2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJZG3WFPQ3VXBFQFM4YEWW', 'story', '06FGSJNP8YM537DJCC82ZD6544', 'Repeatable believability test protocol — cross-district contrast + coherence metrics (promote aliveness_probe)', 'Promote the throwaway probe (server/src/bin/aliveness_probe.rs) into a committed, repeatable believability test protocol — the instrument that found T-1080/T-1081/T-1082. For a body+seed it runs the deterministic cascade and emits: (1) cross-district CONTRAST/variance metrics — moisture, elevation/relief, slope, morphology-zone diversity, terrain-material diversity, vegetation gradient — the screen that catches ''uniform/dead'' worlds; (2) COHERENCE checks with pass/fail — water zones must render wet, vegetation must correlate with moisture/water-distance/slope/aspect, drainage monotonic; (3) optional per-layer PNG maps (a stopgap for the T-960 Atlas viewer). LESSON BAKED IN: the first naive ''is it vegetated'' metric reported a broken uniform world as ALIVE — so the protocol MUST measure CONTRAST + COHERENCE across samples, never marginal per-tile counts. Make it runnable per-body, deterministic (string seed -> u64), snapshot a baseline for regression. This is the D-245 ENFORCER. NOTE: today it samples at the DISTRICT tier because no production code maps a world chunk -> covering DistrictProfile yet (voxel layer is a walking skeleton). Distinct from T-1031 (binding-LAW harness); believability sibling. Relates to T-960.
|
||
|
||
---
|
||
Implemented 2026-06-28 (branch believability-harness).
|
||
|
||
- server/src/atlas/believability.rs (new): the enforcer core. BelievabilityReport (serde, golden-able) + analyze() = CONTRAST (per-field min/max/distinct over ALL districts for moisture/elev/slope/ocean; distinct morphology-zones/vegetation-classes/terrain-materials) + COHERENCE (water-renders-wet [T-1082], drainage-monotonic, vegetation-present). evaluate_criteria() = advisory D-245 checks (thresholds Q-123-TBD). cascade_for_body()/seed_to_u64() loader shared by bin + harness. Unit tests prove the metric distinguishes uniform (fails) vs varied (passes) — the ''never marginal per-tile counts'' lesson — + determinism.
|
||
- server/src/bin/aliveness_probe.rs: refactored to a thin CLI over the module; prints the body-level report + advisory D-245 criteria; dropped the naive per-tile ''reads ALIVE'' verdict.
|
||
- server/tests/believability_harness.rs (+ tests/golden/believability.json): real cascade for Arbour (temperate/ocean) + Edict (frozen/ice); determinism assert; golden regression (updates when T-1080/T-1082 land); BELIEVABILITY_STRICT=1 fails on unmet criteria. Skips if data absent. x86_64 golden.
|
||
|
||
BASELINE @ believability-v1: Arbour 3/7, Edict 3/7. FAIL: moisture gradient (distinct=1, T-1080), water-renders-wet (T-1082), drainage-monotonic. Edict vegetation 0/64 = blank tundra (the frozen ''reads dead'' case). PASS: elevation relief, morphology variety, vegetation-present (Arbour only).
|
||
|
||
DEFERRED (ticket item 3 — explicitly optional): per-layer PNG maps (the T-960 Atlas-viewer stopgap). The contrast+coherence metrics are the core enforcer; maps are a follow-up if the human-gate review wants them before T-960.
|
||
|
||
This is the D-245 enforcer; advisory now, ratchets to strict (BELIEVABILITY_STRICT) once Q-123 calibrates thresholds and T-1080/1081/1082 flip the criteria.', 'in_progress', 'high', NULL, 'server', 'D-239', '2026-06-28 05:55:19.712', '2026-06-28 12:56:03.498', NULL, 'e39a34b2d5f662cef1b8fee88a70c8f9', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJWWZNWYT3C4T828ZF1QCG', 'story', '06FGSJNP8YM537DJCC82ZD6544', 'No water-body voxel generator — OpenOcean/Lake/TidalFlat render as dry land', 'Probe evidence (Arbour @ yolo, an OCEAN world): OpenOcean districts derive water=Dry 100% with vegetation Forest 62% on Wetland substrate — i.e. the sea is painted as dry forested land. Root cause (voxel.rs zone_to_family): OpenOcean/Lake/TidalFlat/Wetland fall back to the AlluvialPlain (dry-land) generator; there is no water-body generator that lays Water::Deep/Shallow for water zones, sets a sea/lake surface elevation, or forms coastlines. On an ocean world this means the majority of the surface renders wrong. Known incompleteness (the fallback is documented), filed so it has a home. Direction to discuss: a water-body morphology family (ocean / lake / tidal-flat) that sets Deep/Shallow water + substrate + coast, and how sea level (heightmap sea_level threshold) feeds it.', 'in_progress', 'high', NULL, 'server', 'D-239', '2026-06-28 05:54:58.429', '2026-06-28 13:00:26.933', NULL, '12c4956809610e71cdf625d28fc48bdb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJWWZNWYT3C4T828ZF1QCG', 'story', '06FGSJNP8YM537DJCC82ZD6544', 'No water-body voxel generator — OpenOcean/Lake/TidalFlat render as dry land', 'Probe evidence (Arbour @ yolo, an OCEAN world): OpenOcean districts derive water=Dry 100% with vegetation Forest 62% on Wetland substrate — i.e. the sea is painted as dry forested land. Root cause (voxel.rs zone_to_family): OpenOcean/Lake/TidalFlat/Wetland fall back to the AlluvialPlain (dry-land) generator; there is no water-body generator that lays Water::Deep/Shallow for water zones, sets a sea/lake surface elevation, or forms coastlines. On an ocean world this means the majority of the surface renders wrong. Known incompleteness (the fallback is documented), filed so it has a home. Direction to discuss: a water-body morphology family (ocean / lake / tidal-flat) that sets Deep/Shallow water + substrate + coast, and how sea level (heightmap sea_level threshold) feeds it.', 'in_progress', 'high', NULL, 'server', 'D-239', '2026-06-28 05:54:58.429', '2026-06-28 13:01:05.826', NULL, '330a98a5774e1be834fd8fef02e2f1ff', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJWWZNWYT3C4T828ZF1QCG', 'story', '06FGSJNP8YM537DJCC82ZD6544', 'No water-body voxel generator — OpenOcean/Lake/TidalFlat render as dry land', 'Probe evidence (Arbour @ yolo, an OCEAN world): OpenOcean districts derive water=Dry 100% with vegetation Forest 62% on Wetland substrate — i.e. the sea is painted as dry forested land. Root cause (voxel.rs zone_to_family): OpenOcean/Lake/TidalFlat/Wetland fall back to the AlluvialPlain (dry-land) generator; there is no water-body generator that lays Water::Deep/Shallow for water zones, sets a sea/lake surface elevation, or forms coastlines. On an ocean world this means the majority of the surface renders wrong. Known incompleteness (the fallback is documented), filed so it has a home. Direction to discuss: a water-body morphology family (ocean / lake / tidal-flat) that sets Deep/Shallow water + substrate + coast, and how sea level (heightmap sea_level threshold) feeds it.
|
||
|
||
---
|
||
Refinement (Si pass + user ruling, 2026-06-28) — resolves the ''direction to discuss'':
|
||
|
||
- FAMILY: dedicated WaterBody family (9th D-239 family) for OpenOcean/Lake/TidalFlat, branching internally on morphology_zone (like IncisedGorge covers MountainPass/ValleyFloor/Alpine). Amend D-239 §5/§6 (8→9 families) + zone_to_family.
|
||
- FIDELITY: RICHER — a Shallow fringe along the district-anchored shoreline (ChunkContext.coast_anchor_m, as CliffCoast uses) + Deep toward the interior; TidalFlat = all Shallow (intertidal).
|
||
- SUBSTRATE: reuse existing TerrainMaterial (no new variant). Rock seabed/shore where slope_q is steep (Rock IS in the enum — rocky available both above and below water, per user), Sand where gentle; TidalFlat = Wetland (mud). Vegetation = Barren in all water voxels (fixes ''Forest on the sea'').
|
||
- SURFACE: water surface elevation_m = 0 (the sea-level convention the existing coastal families already use — raw heightmap sea_level does NOT reach the voxel tier; only ocean_fraction_q/elev_q do). Depth is conveyed by the Water axis (Deep/Shallow), not by elevation_m.
|
||
- COVER: reuse derive_cover so cold-body water gets Ice (frozen seas on Edict) — important for the frozen-world believability case.
|
||
- SCOPE: Wetland zone STAYS AlluvialPlain (it is land — a marsh, not open water; only the 3 named zones get WaterBody). Transient tidal wet/dry alternation deferred to Q-105.
|
||
- DETERMINISM: integer arithmetic only (D-010); warp before the integer voxel address, as the other families.
|
||
- VERIFICATION: the T-1083 believability harness must flip ''water renders wet'' toward green for Arbour + Edict; update the golden (UPDATE_GOLDEN) to capture the improvement.', 'in_progress', 'high', NULL, 'server', 'D-239', '2026-06-28 05:54:58.429', '2026-06-28 13:10:56.408', NULL, '8f55fc31d54598d0756308b8e6ef645c', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJTXTADJRHYEE1WTAENYAG', 'story', '06FGSJNP8YM537DJCC82ZD6544', 'District climate fields lack spatial gradient — uniform moisture/precip/vegetation yields monotone terrain', 'Probe evidence (Arbour @ yolo): moisture_q=80, precip=SuperHumid, veg_class=Forest in ~every one of 2048 districts; the voxel layer then derives terrain=Wetland 100% everywhere. The derivation is LAW-CORRECT (flat + wet -> Wetland, D-239 section 8) — the defect is upstream: the district-scale climate/moisture field has near-zero cross-district variance, so there is no gradient to drive ecotones, material variety, or vegetation bands. Without gradient the ''edge-fuzzed climate'' promise is invisible (nothing to fuzz). Direction to discuss: where moisture/precip SHOULD vary (latitude, orography/rain-shadow, continentality, distance-to-water) and how to introduce believable spatial gradient into the district derivation. Believability gap, not a crash.', 'in_progress', 'high', NULL, 'server', 'D-239', '2026-06-28 05:54:42.258', '2026-06-28 13:42:27.248', NULL, '8daa8d5b388dbc0aa004da1f0abd970f', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJTXTADJRHYEE1WTAENYAG', 'story', '06FGSJNP8YM537DJCC82ZD6544', 'District climate fields lack spatial gradient — uniform moisture/precip/vegetation yields monotone terrain', 'Probe evidence (Arbour @ yolo): moisture_q=80, precip=SuperHumid, veg_class=Forest in ~every one of 2048 districts; the voxel layer then derives terrain=Wetland 100% everywhere. The derivation is LAW-CORRECT (flat + wet -> Wetland, D-239 section 8) — the defect is upstream: the district-scale climate/moisture field has near-zero cross-district variance, so there is no gradient to drive ecotones, material variety, or vegetation bands. Without gradient the ''edge-fuzzed climate'' promise is invisible (nothing to fuzz). Direction to discuss: where moisture/precip SHOULD vary (latitude, orography/rain-shadow, continentality, distance-to-water) and how to introduce believable spatial gradient into the district derivation. Believability gap, not a crash.
|
||
|
||
---
|
||
Refinement (Si pass, 2026-06-28) — READY (no design fork; localized fix).
|
||
|
||
ROOT CAUSE: derive_moisture_q (district_profile.rs) takes only &BodyParams → returns a body-scale constant (ocean → 80) identical for all districts. Structurally cannot vary.
|
||
|
||
FIX: restructure derive_moisture_q to body-ceiling (from hydrosphere) modulated by per-district factors, mirroring derive_temperature_c''s shape (envelope → latitude lerp → elevation lapse → seed nudge), integer/D-010:
|
||
- LATITUDE band: equator wetter → pole drier (uses latitude_deg, already threaded for temperature).
|
||
- ELEVATION lapse: high elev_q → drier (orographic/rain-shadow).
|
||
- CONTINENTALITY: far from water → drier, via TerrainAnalysis.water_dist (Chebyshev cells-to-water, already computed in features.rs; aggregate a per-district mean in the existing derive_district_profile cell loop).
|
||
- small deterministic seed nudge (±N) for per-district variety.
|
||
Signature: derive_moisture_q(params, elev_q, ocean_fraction_q, water_dist_q). build_district_profile forwards them; derive_district_profile accumulates water_dist.
|
||
|
||
PROPAGATION: precipitation_class (derive_precipitation_class_from_climate) + vegetation_class (derive_vegetation) + morphology Wetland gate (slope_q<=5 && moisture_q>=60) all read moisture_q → diversify automatically.
|
||
|
||
TUNING: add [moisture_gradient] to server/data/climate_constants.toml + matching ClimateConstants struct defaults (kept in sync by hand until T-1032 wires TOML loading, per the existing constraint).
|
||
|
||
DETERMINISM: integer (water_dist u16, integer division, clamp 0..100). D-010 ok.
|
||
|
||
VERIFY: believability harness gate moisture_q.distinct>=3 flips FAIL→PASS; vegetation-present should rise too. Magnitude calibration is Q-123 (provisional coefficients now). Files: district_profile.rs, climate_constants.toml.', 'in_progress', 'high', NULL, 'server', 'D-239', '2026-06-28 05:54:42.258', '2026-06-28 13:50:47.912', NULL, '4f5ee94f5fd8f5e447968619a520f915', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJZG3WFPQ3VXBFQFM4YEWW', 'story', '06FGSJNP8YM537DJCC82ZD6544', 'Repeatable believability test protocol — cross-district contrast + coherence metrics (promote aliveness_probe)', 'Promote the throwaway probe (server/src/bin/aliveness_probe.rs) into a committed, repeatable believability test protocol — the instrument that found T-1080/T-1081/T-1082. For a body+seed it runs the deterministic cascade and emits: (1) cross-district CONTRAST/variance metrics — moisture, elevation/relief, slope, morphology-zone diversity, terrain-material diversity, vegetation gradient — the screen that catches ''uniform/dead'' worlds; (2) COHERENCE checks with pass/fail — water zones must render wet, vegetation must correlate with moisture/water-distance/slope/aspect, drainage monotonic; (3) optional per-layer PNG maps (a stopgap for the T-960 Atlas viewer). LESSON BAKED IN: the first naive ''is it vegetated'' metric reported a broken uniform world as ALIVE — so the protocol MUST measure CONTRAST + COHERENCE across samples, never marginal per-tile counts. Make it runnable per-body, deterministic (string seed -> u64), snapshot a baseline for regression. This is the D-245 ENFORCER. NOTE: today it samples at the DISTRICT tier because no production code maps a world chunk -> covering DistrictProfile yet (voxel layer is a walking skeleton). Distinct from T-1031 (binding-LAW harness); believability sibling. Relates to T-960.
|
||
|
||
---
|
||
Implemented 2026-06-28 (branch believability-harness).
|
||
|
||
- server/src/atlas/believability.rs (new): the enforcer core. BelievabilityReport (serde, golden-able) + analyze() = CONTRAST (per-field min/max/distinct over ALL districts for moisture/elev/slope/ocean; distinct morphology-zones/vegetation-classes/terrain-materials) + COHERENCE (water-renders-wet [T-1082], drainage-monotonic, vegetation-present). evaluate_criteria() = advisory D-245 checks (thresholds Q-123-TBD). cascade_for_body()/seed_to_u64() loader shared by bin + harness. Unit tests prove the metric distinguishes uniform (fails) vs varied (passes) — the ''never marginal per-tile counts'' lesson — + determinism.
|
||
- server/src/bin/aliveness_probe.rs: refactored to a thin CLI over the module; prints the body-level report + advisory D-245 criteria; dropped the naive per-tile ''reads ALIVE'' verdict.
|
||
- server/tests/believability_harness.rs (+ tests/golden/believability.json): real cascade for Arbour (temperate/ocean) + Edict (frozen/ice); determinism assert; golden regression (updates when T-1080/T-1082 land); BELIEVABILITY_STRICT=1 fails on unmet criteria. Skips if data absent. x86_64 golden.
|
||
|
||
BASELINE @ believability-v1: Arbour 3/7, Edict 3/7. FAIL: moisture gradient (distinct=1, T-1080), water-renders-wet (T-1082), drainage-monotonic. Edict vegetation 0/64 = blank tundra (the frozen ''reads dead'' case). PASS: elevation relief, morphology variety, vegetation-present (Arbour only).
|
||
|
||
DEFERRED (ticket item 3 — explicitly optional): per-layer PNG maps (the T-960 Atlas-viewer stopgap). The contrast+coherence metrics are the core enforcer; maps are a follow-up if the human-gate review wants them before T-960.
|
||
|
||
This is the D-245 enforcer; advisory now, ratchets to strict (BELIEVABILITY_STRICT) once Q-123 calibrates thresholds and T-1080/1081/1082 flip the criteria.
|
||
|
||
Stack-review note (2026-06-28): the believability sampling-bias fix (contiguous-prefix -> seeded Fisher-Yates spread in sample_indices) is logically a T-1083 enforcer-correctness fix but landed in the T-1082 commit cdc55032d (found while verifying T-1082). git history records it accurately under the water-body work; flagged so a bisect lands in the expected place. The Fisher-Yates termination fix + drainage-proxy exclusion of water districts (stack review) are in the T-1080 review-fix commit.', 'in_progress', 'high', NULL, 'server', 'D-239', '2026-06-28 05:55:19.712', '2026-06-28 15:38:18.308', NULL, '0b6572cca4a24c9658cf4751d7573add', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJTXTADJRHYEE1WTAENYAG', 'story', '06FGSJNP8YM537DJCC82ZD6544', 'District climate fields lack spatial gradient — uniform moisture/precip/vegetation yields monotone terrain', 'Probe evidence (Arbour @ yolo): moisture_q=80, precip=SuperHumid, veg_class=Forest in ~every one of 2048 districts; the voxel layer then derives terrain=Wetland 100% everywhere. The derivation is LAW-CORRECT (flat + wet -> Wetland, D-239 section 8) — the defect is upstream: the district-scale climate/moisture field has near-zero cross-district variance, so there is no gradient to drive ecotones, material variety, or vegetation bands. Without gradient the ''edge-fuzzed climate'' promise is invisible (nothing to fuzz). Direction to discuss: where moisture/precip SHOULD vary (latitude, orography/rain-shadow, continentality, distance-to-water) and how to introduce believable spatial gradient into the district derivation. Believability gap, not a crash.
|
||
|
||
---
|
||
Refinement (Si pass, 2026-06-28) — READY (no design fork; localized fix).
|
||
|
||
ROOT CAUSE: derive_moisture_q (district_profile.rs) takes only &BodyParams → returns a body-scale constant (ocean → 80) identical for all districts. Structurally cannot vary.
|
||
|
||
FIX: restructure derive_moisture_q to body-ceiling (from hydrosphere) modulated by per-district factors, mirroring derive_temperature_c''s shape (envelope → latitude lerp → elevation lapse → seed nudge), integer/D-010:
|
||
- LATITUDE band: equator wetter → pole drier (uses latitude_deg, already threaded for temperature).
|
||
- ELEVATION lapse: high elev_q → drier (orographic/rain-shadow).
|
||
- CONTINENTALITY: far from water → drier, via TerrainAnalysis.water_dist (Chebyshev cells-to-water, already computed in features.rs; aggregate a per-district mean in the existing derive_district_profile cell loop).
|
||
- small deterministic seed nudge (±N) for per-district variety.
|
||
Signature: derive_moisture_q(params, elev_q, ocean_fraction_q, water_dist_q). build_district_profile forwards them; derive_district_profile accumulates water_dist.
|
||
|
||
PROPAGATION: precipitation_class (derive_precipitation_class_from_climate) + vegetation_class (derive_vegetation) + morphology Wetland gate (slope_q<=5 && moisture_q>=60) all read moisture_q → diversify automatically.
|
||
|
||
TUNING: add [moisture_gradient] to server/data/climate_constants.toml + matching ClimateConstants struct defaults (kept in sync by hand until T-1032 wires TOML loading, per the existing constraint).
|
||
|
||
DETERMINISM: integer (water_dist u16, integer division, clamp 0..100). D-010 ok.
|
||
|
||
VERIFY: believability harness gate moisture_q.distinct>=3 flips FAIL→PASS; vegetation-present should rise too. Magnitude calibration is Q-123 (provisional coefficients now). Files: district_profile.rs, climate_constants.toml.', 'done', 'high', NULL, 'server', 'D-239', '2026-06-28 05:54:42.258', '2026-06-28 16:02:46.330', NULL, 'a58653ebc014cfa374fcf62f736f6f18', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJWWZNWYT3C4T828ZF1QCG', 'story', '06FGSJNP8YM537DJCC82ZD6544', 'No water-body voxel generator — OpenOcean/Lake/TidalFlat render as dry land', 'Probe evidence (Arbour @ yolo, an OCEAN world): OpenOcean districts derive water=Dry 100% with vegetation Forest 62% on Wetland substrate — i.e. the sea is painted as dry forested land. Root cause (voxel.rs zone_to_family): OpenOcean/Lake/TidalFlat/Wetland fall back to the AlluvialPlain (dry-land) generator; there is no water-body generator that lays Water::Deep/Shallow for water zones, sets a sea/lake surface elevation, or forms coastlines. On an ocean world this means the majority of the surface renders wrong. Known incompleteness (the fallback is documented), filed so it has a home. Direction to discuss: a water-body morphology family (ocean / lake / tidal-flat) that sets Deep/Shallow water + substrate + coast, and how sea level (heightmap sea_level threshold) feeds it.
|
||
|
||
---
|
||
Refinement (Si pass + user ruling, 2026-06-28) — resolves the ''direction to discuss'':
|
||
|
||
- FAMILY: dedicated WaterBody family (9th D-239 family) for OpenOcean/Lake/TidalFlat, branching internally on morphology_zone (like IncisedGorge covers MountainPass/ValleyFloor/Alpine). Amend D-239 §5/§6 (8→9 families) + zone_to_family.
|
||
- FIDELITY: RICHER — a Shallow fringe along the district-anchored shoreline (ChunkContext.coast_anchor_m, as CliffCoast uses) + Deep toward the interior; TidalFlat = all Shallow (intertidal).
|
||
- SUBSTRATE: reuse existing TerrainMaterial (no new variant). Rock seabed/shore where slope_q is steep (Rock IS in the enum — rocky available both above and below water, per user), Sand where gentle; TidalFlat = Wetland (mud). Vegetation = Barren in all water voxels (fixes ''Forest on the sea'').
|
||
- SURFACE: water surface elevation_m = 0 (the sea-level convention the existing coastal families already use — raw heightmap sea_level does NOT reach the voxel tier; only ocean_fraction_q/elev_q do). Depth is conveyed by the Water axis (Deep/Shallow), not by elevation_m.
|
||
- COVER: reuse derive_cover so cold-body water gets Ice (frozen seas on Edict) — important for the frozen-world believability case.
|
||
- SCOPE: Wetland zone STAYS AlluvialPlain (it is land — a marsh, not open water; only the 3 named zones get WaterBody). Transient tidal wet/dry alternation deferred to Q-105.
|
||
- DETERMINISM: integer arithmetic only (D-010); warp before the integer voxel address, as the other families.
|
||
- VERIFICATION: the T-1083 believability harness must flip ''water renders wet'' toward green for Arbour + Edict; update the golden (UPDATE_GOLDEN) to capture the improvement.', 'done', 'high', NULL, 'server', 'D-239', '2026-06-28 05:54:58.429', '2026-06-28 16:02:46.337', NULL, 'bf04f9dee586698f22aeebd9d2cb81b3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJZG3WFPQ3VXBFQFM4YEWW', 'story', '06FGSJNP8YM537DJCC82ZD6544', 'Repeatable believability test protocol — cross-district contrast + coherence metrics (promote aliveness_probe)', 'Promote the throwaway probe (server/src/bin/aliveness_probe.rs) into a committed, repeatable believability test protocol — the instrument that found T-1080/T-1081/T-1082. For a body+seed it runs the deterministic cascade and emits: (1) cross-district CONTRAST/variance metrics — moisture, elevation/relief, slope, morphology-zone diversity, terrain-material diversity, vegetation gradient — the screen that catches ''uniform/dead'' worlds; (2) COHERENCE checks with pass/fail — water zones must render wet, vegetation must correlate with moisture/water-distance/slope/aspect, drainage monotonic; (3) optional per-layer PNG maps (a stopgap for the T-960 Atlas viewer). LESSON BAKED IN: the first naive ''is it vegetated'' metric reported a broken uniform world as ALIVE — so the protocol MUST measure CONTRAST + COHERENCE across samples, never marginal per-tile counts. Make it runnable per-body, deterministic (string seed -> u64), snapshot a baseline for regression. This is the D-245 ENFORCER. NOTE: today it samples at the DISTRICT tier because no production code maps a world chunk -> covering DistrictProfile yet (voxel layer is a walking skeleton). Distinct from T-1031 (binding-LAW harness); believability sibling. Relates to T-960.
|
||
|
||
---
|
||
Implemented 2026-06-28 (branch believability-harness).
|
||
|
||
- server/src/atlas/believability.rs (new): the enforcer core. BelievabilityReport (serde, golden-able) + analyze() = CONTRAST (per-field min/max/distinct over ALL districts for moisture/elev/slope/ocean; distinct morphology-zones/vegetation-classes/terrain-materials) + COHERENCE (water-renders-wet [T-1082], drainage-monotonic, vegetation-present). evaluate_criteria() = advisory D-245 checks (thresholds Q-123-TBD). cascade_for_body()/seed_to_u64() loader shared by bin + harness. Unit tests prove the metric distinguishes uniform (fails) vs varied (passes) — the ''never marginal per-tile counts'' lesson — + determinism.
|
||
- server/src/bin/aliveness_probe.rs: refactored to a thin CLI over the module; prints the body-level report + advisory D-245 criteria; dropped the naive per-tile ''reads ALIVE'' verdict.
|
||
- server/tests/believability_harness.rs (+ tests/golden/believability.json): real cascade for Arbour (temperate/ocean) + Edict (frozen/ice); determinism assert; golden regression (updates when T-1080/T-1082 land); BELIEVABILITY_STRICT=1 fails on unmet criteria. Skips if data absent. x86_64 golden.
|
||
|
||
BASELINE @ believability-v1: Arbour 3/7, Edict 3/7. FAIL: moisture gradient (distinct=1, T-1080), water-renders-wet (T-1082), drainage-monotonic. Edict vegetation 0/64 = blank tundra (the frozen ''reads dead'' case). PASS: elevation relief, morphology variety, vegetation-present (Arbour only).
|
||
|
||
DEFERRED (ticket item 3 — explicitly optional): per-layer PNG maps (the T-960 Atlas-viewer stopgap). The contrast+coherence metrics are the core enforcer; maps are a follow-up if the human-gate review wants them before T-960.
|
||
|
||
This is the D-245 enforcer; advisory now, ratchets to strict (BELIEVABILITY_STRICT) once Q-123 calibrates thresholds and T-1080/1081/1082 flip the criteria.
|
||
|
||
Stack-review note (2026-06-28): the believability sampling-bias fix (contiguous-prefix -> seeded Fisher-Yates spread in sample_indices) is logically a T-1083 enforcer-correctness fix but landed in the T-1082 commit cdc55032d (found while verifying T-1082). git history records it accurately under the water-body work; flagged so a bisect lands in the expected place. The Fisher-Yates termination fix + drainage-proxy exclusion of water districts (stack review) are in the T-1080 review-fix commit.', 'done', 'high', NULL, 'server', 'D-239', '2026-06-28 05:55:19.712', '2026-06-28 16:02:46.338', NULL, '682f72f4c7d0310247d4cfe20a2f347e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJVW30PSP8K0XAWV02X7M0', 'story', '06FGSJNP8YM537DJCC82ZD6544', 'Near-zero voxel relief (0-3 m) — generated terrain has no hills or landmarks', 'Probe evidence (Arbour @ yolo): voxel elevation 0-3 m across nearly all sampled districts (only one snow upland reached 42-49 m). Flat terrain => nothing to navigate by, no landmarks, no ''specificity of place''. Either the heightmap relief is being flattened by the 512x256 working downsample + district derivation, or detail-scatter (D-227, derive-don''t-store) is not producing the mid-scale relief it is supposed to invent at the voxel tier. Direction to discuss: the relief envelope taken from the heightmap, detail-scatter amplitude, and whether the elev_q -> elevation_m mapping is collapsing the range. Believability gap.', 'in_progress', 'high', NULL, 'server', 'D-227', '2026-06-28 05:54:50.008', '2026-06-28 16:08:41.256', NULL, 'e9823e01ab027322b5f6cd022dfedc1e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJVW30PSP8K0XAWV02X7M0', 'story', '06FGSJNP8YM537DJCC82ZD6544', 'Near-zero voxel relief (0-3 m) — generated terrain has no hills or landmarks', 'Probe evidence (Arbour @ yolo): voxel elevation 0-3 m across nearly all sampled districts (only one snow upland reached 42-49 m). Flat terrain => nothing to navigate by, no landmarks, no ''specificity of place''. Either the heightmap relief is being flattened by the 512x256 working downsample + district derivation, or detail-scatter (D-227, derive-don''t-store) is not producing the mid-scale relief it is supposed to invent at the voxel tier. Direction to discuss: the relief envelope taken from the heightmap, detail-scatter amplitude, and whether the elev_q -> elevation_m mapping is collapsing the range. Believability gap.
|
||
|
||
---
|
||
Refinement (Si pass, 2026-06-28) — READY. Four compounding causes (all confirmed):
|
||
1. elev_q→elevation_m scale: generate_alluvial_plain uses `elev_q / 2` → whole-body relief is 0–50 m (pancake). Other flat families similar (/2,/3,/4). The dramatic families (cliff/fjord/gorge) carry real internal relief; the flat ones (alluvial/lava/dune/braided/meander) don''t.
|
||
2. detail_scatter (D-227) is applied ONLY at the district tier (derive_district → elev_q); it never reaches per-voxel elevation_m. So within a chunk relief = base ± 4 m micro-scatter = flat. The promised mid-scale (sub-district, ~tens-to-hundreds m) relief is missing at the voxel tier.
|
||
3. Envelope collapses to 0 on flat-slope districts (terrain_detail returns 0 when envelope==0) — by design ("no mountain on an authored plain"); consider a small floor so even gentle land rolls.
|
||
4. WaterBody correctly keeps elevation_m=0 (sea level) — must stay.
|
||
|
||
PLAN (data-driven, tune via probe like moisture):
|
||
- Add MID-SCALE rolling relief at the voxel tier: a detail-scatter octave term (sub-district wavelengths ~256–2048 m) added to elevation_m for DRY-LAND columns, enveloped by district ruggedness (slope_q) so plains stay flat and rugged terrain rolls. f64 perturbation truncated to i32 (D-010, same as the warp). Applied centrally in derive_voxel_column (one site, like derive_cover) so all land families benefit.
|
||
- Bump the flat-family base scale from the compressed /N toward a believable span if the probe shows mountains still too low (per-body absolute relief = T-1032 follow-up).
|
||
- Add a VOXEL-RELIEF metric to believability.rs (mean within-chunk elevation range across sampled non-water districts) — the current "elevation relief" criterion measures DISTRICT elev_q spread (already passes), not voxel relief, so it does not catch T-1081.
|
||
- VERIFY: probe per-location elevation range rises from ~0-3 m; the new voxel-relief criterion flips green. Determinism: integer/D-010.
|
||
Files: voxel.rs (generators + central relief), detail_scatter.rs (sub-district wavelengths), believability.rs (metric).', 'in_progress', 'high', NULL, 'server', 'D-227', '2026-06-28 05:54:50.008', '2026-06-28 16:16:05.190', NULL, '1450d38cb522267b239186b96d8ad0a2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJVW30PSP8K0XAWV02X7M0', 'story', '06FGSJNP8YM537DJCC82ZD6544', 'Near-zero voxel relief (0-3 m) — generated terrain has no hills or landmarks', 'Probe evidence (Arbour @ yolo): voxel elevation 0-3 m across nearly all sampled districts (only one snow upland reached 42-49 m). Flat terrain => nothing to navigate by, no landmarks, no ''specificity of place''. Either the heightmap relief is being flattened by the 512x256 working downsample + district derivation, or detail-scatter (D-227, derive-don''t-store) is not producing the mid-scale relief it is supposed to invent at the voxel tier. Direction to discuss: the relief envelope taken from the heightmap, detail-scatter amplitude, and whether the elev_q -> elevation_m mapping is collapsing the range. Believability gap.
|
||
|
||
---
|
||
Refinement (Si pass, 2026-06-28) — READY. Four compounding causes (all confirmed):
|
||
1. elev_q→elevation_m scale: generate_alluvial_plain uses `elev_q / 2` → whole-body relief is 0–50 m (pancake). Other flat families similar (/2,/3,/4). The dramatic families (cliff/fjord/gorge) carry real internal relief; the flat ones (alluvial/lava/dune/braided/meander) don''t.
|
||
2. detail_scatter (D-227) is applied ONLY at the district tier (derive_district → elev_q); it never reaches per-voxel elevation_m. So within a chunk relief = base ± 4 m micro-scatter = flat. The promised mid-scale (sub-district, ~tens-to-hundreds m) relief is missing at the voxel tier.
|
||
3. Envelope collapses to 0 on flat-slope districts (terrain_detail returns 0 when envelope==0) — by design ("no mountain on an authored plain"); consider a small floor so even gentle land rolls.
|
||
4. WaterBody correctly keeps elevation_m=0 (sea level) — must stay.
|
||
|
||
PLAN (data-driven, tune via probe like moisture):
|
||
- Add MID-SCALE rolling relief at the voxel tier: a detail-scatter octave term (sub-district wavelengths ~256–2048 m) added to elevation_m for DRY-LAND columns, enveloped by district ruggedness (slope_q) so plains stay flat and rugged terrain rolls. f64 perturbation truncated to i32 (D-010, same as the warp). Applied centrally in derive_voxel_column (one site, like derive_cover) so all land families benefit.
|
||
- Bump the flat-family base scale from the compressed /N toward a believable span if the probe shows mountains still too low (per-body absolute relief = T-1032 follow-up).
|
||
- Add a VOXEL-RELIEF metric to believability.rs (mean within-chunk elevation range across sampled non-water districts) — the current "elevation relief" criterion measures DISTRICT elev_q spread (already passes), not voxel relief, so it does not catch T-1081.
|
||
- VERIFY: probe per-location elevation range rises from ~0-3 m; the new voxel-relief criterion flips green. Determinism: integer/D-010.
|
||
Files: voxel.rs (generators + central relief), detail_scatter.rs (sub-district wavelengths), believability.rs (metric).
|
||
|
||
Implemented (2026-06-28, branch voxel-relief). The voxel tier now carries mid-scale relief (D-243 §2): a `voxel_relief` fBm pass at the 0.25–2 km octave band (detail_scatter.rs), body-global SeedDomain::VoxelRelief seed, added post-dispatch in derive_voxel_column, truncated to integer metres (D-010).
|
||
|
||
Root cause refined during impl: the coarse heightmap yields slope_q ≈ 0 even on high ground (Arbour max slope_q = 13), so the relief envelope is `slope_q*3 + elev_q` (elevation drives ruggedness), not slope alone. Applied to the FLAT families only (AlluvialPlain/LavaField/BraidedDelta/DuneStrand/MeanderReach) — the dramatic families (Cliff/Fjord/Gorge) already carry strong internal relief and a position-varying field warps their features; WaterBody stays at sea level.
|
||
|
||
Verification: new believability metric `contrast.voxel_relief_m` (mean within-district elevation range over a 2 km transect — a single 64 m chunk is narrower than the relief band). Arbour @ yolo: voxel relief 5 m → 59 m, criteria 6/8 → 7/8 (remaining fail = the Q-123 vegetation-denominator item, not relief). Edict also 59 m. 1586 lib tests + believability harness (determinism + golden) green; clippy -D warnings clean.
|
||
|
||
Deferred (Q-123 / follow-up): provisional VOXEL_RELIEF_SPAN_M=300 + the ≥8 m threshold need calibration; the ABSOLUTE elevation span is still the compressed elev_q/N base — a per-body hypsometric relief model is the later refinement. D-239 amended (T-1081); Q-123 item 4 updated.', 'in_progress', 'high', NULL, 'server', 'D-227', '2026-06-28 05:54:50.008', '2026-06-28 18:41:37.651', NULL, 'bd8abb0e2034f7dcb9a811f4d40b9eff', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJVW30PSP8K0XAWV02X7M0', 'story', '06FGSJNP8YM537DJCC82ZD6544', 'Near-zero voxel relief (0-3 m) — generated terrain has no hills or landmarks', 'Probe evidence (Arbour @ yolo): voxel elevation 0-3 m across nearly all sampled districts (only one snow upland reached 42-49 m). Flat terrain => nothing to navigate by, no landmarks, no ''specificity of place''. Either the heightmap relief is being flattened by the 512x256 working downsample + district derivation, or detail-scatter (D-227, derive-don''t-store) is not producing the mid-scale relief it is supposed to invent at the voxel tier. Direction to discuss: the relief envelope taken from the heightmap, detail-scatter amplitude, and whether the elev_q -> elevation_m mapping is collapsing the range. Believability gap.
|
||
|
||
---
|
||
Refinement (Si pass, 2026-06-28) — READY. Four compounding causes (all confirmed):
|
||
1. elev_q→elevation_m scale: generate_alluvial_plain uses `elev_q / 2` → whole-body relief is 0–50 m (pancake). Other flat families similar (/2,/3,/4). The dramatic families (cliff/fjord/gorge) carry real internal relief; the flat ones (alluvial/lava/dune/braided/meander) don''t.
|
||
2. detail_scatter (D-227) is applied ONLY at the district tier (derive_district → elev_q); it never reaches per-voxel elevation_m. So within a chunk relief = base ± 4 m micro-scatter = flat. The promised mid-scale (sub-district, ~tens-to-hundreds m) relief is missing at the voxel tier.
|
||
3. Envelope collapses to 0 on flat-slope districts (terrain_detail returns 0 when envelope==0) — by design ("no mountain on an authored plain"); consider a small floor so even gentle land rolls.
|
||
4. WaterBody correctly keeps elevation_m=0 (sea level) — must stay.
|
||
|
||
PLAN (data-driven, tune via probe like moisture):
|
||
- Add MID-SCALE rolling relief at the voxel tier: a detail-scatter octave term (sub-district wavelengths ~256–2048 m) added to elevation_m for DRY-LAND columns, enveloped by district ruggedness (slope_q) so plains stay flat and rugged terrain rolls. f64 perturbation truncated to i32 (D-010, same as the warp). Applied centrally in derive_voxel_column (one site, like derive_cover) so all land families benefit.
|
||
- Bump the flat-family base scale from the compressed /N toward a believable span if the probe shows mountains still too low (per-body absolute relief = T-1032 follow-up).
|
||
- Add a VOXEL-RELIEF metric to believability.rs (mean within-chunk elevation range across sampled non-water districts) — the current "elevation relief" criterion measures DISTRICT elev_q spread (already passes), not voxel relief, so it does not catch T-1081.
|
||
- VERIFY: probe per-location elevation range rises from ~0-3 m; the new voxel-relief criterion flips green. Determinism: integer/D-010.
|
||
Files: voxel.rs (generators + central relief), detail_scatter.rs (sub-district wavelengths), believability.rs (metric).
|
||
|
||
Implemented (2026-06-28, branch voxel-relief). The voxel tier now carries mid-scale relief (D-243 §2): a `voxel_relief` fBm pass at the 0.25–2 km octave band (detail_scatter.rs), body-global SeedDomain::VoxelRelief seed, added post-dispatch in derive_voxel_column, truncated to integer metres (D-010).
|
||
|
||
Root cause refined during impl: the coarse heightmap yields slope_q ≈ 0 even on high ground (Arbour max slope_q = 13), so the relief envelope is `slope_q*3 + elev_q` (elevation drives ruggedness), not slope alone. Applied to the FLAT families only (AlluvialPlain/LavaField/BraidedDelta/DuneStrand/MeanderReach) — the dramatic families (Cliff/Fjord/Gorge) already carry strong internal relief and a position-varying field warps their features; WaterBody stays at sea level.
|
||
|
||
Verification: new believability metric `contrast.voxel_relief_m` (mean within-district elevation range over a 2 km transect — a single 64 m chunk is narrower than the relief band). Arbour @ yolo: voxel relief 5 m → 59 m, criteria 6/8 → 7/8 (remaining fail = the Q-123 vegetation-denominator item, not relief). Edict also 59 m. 1586 lib tests + believability harness (determinism + golden) green; clippy -D warnings clean.
|
||
|
||
Deferred (Q-123 / follow-up): provisional VOXEL_RELIEF_SPAN_M=300 + the ≥8 m threshold need calibration; the ABSOLUTE elevation span is still the compressed elev_q/N base — a per-body hypsometric relief model is the later refinement. D-239 amended (T-1081); Q-123 item 4 updated.', 'review', 'high', NULL, 'server', 'D-227', '2026-06-28 05:54:50.008', '2026-06-28 18:42:16.275', NULL, '2487f66072b663853ae335b807756ddb', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSJVW30PSP8K0XAWV02X7M0', 'story', '06FGSJNP8YM537DJCC82ZD6544', 'Near-zero voxel relief (0-3 m) — generated terrain has no hills or landmarks', 'Probe evidence (Arbour @ yolo): voxel elevation 0-3 m across nearly all sampled districts (only one snow upland reached 42-49 m). Flat terrain => nothing to navigate by, no landmarks, no ''specificity of place''. Either the heightmap relief is being flattened by the 512x256 working downsample + district derivation, or detail-scatter (D-227, derive-don''t-store) is not producing the mid-scale relief it is supposed to invent at the voxel tier. Direction to discuss: the relief envelope taken from the heightmap, detail-scatter amplitude, and whether the elev_q -> elevation_m mapping is collapsing the range. Believability gap.
|
||
|
||
---
|
||
Refinement (Si pass, 2026-06-28) — READY. Four compounding causes (all confirmed):
|
||
1. elev_q→elevation_m scale: generate_alluvial_plain uses `elev_q / 2` → whole-body relief is 0–50 m (pancake). Other flat families similar (/2,/3,/4). The dramatic families (cliff/fjord/gorge) carry real internal relief; the flat ones (alluvial/lava/dune/braided/meander) don''t.
|
||
2. detail_scatter (D-227) is applied ONLY at the district tier (derive_district → elev_q); it never reaches per-voxel elevation_m. So within a chunk relief = base ± 4 m micro-scatter = flat. The promised mid-scale (sub-district, ~tens-to-hundreds m) relief is missing at the voxel tier.
|
||
3. Envelope collapses to 0 on flat-slope districts (terrain_detail returns 0 when envelope==0) — by design ("no mountain on an authored plain"); consider a small floor so even gentle land rolls.
|
||
4. WaterBody correctly keeps elevation_m=0 (sea level) — must stay.
|
||
|
||
PLAN (data-driven, tune via probe like moisture):
|
||
- Add MID-SCALE rolling relief at the voxel tier: a detail-scatter octave term (sub-district wavelengths ~256–2048 m) added to elevation_m for DRY-LAND columns, enveloped by district ruggedness (slope_q) so plains stay flat and rugged terrain rolls. f64 perturbation truncated to i32 (D-010, same as the warp). Applied centrally in derive_voxel_column (one site, like derive_cover) so all land families benefit.
|
||
- Bump the flat-family base scale from the compressed /N toward a believable span if the probe shows mountains still too low (per-body absolute relief = T-1032 follow-up).
|
||
- Add a VOXEL-RELIEF metric to believability.rs (mean within-chunk elevation range across sampled non-water districts) — the current "elevation relief" criterion measures DISTRICT elev_q spread (already passes), not voxel relief, so it does not catch T-1081.
|
||
- VERIFY: probe per-location elevation range rises from ~0-3 m; the new voxel-relief criterion flips green. Determinism: integer/D-010.
|
||
Files: voxel.rs (generators + central relief), detail_scatter.rs (sub-district wavelengths), believability.rs (metric).
|
||
|
||
Implemented (2026-06-28, branch voxel-relief). The voxel tier now carries mid-scale relief (D-243 §2): a `voxel_relief` fBm pass at the 0.25–2 km octave band (detail_scatter.rs), body-global SeedDomain::VoxelRelief seed, added post-dispatch in derive_voxel_column, truncated to integer metres (D-010).
|
||
|
||
Root cause refined during impl: the coarse heightmap yields slope_q ≈ 0 even on high ground (Arbour max slope_q = 13), so the relief envelope is `slope_q*3 + elev_q` (elevation drives ruggedness), not slope alone. Applied to the FLAT families only (AlluvialPlain/LavaField/BraidedDelta/DuneStrand/MeanderReach) — the dramatic families (Cliff/Fjord/Gorge) already carry strong internal relief and a position-varying field warps their features; WaterBody stays at sea level.
|
||
|
||
Verification: new believability metric `contrast.voxel_relief_m` (mean within-district elevation range over a 2 km transect — a single 64 m chunk is narrower than the relief band). Arbour @ yolo: voxel relief 5 m → 59 m, criteria 6/8 → 7/8 (remaining fail = the Q-123 vegetation-denominator item, not relief). Edict also 59 m. 1586 lib tests + believability harness (determinism + golden) green; clippy -D warnings clean.
|
||
|
||
Deferred (Q-123 / follow-up): provisional VOXEL_RELIEF_SPAN_M=300 + the ≥8 m threshold need calibration; the ABSOLUTE elevation span is still the compressed elev_q/N base — a per-body hypsometric relief model is the later refinement. D-239 amended (T-1081); Q-123 item 4 updated.', 'done', 'high', NULL, 'server', 'D-227', '2026-06-28 05:54:50.008', '2026-06-28 19:23:32.948', NULL, '5e596b52592847d7bd59ba1614f819b8', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|