3126 lines
935 KiB
SQL
3126 lines
935 KiB
SQL
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSK19FGZAC3H25VRAV4JRFW', 'description', '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).', '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).
|
||
|
||
---
|
||
Refinement (2026-07-02, /whats-next Si pass + user resolution): design gate resolved. First work item: write the Q/D-record (claim via `pql decisions claim D architecture`), pinning the five decisions below; then implement.
|
||
|
||
DECISIONS (user-resolved):
|
||
1. MECHANISM: new `voxel_mosaic()` octave band in detail_scatter.rs (~[64,32,16,8] m) + `SeedDomain::VoxelMosaic = 12` (append-only; update the pinned-discriminant test in server/src/seed.rs) → organic blob patches. Creeks + wet/dry conditioning follow the existing voxel_relief field''s micro-thalwegs (creeks along lowest-relief paths; bogs in lows, meadows on rises). ~4 extra value_noise calls/voxel — same cost class as voxel_relief.
|
||
2. VOCAB→AXES: expand D-228 enum VARIANTS (values on existing axes — not new axes) to cover the FULL shipped vocabulary NOW, all 7 classes. User rationale: palette composition affects the deterministic realization, so adding variants later would shift generated worlds — front-load the vocabulary. The complete axis-combination table for all 7×5–6 vocab items is the load-bearing content of the D-record, with a D-228 amendment for every item needing a new variant (deadfall / hardpan / lichen / fern-undergrowth have no honest existing mapping).
|
||
3. PALETTE RESIDENCY: `server/data/mosaic_constants.toml`, runtime-loaded like climate_constants.toml (T-1080 precedent). Note: the TOML is part of the deterministic input surface — weight changes change realizations; expected during Q-123 calibration, freeze after.
|
||
4. DoD METRIC IN SCOPE: add a within-patch intra-class variety field to ContrastMetrics (server/src/atlas/believability.rs) + a provisional criterion K≥3 distinct micro-features per sampled patch; Q-123 calibrates the final K. Matches the T-1081 precedent (mechanic + metric land together).
|
||
5. FAMILY GATING (grounded default, accepted): flat families (AlluvialPlain, LavaField, BraidedDelta, DuneStrand, MeanderReach) take the full mosaic; dramatic families (CliffCoast, FjordWall, IncisedGorge) get a per-family-gated non-structural modulation pass (vegetation/material only — must not warp carved geometry), mirroring voxel_relief gating. WaterBody: none. <5 ms chunk budget verification is part of implementation (T-1081 harness precedent).
|
||
|
||
CODE TOUCHPOINTS (Si-verified 2026-07-02): detail_scatter.rs:87-96 (voxel_relief pattern to extend), seed.rs:84-118 (SeedDomain; pinned-discriminant test ~:267), voxel.rs:1907-1943 (scatter_vegetation — the per-voxel salt-and-pepper this replaces), voxel.rs:445-495 (post-dispatch modulation seam), believability.rs (ContrastMetrics; evaluate_criteria ~:319). Overlaps to reconcile in the axis table: tube_depression (voxel.rs:710-717, Lava vocab) and braided-delta gravel-bar scrub (voxel.rs:1069-1092, Gravel vocab).', NULL, '2026-07-02 07:42:06', '2026-07-02 07:42:06.753', '2026-07-02 07:42:06.753', NULL, 'c8ddbe0307a798f866d712faa648eed6', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSK19FGZAC3H25VRAV4JRFW', 'status', 'backlog', 'in_progress', NULL, '2026-07-02 14:25:53', '2026-07-02 14:25:53.593', '2026-07-02 14:25:53.593', NULL, '30748fd1dc15dfc3c076d31e6d7f2b7c', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSK19FGZAC3H25VRAV4JRFW', 'description', '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).
|
||
|
||
---
|
||
Refinement (2026-07-02, /whats-next Si pass + user resolution): design gate resolved. First work item: write the Q/D-record (claim via `pql decisions claim D architecture`), pinning the five decisions below; then implement.
|
||
|
||
DECISIONS (user-resolved):
|
||
1. MECHANISM: new `voxel_mosaic()` octave band in detail_scatter.rs (~[64,32,16,8] m) + `SeedDomain::VoxelMosaic = 12` (append-only; update the pinned-discriminant test in server/src/seed.rs) → organic blob patches. Creeks + wet/dry conditioning follow the existing voxel_relief field''s micro-thalwegs (creeks along lowest-relief paths; bogs in lows, meadows on rises). ~4 extra value_noise calls/voxel — same cost class as voxel_relief.
|
||
2. VOCAB→AXES: expand D-228 enum VARIANTS (values on existing axes — not new axes) to cover the FULL shipped vocabulary NOW, all 7 classes. User rationale: palette composition affects the deterministic realization, so adding variants later would shift generated worlds — front-load the vocabulary. The complete axis-combination table for all 7×5–6 vocab items is the load-bearing content of the D-record, with a D-228 amendment for every item needing a new variant (deadfall / hardpan / lichen / fern-undergrowth have no honest existing mapping).
|
||
3. PALETTE RESIDENCY: `server/data/mosaic_constants.toml`, runtime-loaded like climate_constants.toml (T-1080 precedent). Note: the TOML is part of the deterministic input surface — weight changes change realizations; expected during Q-123 calibration, freeze after.
|
||
4. DoD METRIC IN SCOPE: add a within-patch intra-class variety field to ContrastMetrics (server/src/atlas/believability.rs) + a provisional criterion K≥3 distinct micro-features per sampled patch; Q-123 calibrates the final K. Matches the T-1081 precedent (mechanic + metric land together).
|
||
5. FAMILY GATING (grounded default, accepted): flat families (AlluvialPlain, LavaField, BraidedDelta, DuneStrand, MeanderReach) take the full mosaic; dramatic families (CliffCoast, FjordWall, IncisedGorge) get a per-family-gated non-structural modulation pass (vegetation/material only — must not warp carved geometry), mirroring voxel_relief gating. WaterBody: none. <5 ms chunk budget verification is part of implementation (T-1081 harness precedent).
|
||
|
||
CODE TOUCHPOINTS (Si-verified 2026-07-02): detail_scatter.rs:87-96 (voxel_relief pattern to extend), seed.rs:84-118 (SeedDomain; pinned-discriminant test ~:267), voxel.rs:1907-1943 (scatter_vegetation — the per-voxel salt-and-pepper this replaces), voxel.rs:445-495 (post-dispatch modulation seam), believability.rs (ContrastMetrics; evaluate_criteria ~:319). Overlaps to reconcile in the axis table: tube_depression (voxel.rs:710-717, Lava vocab) and braided-delta gravel-bar scrub (voxel.rs:1069-1092, Gravel vocab).', '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).
|
||
|
||
---
|
||
Refinement (2026-07-02, /whats-next Si pass + user resolution): design gate resolved. First work item: write the Q/D-record (claim via `pql decisions claim D architecture`), pinning the five decisions below; then implement.
|
||
|
||
DECISIONS (user-resolved):
|
||
1. MECHANISM: new `voxel_mosaic()` octave band in detail_scatter.rs (~[64,32,16,8] m) + `SeedDomain::VoxelMosaic = 12` (append-only; update the pinned-discriminant test in server/src/seed.rs) → organic blob patches. Creeks + wet/dry conditioning follow the existing voxel_relief field''s micro-thalwegs (creeks along lowest-relief paths; bogs in lows, meadows on rises). ~4 extra value_noise calls/voxel — same cost class as voxel_relief.
|
||
2. VOCAB→AXES: expand D-228 enum VARIANTS (values on existing axes — not new axes) to cover the FULL shipped vocabulary NOW, all 7 classes. User rationale: palette composition affects the deterministic realization, so adding variants later would shift generated worlds — front-load the vocabulary. The complete axis-combination table for all 7×5–6 vocab items is the load-bearing content of the D-record, with a D-228 amendment for every item needing a new variant (deadfall / hardpan / lichen / fern-undergrowth have no honest existing mapping).
|
||
3. PALETTE RESIDENCY: `server/data/mosaic_constants.toml`, runtime-loaded like climate_constants.toml (T-1080 precedent). Note: the TOML is part of the deterministic input surface — weight changes change realizations; expected during Q-123 calibration, freeze after.
|
||
4. DoD METRIC IN SCOPE: add a within-patch intra-class variety field to ContrastMetrics (server/src/atlas/believability.rs) + a provisional criterion K≥3 distinct micro-features per sampled patch; Q-123 calibrates the final K. Matches the T-1081 precedent (mechanic + metric land together).
|
||
5. FAMILY GATING (grounded default, accepted): flat families (AlluvialPlain, LavaField, BraidedDelta, DuneStrand, MeanderReach) take the full mosaic; dramatic families (CliffCoast, FjordWall, IncisedGorge) get a per-family-gated non-structural modulation pass (vegetation/material only — must not warp carved geometry), mirroring voxel_relief gating. WaterBody: none. <5 ms chunk budget verification is part of implementation (T-1081 harness precedent).
|
||
|
||
CODE TOUCHPOINTS (Si-verified 2026-07-02): detail_scatter.rs:87-96 (voxel_relief pattern to extend), seed.rs:84-118 (SeedDomain; pinned-discriminant test ~:267), voxel.rs:1907-1943 (scatter_vegetation — the per-voxel salt-and-pepper this replaces), voxel.rs:445-495 (post-dispatch modulation seam), believability.rs (ContrastMetrics; evaluate_criteria ~:319). Overlaps to reconcile in the axis table: tube_depression (voxel.rs:710-717, Lava vocab) and braided-delta gravel-bar scrub (voxel.rs:1069-1092, Gravel vocab).
|
||
|
||
D-record written: D-246 (governance/decisions/architecture.md) pins all five resolved decisions + the full 32-row vocab→D-228 axis table + palette-key rule. D-228 amended to add the five new axis values (Vegetation::{Meadow,Deadfall,Lichen}, TerrainMaterial::{Hardpan,Scree}). D-246 is now the governing record for implementation; decision_ref D-227 kept as the derive-don''t-store parent.', NULL, '2026-07-02 18:26:37', '2026-07-02 18:26:37.203', '2026-07-02 18:26:37.203', NULL, 'c38329ce7eea51cd8aa53b0c5769da76', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ91R8RV38BJXGB2V55FP3B8', 'description', 'Operationalize the D-247 native-biosphere premise. Full brief appended.', 'Operationalize the D-247 native-biosphere premise. Full brief appended.
|
||
|
||
---
|
||
BRIEF (2026-07-02) — governing record: D-247 (governance/decisions/content.md); consumer: D-246 / T-1084 mosaic register.
|
||
|
||
WHAT THIS IS
|
||
D-247 established that habitable Reach worlds were alive before humans (the settlement timeline forbids terraforming from dead rock), and that an AUTHORED per-world chirality bit gates whether native life is edible. This ticket turns that canon into data + reconciled wiki + the vocabulary the mosaic needs. Owner: Miri (worldbuilding/continuity). Stakeholder: Burnelli (food-import economics). Co-maintainer for the vocab: Araminta (visual grammar, per the T-995 ObjectTag precedent).
|
||
|
||
THE MODEL (locked in D-247 — do not re-litigate, apply it):
|
||
- `biosphere_class ∈ {NativeCompatible, NativeMirror, TerraformedSterile, Airless}`. It is an AUTHORED INPUT, never seed-derived — it follows a world''s economic/cultural identity.
|
||
- Compatible ("levo") = edible; coupling *permits* an authored hazard but does not force it (most are benign gardens).
|
||
- Mirror ("dextro") = inedible but *guaranteed* inert (can''t infect/poison — safe to study).
|
||
- "Safe" ≠ "edible" — decoupled. Bio-safe is guaranteed on Mirror; food-safe is Compatible-only.
|
||
- Achiral seam (always works either way): breathe air, drink water, mine ore, burn/build with native biomass. Only eat/metabolize/medicate/infect/chirally-poison are gated.
|
||
- ~50/50 Compatible:Mirror is a DESIGN TARGET across canon-silent worlds, not a per-world draw.
|
||
|
||
WORKSTREAMS
|
||
1. CHIRALITY ASSIGNMENT (Miri). Give every inhabited body a biosphere_class by authored identity: principled default from `economic_base_primary` + `planet_class` (food/drink exporters → Compatible; dead+maintained-atmosphere → TerraformedSterile), explicit overrides where canon speaks. Locked exemplars: Arbour (GJ-338B)=Compatible; Solandar (GJ-827)=Mirror; Keid (GJ-166A)=Compatible (preserved *from exploitation* of edible alien life — the stronger conservation motive; Solandar is the Mirror-inert preserve); Oshima (GJ-79)=TerraformedSterile. Hit the ~50/50 target across the silent remainder.
|
||
2. WIKI CONTINUITY (Miri). Reconcile the entries that already gesture at native biochemistry so each is consistent with its assigned bit + the mechanism: GJ-827, GJ-524, GJ-166A, GJ-684A, GJ-197, GJ-79, GJ-124 (resolve whether Hạ Long''s "protein" is native-Compatible harvest or Earth aquaculture). Additive/explanatory, not contradictory — preserve deliberately-vague lines as intentional.
|
||
3. biosphere_class AUTHORING PATH (asset-pipeline discipline — schema + source + values together, per .claude/rules/asset-pipeline.md). Add `biosphere_class` to wiki body frontmatter (where `substrate:` already lives), a nullable `bodies.biosphere_class` column in systems-schema.sql + MIGRATION_SQL, and importer read. NOT needed for D-246; lands with this pass.
|
||
4. ALIEN-ECOLOGY VOCABULARY (Miri + Araminta) — feeds T-1084 directly. The mosaic palette is keyed on surface-class × climate-biome × biosphere-register (D-246 Palette-key). Provide the micro-habitat NAMES per biome × register: native-mirror niches get *alien* clade names (Solandar''s "five kingdoms" flavor); introduced-Earth niches get Earth names (wheatfield, orchard, pasture). Fill the fixed niche spine (canopy / understory / wet-hollow / pioneer / bare) per climate-biome (savanna gallery-copse, tundra thermokarst / lichen-heath, boreal muskeg / deadfall, …). DETERMINISM: the vocab must be fixed before T-1084 generates its first world (a later addition re-rolls affected voxels). Table size is not a perf/storage concern — author generously but to taste (~100k is headroom, not a target).
|
||
|
||
BURNELLI (stakeholder, follow-on): a food-supply demand primitive keyed on biosphere_class (Mirror + frontier → import dependency; Compatible → local-food capable). Phase-2 economy consumer; does not block this ticket.
|
||
|
||
CONSTRAINTS
|
||
- Authored input, not derivation (Arbour''s estate food must never be coin-flipped inedible).
|
||
- Semantic axes stay clade-agnostic (Forest = canopy whether oak or mega-fungus); the register skins niches, it does not change gameplay semantics.
|
||
- The mosaic geometry is chirality-blind — this work does NOT touch voxel geometry, only edibility/economy/naming/vocab.', NULL, '2026-07-02 20:33:09', '2026-07-02 20:33:09.514', '2026-07-02 20:33:09.514', NULL, '02a8635cdb5f42ec0a512d12804b3f35', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ91R8RV38BJXGB2V55FP3B8', 'description', 'Operationalize the D-247 native-biosphere premise. Full brief appended.
|
||
|
||
---
|
||
BRIEF (2026-07-02) — governing record: D-247 (governance/decisions/content.md); consumer: D-246 / T-1084 mosaic register.
|
||
|
||
WHAT THIS IS
|
||
D-247 established that habitable Reach worlds were alive before humans (the settlement timeline forbids terraforming from dead rock), and that an AUTHORED per-world chirality bit gates whether native life is edible. This ticket turns that canon into data + reconciled wiki + the vocabulary the mosaic needs. Owner: Miri (worldbuilding/continuity). Stakeholder: Burnelli (food-import economics). Co-maintainer for the vocab: Araminta (visual grammar, per the T-995 ObjectTag precedent).
|
||
|
||
THE MODEL (locked in D-247 — do not re-litigate, apply it):
|
||
- `biosphere_class ∈ {NativeCompatible, NativeMirror, TerraformedSterile, Airless}`. It is an AUTHORED INPUT, never seed-derived — it follows a world''s economic/cultural identity.
|
||
- Compatible ("levo") = edible; coupling *permits* an authored hazard but does not force it (most are benign gardens).
|
||
- Mirror ("dextro") = inedible but *guaranteed* inert (can''t infect/poison — safe to study).
|
||
- "Safe" ≠ "edible" — decoupled. Bio-safe is guaranteed on Mirror; food-safe is Compatible-only.
|
||
- Achiral seam (always works either way): breathe air, drink water, mine ore, burn/build with native biomass. Only eat/metabolize/medicate/infect/chirally-poison are gated.
|
||
- ~50/50 Compatible:Mirror is a DESIGN TARGET across canon-silent worlds, not a per-world draw.
|
||
|
||
WORKSTREAMS
|
||
1. CHIRALITY ASSIGNMENT (Miri). Give every inhabited body a biosphere_class by authored identity: principled default from `economic_base_primary` + `planet_class` (food/drink exporters → Compatible; dead+maintained-atmosphere → TerraformedSterile), explicit overrides where canon speaks. Locked exemplars: Arbour (GJ-338B)=Compatible; Solandar (GJ-827)=Mirror; Keid (GJ-166A)=Compatible (preserved *from exploitation* of edible alien life — the stronger conservation motive; Solandar is the Mirror-inert preserve); Oshima (GJ-79)=TerraformedSterile. Hit the ~50/50 target across the silent remainder.
|
||
2. WIKI CONTINUITY (Miri). Reconcile the entries that already gesture at native biochemistry so each is consistent with its assigned bit + the mechanism: GJ-827, GJ-524, GJ-166A, GJ-684A, GJ-197, GJ-79, GJ-124 (resolve whether Hạ Long''s "protein" is native-Compatible harvest or Earth aquaculture). Additive/explanatory, not contradictory — preserve deliberately-vague lines as intentional.
|
||
3. biosphere_class AUTHORING PATH (asset-pipeline discipline — schema + source + values together, per .claude/rules/asset-pipeline.md). Add `biosphere_class` to wiki body frontmatter (where `substrate:` already lives), a nullable `bodies.biosphere_class` column in systems-schema.sql + MIGRATION_SQL, and importer read. NOT needed for D-246; lands with this pass.
|
||
4. ALIEN-ECOLOGY VOCABULARY (Miri + Araminta) — feeds T-1084 directly. The mosaic palette is keyed on surface-class × climate-biome × biosphere-register (D-246 Palette-key). Provide the micro-habitat NAMES per biome × register: native-mirror niches get *alien* clade names (Solandar''s "five kingdoms" flavor); introduced-Earth niches get Earth names (wheatfield, orchard, pasture). Fill the fixed niche spine (canopy / understory / wet-hollow / pioneer / bare) per climate-biome (savanna gallery-copse, tundra thermokarst / lichen-heath, boreal muskeg / deadfall, …). DETERMINISM: the vocab must be fixed before T-1084 generates its first world (a later addition re-rolls affected voxels). Table size is not a perf/storage concern — author generously but to taste (~100k is headroom, not a target).
|
||
|
||
BURNELLI (stakeholder, follow-on): a food-supply demand primitive keyed on biosphere_class (Mirror + frontier → import dependency; Compatible → local-food capable). Phase-2 economy consumer; does not block this ticket.
|
||
|
||
CONSTRAINTS
|
||
- Authored input, not derivation (Arbour''s estate food must never be coin-flipped inedible).
|
||
- Semantic axes stay clade-agnostic (Forest = canopy whether oak or mega-fungus); the register skins niches, it does not change gameplay semantics.
|
||
- The mosaic geometry is chirality-blind — this work does NOT touch voxel geometry, only edibility/economy/naming/vocab.', 'Operationalize the D-247 native-biosphere premise. Full brief appended.
|
||
|
||
---
|
||
BRIEF (2026-07-02) — governing record: D-247 (governance/decisions/content.md); consumer: D-246 / T-1084 mosaic register.
|
||
|
||
WHAT THIS IS
|
||
D-247 established that habitable Reach worlds were alive before humans (the settlement timeline forbids terraforming from dead rock), and that an AUTHORED per-world chirality bit gates whether native life is edible. This ticket turns that canon into data + reconciled wiki + the vocabulary the mosaic needs. Owner: Miri (worldbuilding/continuity). Stakeholder: Burnelli (food-import economics). Co-maintainer for the vocab: Araminta (visual grammar, per the T-995 ObjectTag precedent).
|
||
|
||
THE MODEL (locked in D-247 — do not re-litigate, apply it):
|
||
- `biosphere_class ∈ {NativeCompatible, NativeMirror, TerraformedSterile, Airless}`. It is an AUTHORED INPUT, never seed-derived — it follows a world''s economic/cultural identity.
|
||
- Compatible ("levo") = edible; coupling *permits* an authored hazard but does not force it (most are benign gardens).
|
||
- Mirror ("dextro") = inedible but *guaranteed* inert (can''t infect/poison — safe to study).
|
||
- "Safe" ≠ "edible" — decoupled. Bio-safe is guaranteed on Mirror; food-safe is Compatible-only.
|
||
- Achiral seam (always works either way): breathe air, drink water, mine ore, burn/build with native biomass. Only eat/metabolize/medicate/infect/chirally-poison are gated.
|
||
- ~50/50 Compatible:Mirror is a DESIGN TARGET across canon-silent worlds, not a per-world draw.
|
||
|
||
WORKSTREAMS
|
||
1. CHIRALITY ASSIGNMENT (Miri). Give every inhabited body a biosphere_class by authored identity: principled default from `economic_base_primary` + `planet_class` (food/drink exporters → Compatible; dead+maintained-atmosphere → TerraformedSterile), explicit overrides where canon speaks. Locked exemplars: Arbour (GJ-338B)=Compatible; Solandar (GJ-827)=Mirror; Keid (GJ-166A)=Compatible (preserved *from exploitation* of edible alien life — the stronger conservation motive; Solandar is the Mirror-inert preserve); Oshima (GJ-79)=TerraformedSterile. Hit the ~50/50 target across the silent remainder.
|
||
2. WIKI CONTINUITY (Miri). Reconcile the entries that already gesture at native biochemistry so each is consistent with its assigned bit + the mechanism: GJ-827, GJ-524, GJ-166A, GJ-684A, GJ-197, GJ-79, GJ-124 (resolve whether Hạ Long''s "protein" is native-Compatible harvest or Earth aquaculture). Additive/explanatory, not contradictory — preserve deliberately-vague lines as intentional.
|
||
3. biosphere_class AUTHORING PATH (asset-pipeline discipline — schema + source + values together, per .claude/rules/asset-pipeline.md). Add `biosphere_class` to wiki body frontmatter (where `substrate:` already lives), a nullable `bodies.biosphere_class` column in systems-schema.sql + MIGRATION_SQL, and importer read. NOT needed for D-246; lands with this pass.
|
||
4. ALIEN-ECOLOGY VOCABULARY (Miri + Araminta) — feeds T-1084 directly. The mosaic palette is keyed on surface-class × climate-biome × biosphere-register (D-246 Palette-key). Provide the micro-habitat NAMES per biome × register: native-mirror niches get *alien* clade names (Solandar''s "five kingdoms" flavor); introduced-Earth niches get Earth names (wheatfield, orchard, pasture). Fill the fixed niche spine (canopy / understory / wet-hollow / pioneer / bare) per climate-biome (savanna gallery-copse, tundra thermokarst / lichen-heath, boreal muskeg / deadfall, …). DETERMINISM: the vocab must be fixed before T-1084 generates its first world (a later addition re-rolls affected voxels). Table size is not a perf/storage concern — author generously but to taste (~100k is headroom, not a target).
|
||
|
||
BURNELLI (stakeholder, follow-on): a food-supply demand primitive keyed on biosphere_class (Mirror + frontier → import dependency; Compatible → local-food capable). Phase-2 economy consumer; does not block this ticket.
|
||
|
||
CONSTRAINTS
|
||
- Authored input, not derivation (Arbour''s estate food must never be coin-flipped inedible).
|
||
- Semantic axes stay clade-agnostic (Forest = canopy whether oak or mega-fungus); the register skins niches, it does not change gameplay semantics.
|
||
- The mosaic geometry is chirality-blind — this work does NOT touch voxel geometry, only edibility/economy/naming/vocab.
|
||
|
||
Chirality decisions resolved (2026-07-02, with Jeroen):
|
||
- Locked exemplars: Arbour=NativeCompatible, Solandar=NativeMirror, Keid=NativeCompatible, Oshima=TerraformedSterile.
|
||
- Miri assignments accepted: GJ-524=Mirror, Freyburg(GJ-684A)=Compatible, Hạ Long(GJ-124)=Compatible (native-Compatible harvest, per her rationale).
|
||
- USER OVERRIDES: Puerto Último(GJ-197)=NativeCompatible (breadbasket identity over Miri''s balance-motivated Mirror). Edict/Sirius(GJ-244A)=Airless — keep the world harsh/frozen (deliberately-inconvenient below-grade transit capital is load-bearing canon); no climate change; below-grade sealed habitat = no open-air biosphere.
|
||
- Two-gate default rule ACCEPTED for canon-silent worlds: Gate 0 (habitability from atmosphere/hydrosphere frontmatter → Airless / TerraformedSterile / Alive), Gate 1 (Compatible vs Mirror from economic_base_primary; agriculture→Compatible near-lock, penal→Mirror, research→50/50 lever).
|
||
- NAMING: Keid''s habitable body renamed Cadwal→(pending final pick; rec Linnaeus — pairs with Solander, its student naturalist; or Beagle). Capital stays ''Vance'' (already the author tribute). Miri''s IP flag (Cadwal = Vance''s exact book title) is the driver.
|
||
- Still to APPLY: the 7 additive wiki continuity edits (Miri specified exact text), the biosphere_class frontmatter+schema+importer plumbing (workstream 3), and the Cadwal→<name> rename across wiki + the GJ166A atlas proposal.', NULL, '2026-07-02 21:23:34', '2026-07-02 21:23:34.735', '2026-07-02 21:23:34.735', NULL, '80cb1aabee1e9defb9795e677e7ee58d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ91R8RV38BJXGB2V55FP3B8', 'description', 'Operationalize the D-247 native-biosphere premise. Full brief appended.
|
||
|
||
---
|
||
BRIEF (2026-07-02) — governing record: D-247 (governance/decisions/content.md); consumer: D-246 / T-1084 mosaic register.
|
||
|
||
WHAT THIS IS
|
||
D-247 established that habitable Reach worlds were alive before humans (the settlement timeline forbids terraforming from dead rock), and that an AUTHORED per-world chirality bit gates whether native life is edible. This ticket turns that canon into data + reconciled wiki + the vocabulary the mosaic needs. Owner: Miri (worldbuilding/continuity). Stakeholder: Burnelli (food-import economics). Co-maintainer for the vocab: Araminta (visual grammar, per the T-995 ObjectTag precedent).
|
||
|
||
THE MODEL (locked in D-247 — do not re-litigate, apply it):
|
||
- `biosphere_class ∈ {NativeCompatible, NativeMirror, TerraformedSterile, Airless}`. It is an AUTHORED INPUT, never seed-derived — it follows a world''s economic/cultural identity.
|
||
- Compatible ("levo") = edible; coupling *permits* an authored hazard but does not force it (most are benign gardens).
|
||
- Mirror ("dextro") = inedible but *guaranteed* inert (can''t infect/poison — safe to study).
|
||
- "Safe" ≠ "edible" — decoupled. Bio-safe is guaranteed on Mirror; food-safe is Compatible-only.
|
||
- Achiral seam (always works either way): breathe air, drink water, mine ore, burn/build with native biomass. Only eat/metabolize/medicate/infect/chirally-poison are gated.
|
||
- ~50/50 Compatible:Mirror is a DESIGN TARGET across canon-silent worlds, not a per-world draw.
|
||
|
||
WORKSTREAMS
|
||
1. CHIRALITY ASSIGNMENT (Miri). Give every inhabited body a biosphere_class by authored identity: principled default from `economic_base_primary` + `planet_class` (food/drink exporters → Compatible; dead+maintained-atmosphere → TerraformedSterile), explicit overrides where canon speaks. Locked exemplars: Arbour (GJ-338B)=Compatible; Solandar (GJ-827)=Mirror; Keid (GJ-166A)=Compatible (preserved *from exploitation* of edible alien life — the stronger conservation motive; Solandar is the Mirror-inert preserve); Oshima (GJ-79)=TerraformedSterile. Hit the ~50/50 target across the silent remainder.
|
||
2. WIKI CONTINUITY (Miri). Reconcile the entries that already gesture at native biochemistry so each is consistent with its assigned bit + the mechanism: GJ-827, GJ-524, GJ-166A, GJ-684A, GJ-197, GJ-79, GJ-124 (resolve whether Hạ Long''s "protein" is native-Compatible harvest or Earth aquaculture). Additive/explanatory, not contradictory — preserve deliberately-vague lines as intentional.
|
||
3. biosphere_class AUTHORING PATH (asset-pipeline discipline — schema + source + values together, per .claude/rules/asset-pipeline.md). Add `biosphere_class` to wiki body frontmatter (where `substrate:` already lives), a nullable `bodies.biosphere_class` column in systems-schema.sql + MIGRATION_SQL, and importer read. NOT needed for D-246; lands with this pass.
|
||
4. ALIEN-ECOLOGY VOCABULARY (Miri + Araminta) — feeds T-1084 directly. The mosaic palette is keyed on surface-class × climate-biome × biosphere-register (D-246 Palette-key). Provide the micro-habitat NAMES per biome × register: native-mirror niches get *alien* clade names (Solandar''s "five kingdoms" flavor); introduced-Earth niches get Earth names (wheatfield, orchard, pasture). Fill the fixed niche spine (canopy / understory / wet-hollow / pioneer / bare) per climate-biome (savanna gallery-copse, tundra thermokarst / lichen-heath, boreal muskeg / deadfall, …). DETERMINISM: the vocab must be fixed before T-1084 generates its first world (a later addition re-rolls affected voxels). Table size is not a perf/storage concern — author generously but to taste (~100k is headroom, not a target).
|
||
|
||
BURNELLI (stakeholder, follow-on): a food-supply demand primitive keyed on biosphere_class (Mirror + frontier → import dependency; Compatible → local-food capable). Phase-2 economy consumer; does not block this ticket.
|
||
|
||
CONSTRAINTS
|
||
- Authored input, not derivation (Arbour''s estate food must never be coin-flipped inedible).
|
||
- Semantic axes stay clade-agnostic (Forest = canopy whether oak or mega-fungus); the register skins niches, it does not change gameplay semantics.
|
||
- The mosaic geometry is chirality-blind — this work does NOT touch voxel geometry, only edibility/economy/naming/vocab.
|
||
|
||
Chirality decisions resolved (2026-07-02, with Jeroen):
|
||
- Locked exemplars: Arbour=NativeCompatible, Solandar=NativeMirror, Keid=NativeCompatible, Oshima=TerraformedSterile.
|
||
- Miri assignments accepted: GJ-524=Mirror, Freyburg(GJ-684A)=Compatible, Hạ Long(GJ-124)=Compatible (native-Compatible harvest, per her rationale).
|
||
- USER OVERRIDES: Puerto Último(GJ-197)=NativeCompatible (breadbasket identity over Miri''s balance-motivated Mirror). Edict/Sirius(GJ-244A)=Airless — keep the world harsh/frozen (deliberately-inconvenient below-grade transit capital is load-bearing canon); no climate change; below-grade sealed habitat = no open-air biosphere.
|
||
- Two-gate default rule ACCEPTED for canon-silent worlds: Gate 0 (habitability from atmosphere/hydrosphere frontmatter → Airless / TerraformedSterile / Alive), Gate 1 (Compatible vs Mirror from economic_base_primary; agriculture→Compatible near-lock, penal→Mirror, research→50/50 lever).
|
||
- NAMING: Keid''s habitable body renamed Cadwal→(pending final pick; rec Linnaeus — pairs with Solander, its student naturalist; or Beagle). Capital stays ''Vance'' (already the author tribute). Miri''s IP flag (Cadwal = Vance''s exact book title) is the driver.
|
||
- Still to APPLY: the 7 additive wiki continuity edits (Miri specified exact text), the biosphere_class frontmatter+schema+importer plumbing (workstream 3), and the Cadwal→<name> rename across wiki + the GJ166A atlas proposal.', 'Operationalize the D-247 native-biosphere premise. Full brief appended.
|
||
|
||
---
|
||
BRIEF (2026-07-02) — governing record: D-247 (governance/decisions/content.md); consumer: D-246 / T-1084 mosaic register.
|
||
|
||
WHAT THIS IS
|
||
D-247 established that habitable Reach worlds were alive before humans (the settlement timeline forbids terraforming from dead rock), and that an AUTHORED per-world chirality bit gates whether native life is edible. This ticket turns that canon into data + reconciled wiki + the vocabulary the mosaic needs. Owner: Miri (worldbuilding/continuity). Stakeholder: Burnelli (food-import economics). Co-maintainer for the vocab: Araminta (visual grammar, per the T-995 ObjectTag precedent).
|
||
|
||
THE MODEL (locked in D-247 — do not re-litigate, apply it):
|
||
- `biosphere_class ∈ {NativeCompatible, NativeMirror, TerraformedSterile, Airless}`. It is an AUTHORED INPUT, never seed-derived — it follows a world''s economic/cultural identity.
|
||
- Compatible ("levo") = edible; coupling *permits* an authored hazard but does not force it (most are benign gardens).
|
||
- Mirror ("dextro") = inedible but *guaranteed* inert (can''t infect/poison — safe to study).
|
||
- "Safe" ≠ "edible" — decoupled. Bio-safe is guaranteed on Mirror; food-safe is Compatible-only.
|
||
- Achiral seam (always works either way): breathe air, drink water, mine ore, burn/build with native biomass. Only eat/metabolize/medicate/infect/chirally-poison are gated.
|
||
- ~50/50 Compatible:Mirror is a DESIGN TARGET across canon-silent worlds, not a per-world draw.
|
||
|
||
WORKSTREAMS
|
||
1. CHIRALITY ASSIGNMENT (Miri). Give every inhabited body a biosphere_class by authored identity: principled default from `economic_base_primary` + `planet_class` (food/drink exporters → Compatible; dead+maintained-atmosphere → TerraformedSterile), explicit overrides where canon speaks. Locked exemplars: Arbour (GJ-338B)=Compatible; Solandar (GJ-827)=Mirror; Keid (GJ-166A)=Compatible (preserved *from exploitation* of edible alien life — the stronger conservation motive; Solandar is the Mirror-inert preserve); Oshima (GJ-79)=TerraformedSterile. Hit the ~50/50 target across the silent remainder.
|
||
2. WIKI CONTINUITY (Miri). Reconcile the entries that already gesture at native biochemistry so each is consistent with its assigned bit + the mechanism: GJ-827, GJ-524, GJ-166A, GJ-684A, GJ-197, GJ-79, GJ-124 (resolve whether Hạ Long''s "protein" is native-Compatible harvest or Earth aquaculture). Additive/explanatory, not contradictory — preserve deliberately-vague lines as intentional.
|
||
3. biosphere_class AUTHORING PATH (asset-pipeline discipline — schema + source + values together, per .claude/rules/asset-pipeline.md). Add `biosphere_class` to wiki body frontmatter (where `substrate:` already lives), a nullable `bodies.biosphere_class` column in systems-schema.sql + MIGRATION_SQL, and importer read. NOT needed for D-246; lands with this pass.
|
||
4. ALIEN-ECOLOGY VOCABULARY (Miri + Araminta) — feeds T-1084 directly. The mosaic palette is keyed on surface-class × climate-biome × biosphere-register (D-246 Palette-key). Provide the micro-habitat NAMES per biome × register: native-mirror niches get *alien* clade names (Solandar''s "five kingdoms" flavor); introduced-Earth niches get Earth names (wheatfield, orchard, pasture). Fill the fixed niche spine (canopy / understory / wet-hollow / pioneer / bare) per climate-biome (savanna gallery-copse, tundra thermokarst / lichen-heath, boreal muskeg / deadfall, …). DETERMINISM: the vocab must be fixed before T-1084 generates its first world (a later addition re-rolls affected voxels). Table size is not a perf/storage concern — author generously but to taste (~100k is headroom, not a target).
|
||
|
||
BURNELLI (stakeholder, follow-on): a food-supply demand primitive keyed on biosphere_class (Mirror + frontier → import dependency; Compatible → local-food capable). Phase-2 economy consumer; does not block this ticket.
|
||
|
||
CONSTRAINTS
|
||
- Authored input, not derivation (Arbour''s estate food must never be coin-flipped inedible).
|
||
- Semantic axes stay clade-agnostic (Forest = canopy whether oak or mega-fungus); the register skins niches, it does not change gameplay semantics.
|
||
- The mosaic geometry is chirality-blind — this work does NOT touch voxel geometry, only edibility/economy/naming/vocab.
|
||
|
||
Chirality decisions resolved (2026-07-02, with Jeroen):
|
||
- Locked exemplars: Arbour=NativeCompatible, Solandar=NativeMirror, Keid=NativeCompatible, Oshima=TerraformedSterile.
|
||
- Miri assignments accepted: GJ-524=Mirror, Freyburg(GJ-684A)=Compatible, Hạ Long(GJ-124)=Compatible (native-Compatible harvest, per her rationale).
|
||
- USER OVERRIDES: Puerto Último(GJ-197)=NativeCompatible (breadbasket identity over Miri''s balance-motivated Mirror). Edict/Sirius(GJ-244A)=Airless — keep the world harsh/frozen (deliberately-inconvenient below-grade transit capital is load-bearing canon); no climate change; below-grade sealed habitat = no open-air biosphere.
|
||
- Two-gate default rule ACCEPTED for canon-silent worlds: Gate 0 (habitability from atmosphere/hydrosphere frontmatter → Airless / TerraformedSterile / Alive), Gate 1 (Compatible vs Mirror from economic_base_primary; agriculture→Compatible near-lock, penal→Mirror, research→50/50 lever).
|
||
- NAMING: Keid''s habitable body renamed Cadwal→(pending final pick; rec Linnaeus — pairs with Solander, its student naturalist; or Beagle). Capital stays ''Vance'' (already the author tribute). Miri''s IP flag (Cadwal = Vance''s exact book title) is the driver.
|
||
- Still to APPLY: the 7 additive wiki continuity edits (Miri specified exact text), the biosphere_class frontmatter+schema+importer plumbing (workstream 3), and the Cadwal→<name> rename across wiki + the GJ166A atlas proposal.
|
||
|
||
NAMING CONFIRMED: Keid''s habitable body Cadwal → Linnaeus (the great classifier; ties to Solander/Solandar taxonomy + the ''five kingdoms''). Capital stays Vance.', NULL, '2026-07-02 21:24:12', '2026-07-02 21:24:12.734', '2026-07-02 21:24:12.734', NULL, 'b13c9f1ce1d47437fdb599e6efce7f0e', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ91R8RV38BJXGB2V55FP3B8', 'status', 'backlog', 'in_progress', NULL, '2026-07-03 20:18:52', '2026-07-03 20:18:52.241', '2026-07-03 20:18:52.241', NULL, '89aa6692b3a1ab821cb7b02c3970f5a5', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ91R8RV38BJXGB2V55FP3B8', 'status', 'in_progress', 'in_progress', NULL, '2026-07-03 20:20:01', '2026-07-03 20:20:01.466', '2026-07-03 20:20:01.466', NULL, '6d2a3d77d702940bbc9207e4b9ce2b26', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ91R8RV38BJXGB2V55FP3B8', 'description', 'Operationalize the D-247 native-biosphere premise. Full brief appended.
|
||
|
||
---
|
||
BRIEF (2026-07-02) — governing record: D-247 (governance/decisions/content.md); consumer: D-246 / T-1084 mosaic register.
|
||
|
||
WHAT THIS IS
|
||
D-247 established that habitable Reach worlds were alive before humans (the settlement timeline forbids terraforming from dead rock), and that an AUTHORED per-world chirality bit gates whether native life is edible. This ticket turns that canon into data + reconciled wiki + the vocabulary the mosaic needs. Owner: Miri (worldbuilding/continuity). Stakeholder: Burnelli (food-import economics). Co-maintainer for the vocab: Araminta (visual grammar, per the T-995 ObjectTag precedent).
|
||
|
||
THE MODEL (locked in D-247 — do not re-litigate, apply it):
|
||
- `biosphere_class ∈ {NativeCompatible, NativeMirror, TerraformedSterile, Airless}`. It is an AUTHORED INPUT, never seed-derived — it follows a world''s economic/cultural identity.
|
||
- Compatible ("levo") = edible; coupling *permits* an authored hazard but does not force it (most are benign gardens).
|
||
- Mirror ("dextro") = inedible but *guaranteed* inert (can''t infect/poison — safe to study).
|
||
- "Safe" ≠ "edible" — decoupled. Bio-safe is guaranteed on Mirror; food-safe is Compatible-only.
|
||
- Achiral seam (always works either way): breathe air, drink water, mine ore, burn/build with native biomass. Only eat/metabolize/medicate/infect/chirally-poison are gated.
|
||
- ~50/50 Compatible:Mirror is a DESIGN TARGET across canon-silent worlds, not a per-world draw.
|
||
|
||
WORKSTREAMS
|
||
1. CHIRALITY ASSIGNMENT (Miri). Give every inhabited body a biosphere_class by authored identity: principled default from `economic_base_primary` + `planet_class` (food/drink exporters → Compatible; dead+maintained-atmosphere → TerraformedSterile), explicit overrides where canon speaks. Locked exemplars: Arbour (GJ-338B)=Compatible; Solandar (GJ-827)=Mirror; Keid (GJ-166A)=Compatible (preserved *from exploitation* of edible alien life — the stronger conservation motive; Solandar is the Mirror-inert preserve); Oshima (GJ-79)=TerraformedSterile. Hit the ~50/50 target across the silent remainder.
|
||
2. WIKI CONTINUITY (Miri). Reconcile the entries that already gesture at native biochemistry so each is consistent with its assigned bit + the mechanism: GJ-827, GJ-524, GJ-166A, GJ-684A, GJ-197, GJ-79, GJ-124 (resolve whether Hạ Long''s "protein" is native-Compatible harvest or Earth aquaculture). Additive/explanatory, not contradictory — preserve deliberately-vague lines as intentional.
|
||
3. biosphere_class AUTHORING PATH (asset-pipeline discipline — schema + source + values together, per .claude/rules/asset-pipeline.md). Add `biosphere_class` to wiki body frontmatter (where `substrate:` already lives), a nullable `bodies.biosphere_class` column in systems-schema.sql + MIGRATION_SQL, and importer read. NOT needed for D-246; lands with this pass.
|
||
4. ALIEN-ECOLOGY VOCABULARY (Miri + Araminta) — feeds T-1084 directly. The mosaic palette is keyed on surface-class × climate-biome × biosphere-register (D-246 Palette-key). Provide the micro-habitat NAMES per biome × register: native-mirror niches get *alien* clade names (Solandar''s "five kingdoms" flavor); introduced-Earth niches get Earth names (wheatfield, orchard, pasture). Fill the fixed niche spine (canopy / understory / wet-hollow / pioneer / bare) per climate-biome (savanna gallery-copse, tundra thermokarst / lichen-heath, boreal muskeg / deadfall, …). DETERMINISM: the vocab must be fixed before T-1084 generates its first world (a later addition re-rolls affected voxels). Table size is not a perf/storage concern — author generously but to taste (~100k is headroom, not a target).
|
||
|
||
BURNELLI (stakeholder, follow-on): a food-supply demand primitive keyed on biosphere_class (Mirror + frontier → import dependency; Compatible → local-food capable). Phase-2 economy consumer; does not block this ticket.
|
||
|
||
CONSTRAINTS
|
||
- Authored input, not derivation (Arbour''s estate food must never be coin-flipped inedible).
|
||
- Semantic axes stay clade-agnostic (Forest = canopy whether oak or mega-fungus); the register skins niches, it does not change gameplay semantics.
|
||
- The mosaic geometry is chirality-blind — this work does NOT touch voxel geometry, only edibility/economy/naming/vocab.
|
||
|
||
Chirality decisions resolved (2026-07-02, with Jeroen):
|
||
- Locked exemplars: Arbour=NativeCompatible, Solandar=NativeMirror, Keid=NativeCompatible, Oshima=TerraformedSterile.
|
||
- Miri assignments accepted: GJ-524=Mirror, Freyburg(GJ-684A)=Compatible, Hạ Long(GJ-124)=Compatible (native-Compatible harvest, per her rationale).
|
||
- USER OVERRIDES: Puerto Último(GJ-197)=NativeCompatible (breadbasket identity over Miri''s balance-motivated Mirror). Edict/Sirius(GJ-244A)=Airless — keep the world harsh/frozen (deliberately-inconvenient below-grade transit capital is load-bearing canon); no climate change; below-grade sealed habitat = no open-air biosphere.
|
||
- Two-gate default rule ACCEPTED for canon-silent worlds: Gate 0 (habitability from atmosphere/hydrosphere frontmatter → Airless / TerraformedSterile / Alive), Gate 1 (Compatible vs Mirror from economic_base_primary; agriculture→Compatible near-lock, penal→Mirror, research→50/50 lever).
|
||
- NAMING: Keid''s habitable body renamed Cadwal→(pending final pick; rec Linnaeus — pairs with Solander, its student naturalist; or Beagle). Capital stays ''Vance'' (already the author tribute). Miri''s IP flag (Cadwal = Vance''s exact book title) is the driver.
|
||
- Still to APPLY: the 7 additive wiki continuity edits (Miri specified exact text), the biosphere_class frontmatter+schema+importer plumbing (workstream 3), and the Cadwal→<name> rename across wiki + the GJ166A atlas proposal.
|
||
|
||
NAMING CONFIRMED: Keid''s habitable body Cadwal → Linnaeus (the great classifier; ties to Solander/Solandar taxonomy + the ''five kingdoms''). Capital stays Vance.', 'Operationalize the D-247 native-biosphere premise. Full brief appended.
|
||
|
||
---
|
||
BRIEF (2026-07-02) — governing record: D-247 (governance/decisions/content.md); consumer: D-246 / T-1084 mosaic register.
|
||
|
||
WHAT THIS IS
|
||
D-247 established that habitable Reach worlds were alive before humans (the settlement timeline forbids terraforming from dead rock), and that an AUTHORED per-world chirality bit gates whether native life is edible. This ticket turns that canon into data + reconciled wiki + the vocabulary the mosaic needs. Owner: Miri (worldbuilding/continuity). Stakeholder: Burnelli (food-import economics). Co-maintainer for the vocab: Araminta (visual grammar, per the T-995 ObjectTag precedent).
|
||
|
||
THE MODEL (locked in D-247 — do not re-litigate, apply it):
|
||
- `biosphere_class ∈ {NativeCompatible, NativeMirror, TerraformedSterile, Airless}`. It is an AUTHORED INPUT, never seed-derived — it follows a world''s economic/cultural identity.
|
||
- Compatible ("levo") = edible; coupling *permits* an authored hazard but does not force it (most are benign gardens).
|
||
- Mirror ("dextro") = inedible but *guaranteed* inert (can''t infect/poison — safe to study).
|
||
- "Safe" ≠ "edible" — decoupled. Bio-safe is guaranteed on Mirror; food-safe is Compatible-only.
|
||
- Achiral seam (always works either way): breathe air, drink water, mine ore, burn/build with native biomass. Only eat/metabolize/medicate/infect/chirally-poison are gated.
|
||
- ~50/50 Compatible:Mirror is a DESIGN TARGET across canon-silent worlds, not a per-world draw.
|
||
|
||
WORKSTREAMS
|
||
1. CHIRALITY ASSIGNMENT (Miri). Give every inhabited body a biosphere_class by authored identity: principled default from `economic_base_primary` + `planet_class` (food/drink exporters → Compatible; dead+maintained-atmosphere → TerraformedSterile), explicit overrides where canon speaks. Locked exemplars: Arbour (GJ-338B)=Compatible; Solandar (GJ-827)=Mirror; Keid (GJ-166A)=Compatible (preserved *from exploitation* of edible alien life — the stronger conservation motive; Solandar is the Mirror-inert preserve); Oshima (GJ-79)=TerraformedSterile. Hit the ~50/50 target across the silent remainder.
|
||
2. WIKI CONTINUITY (Miri). Reconcile the entries that already gesture at native biochemistry so each is consistent with its assigned bit + the mechanism: GJ-827, GJ-524, GJ-166A, GJ-684A, GJ-197, GJ-79, GJ-124 (resolve whether Hạ Long''s "protein" is native-Compatible harvest or Earth aquaculture). Additive/explanatory, not contradictory — preserve deliberately-vague lines as intentional.
|
||
3. biosphere_class AUTHORING PATH (asset-pipeline discipline — schema + source + values together, per .claude/rules/asset-pipeline.md). Add `biosphere_class` to wiki body frontmatter (where `substrate:` already lives), a nullable `bodies.biosphere_class` column in systems-schema.sql + MIGRATION_SQL, and importer read. NOT needed for D-246; lands with this pass.
|
||
4. ALIEN-ECOLOGY VOCABULARY (Miri + Araminta) — feeds T-1084 directly. The mosaic palette is keyed on surface-class × climate-biome × biosphere-register (D-246 Palette-key). Provide the micro-habitat NAMES per biome × register: native-mirror niches get *alien* clade names (Solandar''s "five kingdoms" flavor); introduced-Earth niches get Earth names (wheatfield, orchard, pasture). Fill the fixed niche spine (canopy / understory / wet-hollow / pioneer / bare) per climate-biome (savanna gallery-copse, tundra thermokarst / lichen-heath, boreal muskeg / deadfall, …). DETERMINISM: the vocab must be fixed before T-1084 generates its first world (a later addition re-rolls affected voxels). Table size is not a perf/storage concern — author generously but to taste (~100k is headroom, not a target).
|
||
|
||
BURNELLI (stakeholder, follow-on): a food-supply demand primitive keyed on biosphere_class (Mirror + frontier → import dependency; Compatible → local-food capable). Phase-2 economy consumer; does not block this ticket.
|
||
|
||
CONSTRAINTS
|
||
- Authored input, not derivation (Arbour''s estate food must never be coin-flipped inedible).
|
||
- Semantic axes stay clade-agnostic (Forest = canopy whether oak or mega-fungus); the register skins niches, it does not change gameplay semantics.
|
||
- The mosaic geometry is chirality-blind — this work does NOT touch voxel geometry, only edibility/economy/naming/vocab.
|
||
|
||
Chirality decisions resolved (2026-07-02, with Jeroen):
|
||
- Locked exemplars: Arbour=NativeCompatible, Solandar=NativeMirror, Keid=NativeCompatible, Oshima=TerraformedSterile.
|
||
- Miri assignments accepted: GJ-524=Mirror, Freyburg(GJ-684A)=Compatible, Hạ Long(GJ-124)=Compatible (native-Compatible harvest, per her rationale).
|
||
- USER OVERRIDES: Puerto Último(GJ-197)=NativeCompatible (breadbasket identity over Miri''s balance-motivated Mirror). Edict/Sirius(GJ-244A)=Airless — keep the world harsh/frozen (deliberately-inconvenient below-grade transit capital is load-bearing canon); no climate change; below-grade sealed habitat = no open-air biosphere.
|
||
- Two-gate default rule ACCEPTED for canon-silent worlds: Gate 0 (habitability from atmosphere/hydrosphere frontmatter → Airless / TerraformedSterile / Alive), Gate 1 (Compatible vs Mirror from economic_base_primary; agriculture→Compatible near-lock, penal→Mirror, research→50/50 lever).
|
||
- NAMING: Keid''s habitable body renamed Cadwal→(pending final pick; rec Linnaeus — pairs with Solander, its student naturalist; or Beagle). Capital stays ''Vance'' (already the author tribute). Miri''s IP flag (Cadwal = Vance''s exact book title) is the driver.
|
||
- Still to APPLY: the 7 additive wiki continuity edits (Miri specified exact text), the biosphere_class frontmatter+schema+importer plumbing (workstream 3), and the Cadwal→<name> rename across wiki + the GJ166A atlas proposal.
|
||
|
||
NAMING CONFIRMED: Keid''s habitable body Cadwal → Linnaeus (the great classifier; ties to Solander/Solandar taxonomy + the ''five kingdoms''). Capital stays Vance.
|
||
|
||
PROGRESS 2026-07-03: Workstreams 1-2 DONE + committed (388168eef, branch micro-habitat-mosaic).
|
||
- Cadwal→Linnaeus rename applied (body frontmatter name + biosphere_class:NativeCompatible, GJ-166A infobox, atlas proposal, D-247 clarified). Capital stays Vance.
|
||
- 5 wiki continuity edits applied (GJ-524 Mirror, GJ-166A/Keid Compatible, GJ-684A Freyburg Compatible, GJ-124 Hạ Long Compatible, GJ-197 Puerto Último Compatible). Solandar/Oshima needed none.
|
||
REMAINING:
|
||
- Workstream 3 (biosphere_class plumbing): add nullable bodies.biosphere_class column to systems-schema.sql; teach tooling/db/wiki_sync.py import_from_wiki to read biosphere_class frontmatter + apply the two-gate DEFAULT for canon-silent bodies (Gate0 atmosphere/hydrosphere, Gate1 economic_role/economic_base); add explicit frontmatter for the 3 override bodies still needing it (Solandar=NativeMirror, GJ-524=NativeMirror [uninhabited-but-alive → default would mis-Airless it], Edict/GJ244Ad=Airless [standard-atm+ice edge case]); ensure generate_wiki round-trips biosphere_class; then the BAKE (run import_from_wiki + generate_wiki → systems.db + regenerated infoboxes, incl. the Linnaeus name propagation) + commit systems.db. Add biosphere_class to BodyParams read set (D-240) as the D-247 code hook. NOTE: the bake is a systems.db binary-artifact commit — consequential, do deliberately.
|
||
- Workstream 4 (alien-ecology vocab → palette): integrate Miri''s biome × register vocabulary (cane/vane/wrack/husk/drum-root native-mirror lexicon + Earth-register names, per her Deliverable 3) into atlas/mosaic.rs + mosaic_constants.toml — extends the temperate/native baseline to the full surface-class × climate-biome × register palette. This also completes T-1084''s biome-awareness. Determinism: lock before generation.
|
||
Miri''s full Deliverable 3 vocab (the source for workstream 4) is in her T-1085 agent report.', NULL, '2026-07-03 20:40:15', '2026-07-03 20:40:15.305', '2026-07-03 20:40:15.305', NULL, 'fa34e073db0be60d59ec01ebd7a5e5f4', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ91R8RV38BJXGB2V55FP3B8', 'description', 'Operationalize the D-247 native-biosphere premise. Full brief appended.
|
||
|
||
---
|
||
BRIEF (2026-07-02) — governing record: D-247 (governance/decisions/content.md); consumer: D-246 / T-1084 mosaic register.
|
||
|
||
WHAT THIS IS
|
||
D-247 established that habitable Reach worlds were alive before humans (the settlement timeline forbids terraforming from dead rock), and that an AUTHORED per-world chirality bit gates whether native life is edible. This ticket turns that canon into data + reconciled wiki + the vocabulary the mosaic needs. Owner: Miri (worldbuilding/continuity). Stakeholder: Burnelli (food-import economics). Co-maintainer for the vocab: Araminta (visual grammar, per the T-995 ObjectTag precedent).
|
||
|
||
THE MODEL (locked in D-247 — do not re-litigate, apply it):
|
||
- `biosphere_class ∈ {NativeCompatible, NativeMirror, TerraformedSterile, Airless}`. It is an AUTHORED INPUT, never seed-derived — it follows a world''s economic/cultural identity.
|
||
- Compatible ("levo") = edible; coupling *permits* an authored hazard but does not force it (most are benign gardens).
|
||
- Mirror ("dextro") = inedible but *guaranteed* inert (can''t infect/poison — safe to study).
|
||
- "Safe" ≠ "edible" — decoupled. Bio-safe is guaranteed on Mirror; food-safe is Compatible-only.
|
||
- Achiral seam (always works either way): breathe air, drink water, mine ore, burn/build with native biomass. Only eat/metabolize/medicate/infect/chirally-poison are gated.
|
||
- ~50/50 Compatible:Mirror is a DESIGN TARGET across canon-silent worlds, not a per-world draw.
|
||
|
||
WORKSTREAMS
|
||
1. CHIRALITY ASSIGNMENT (Miri). Give every inhabited body a biosphere_class by authored identity: principled default from `economic_base_primary` + `planet_class` (food/drink exporters → Compatible; dead+maintained-atmosphere → TerraformedSterile), explicit overrides where canon speaks. Locked exemplars: Arbour (GJ-338B)=Compatible; Solandar (GJ-827)=Mirror; Keid (GJ-166A)=Compatible (preserved *from exploitation* of edible alien life — the stronger conservation motive; Solandar is the Mirror-inert preserve); Oshima (GJ-79)=TerraformedSterile. Hit the ~50/50 target across the silent remainder.
|
||
2. WIKI CONTINUITY (Miri). Reconcile the entries that already gesture at native biochemistry so each is consistent with its assigned bit + the mechanism: GJ-827, GJ-524, GJ-166A, GJ-684A, GJ-197, GJ-79, GJ-124 (resolve whether Hạ Long''s "protein" is native-Compatible harvest or Earth aquaculture). Additive/explanatory, not contradictory — preserve deliberately-vague lines as intentional.
|
||
3. biosphere_class AUTHORING PATH (asset-pipeline discipline — schema + source + values together, per .claude/rules/asset-pipeline.md). Add `biosphere_class` to wiki body frontmatter (where `substrate:` already lives), a nullable `bodies.biosphere_class` column in systems-schema.sql + MIGRATION_SQL, and importer read. NOT needed for D-246; lands with this pass.
|
||
4. ALIEN-ECOLOGY VOCABULARY (Miri + Araminta) — feeds T-1084 directly. The mosaic palette is keyed on surface-class × climate-biome × biosphere-register (D-246 Palette-key). Provide the micro-habitat NAMES per biome × register: native-mirror niches get *alien* clade names (Solandar''s "five kingdoms" flavor); introduced-Earth niches get Earth names (wheatfield, orchard, pasture). Fill the fixed niche spine (canopy / understory / wet-hollow / pioneer / bare) per climate-biome (savanna gallery-copse, tundra thermokarst / lichen-heath, boreal muskeg / deadfall, …). DETERMINISM: the vocab must be fixed before T-1084 generates its first world (a later addition re-rolls affected voxels). Table size is not a perf/storage concern — author generously but to taste (~100k is headroom, not a target).
|
||
|
||
BURNELLI (stakeholder, follow-on): a food-supply demand primitive keyed on biosphere_class (Mirror + frontier → import dependency; Compatible → local-food capable). Phase-2 economy consumer; does not block this ticket.
|
||
|
||
CONSTRAINTS
|
||
- Authored input, not derivation (Arbour''s estate food must never be coin-flipped inedible).
|
||
- Semantic axes stay clade-agnostic (Forest = canopy whether oak or mega-fungus); the register skins niches, it does not change gameplay semantics.
|
||
- The mosaic geometry is chirality-blind — this work does NOT touch voxel geometry, only edibility/economy/naming/vocab.
|
||
|
||
Chirality decisions resolved (2026-07-02, with Jeroen):
|
||
- Locked exemplars: Arbour=NativeCompatible, Solandar=NativeMirror, Keid=NativeCompatible, Oshima=TerraformedSterile.
|
||
- Miri assignments accepted: GJ-524=Mirror, Freyburg(GJ-684A)=Compatible, Hạ Long(GJ-124)=Compatible (native-Compatible harvest, per her rationale).
|
||
- USER OVERRIDES: Puerto Último(GJ-197)=NativeCompatible (breadbasket identity over Miri''s balance-motivated Mirror). Edict/Sirius(GJ-244A)=Airless — keep the world harsh/frozen (deliberately-inconvenient below-grade transit capital is load-bearing canon); no climate change; below-grade sealed habitat = no open-air biosphere.
|
||
- Two-gate default rule ACCEPTED for canon-silent worlds: Gate 0 (habitability from atmosphere/hydrosphere frontmatter → Airless / TerraformedSterile / Alive), Gate 1 (Compatible vs Mirror from economic_base_primary; agriculture→Compatible near-lock, penal→Mirror, research→50/50 lever).
|
||
- NAMING: Keid''s habitable body renamed Cadwal→(pending final pick; rec Linnaeus — pairs with Solander, its student naturalist; or Beagle). Capital stays ''Vance'' (already the author tribute). Miri''s IP flag (Cadwal = Vance''s exact book title) is the driver.
|
||
- Still to APPLY: the 7 additive wiki continuity edits (Miri specified exact text), the biosphere_class frontmatter+schema+importer plumbing (workstream 3), and the Cadwal→<name> rename across wiki + the GJ166A atlas proposal.
|
||
|
||
NAMING CONFIRMED: Keid''s habitable body Cadwal → Linnaeus (the great classifier; ties to Solander/Solandar taxonomy + the ''five kingdoms''). Capital stays Vance.
|
||
|
||
PROGRESS 2026-07-03: Workstreams 1-2 DONE + committed (388168eef, branch micro-habitat-mosaic).
|
||
- Cadwal→Linnaeus rename applied (body frontmatter name + biosphere_class:NativeCompatible, GJ-166A infobox, atlas proposal, D-247 clarified). Capital stays Vance.
|
||
- 5 wiki continuity edits applied (GJ-524 Mirror, GJ-166A/Keid Compatible, GJ-684A Freyburg Compatible, GJ-124 Hạ Long Compatible, GJ-197 Puerto Último Compatible). Solandar/Oshima needed none.
|
||
REMAINING:
|
||
- Workstream 3 (biosphere_class plumbing): add nullable bodies.biosphere_class column to systems-schema.sql; teach tooling/db/wiki_sync.py import_from_wiki to read biosphere_class frontmatter + apply the two-gate DEFAULT for canon-silent bodies (Gate0 atmosphere/hydrosphere, Gate1 economic_role/economic_base); add explicit frontmatter for the 3 override bodies still needing it (Solandar=NativeMirror, GJ-524=NativeMirror [uninhabited-but-alive → default would mis-Airless it], Edict/GJ244Ad=Airless [standard-atm+ice edge case]); ensure generate_wiki round-trips biosphere_class; then the BAKE (run import_from_wiki + generate_wiki → systems.db + regenerated infoboxes, incl. the Linnaeus name propagation) + commit systems.db. Add biosphere_class to BodyParams read set (D-240) as the D-247 code hook. NOTE: the bake is a systems.db binary-artifact commit — consequential, do deliberately.
|
||
- Workstream 4 (alien-ecology vocab → palette): integrate Miri''s biome × register vocabulary (cane/vane/wrack/husk/drum-root native-mirror lexicon + Earth-register names, per her Deliverable 3) into atlas/mosaic.rs + mosaic_constants.toml — extends the temperate/native baseline to the full surface-class × climate-biome × register palette. This also completes T-1084''s biome-awareness. Determinism: lock before generation.
|
||
Miri''s full Deliverable 3 vocab (the source for workstream 4) is in her T-1085 agent report.', 'Operationalize the D-247 native-biosphere premise. Full brief appended.
|
||
|
||
---
|
||
BRIEF (2026-07-02) — governing record: D-247 (governance/decisions/content.md); consumer: D-246 / T-1084 mosaic register.
|
||
|
||
WHAT THIS IS
|
||
D-247 established that habitable Reach worlds were alive before humans (the settlement timeline forbids terraforming from dead rock), and that an AUTHORED per-world chirality bit gates whether native life is edible. This ticket turns that canon into data + reconciled wiki + the vocabulary the mosaic needs. Owner: Miri (worldbuilding/continuity). Stakeholder: Burnelli (food-import economics). Co-maintainer for the vocab: Araminta (visual grammar, per the T-995 ObjectTag precedent).
|
||
|
||
THE MODEL (locked in D-247 — do not re-litigate, apply it):
|
||
- `biosphere_class ∈ {NativeCompatible, NativeMirror, TerraformedSterile, Airless}`. It is an AUTHORED INPUT, never seed-derived — it follows a world''s economic/cultural identity.
|
||
- Compatible ("levo") = edible; coupling *permits* an authored hazard but does not force it (most are benign gardens).
|
||
- Mirror ("dextro") = inedible but *guaranteed* inert (can''t infect/poison — safe to study).
|
||
- "Safe" ≠ "edible" — decoupled. Bio-safe is guaranteed on Mirror; food-safe is Compatible-only.
|
||
- Achiral seam (always works either way): breathe air, drink water, mine ore, burn/build with native biomass. Only eat/metabolize/medicate/infect/chirally-poison are gated.
|
||
- ~50/50 Compatible:Mirror is a DESIGN TARGET across canon-silent worlds, not a per-world draw.
|
||
|
||
WORKSTREAMS
|
||
1. CHIRALITY ASSIGNMENT (Miri). Give every inhabited body a biosphere_class by authored identity: principled default from `economic_base_primary` + `planet_class` (food/drink exporters → Compatible; dead+maintained-atmosphere → TerraformedSterile), explicit overrides where canon speaks. Locked exemplars: Arbour (GJ-338B)=Compatible; Solandar (GJ-827)=Mirror; Keid (GJ-166A)=Compatible (preserved *from exploitation* of edible alien life — the stronger conservation motive; Solandar is the Mirror-inert preserve); Oshima (GJ-79)=TerraformedSterile. Hit the ~50/50 target across the silent remainder.
|
||
2. WIKI CONTINUITY (Miri). Reconcile the entries that already gesture at native biochemistry so each is consistent with its assigned bit + the mechanism: GJ-827, GJ-524, GJ-166A, GJ-684A, GJ-197, GJ-79, GJ-124 (resolve whether Hạ Long''s "protein" is native-Compatible harvest or Earth aquaculture). Additive/explanatory, not contradictory — preserve deliberately-vague lines as intentional.
|
||
3. biosphere_class AUTHORING PATH (asset-pipeline discipline — schema + source + values together, per .claude/rules/asset-pipeline.md). Add `biosphere_class` to wiki body frontmatter (where `substrate:` already lives), a nullable `bodies.biosphere_class` column in systems-schema.sql + MIGRATION_SQL, and importer read. NOT needed for D-246; lands with this pass.
|
||
4. ALIEN-ECOLOGY VOCABULARY (Miri + Araminta) — feeds T-1084 directly. The mosaic palette is keyed on surface-class × climate-biome × biosphere-register (D-246 Palette-key). Provide the micro-habitat NAMES per biome × register: native-mirror niches get *alien* clade names (Solandar''s "five kingdoms" flavor); introduced-Earth niches get Earth names (wheatfield, orchard, pasture). Fill the fixed niche spine (canopy / understory / wet-hollow / pioneer / bare) per climate-biome (savanna gallery-copse, tundra thermokarst / lichen-heath, boreal muskeg / deadfall, …). DETERMINISM: the vocab must be fixed before T-1084 generates its first world (a later addition re-rolls affected voxels). Table size is not a perf/storage concern — author generously but to taste (~100k is headroom, not a target).
|
||
|
||
BURNELLI (stakeholder, follow-on): a food-supply demand primitive keyed on biosphere_class (Mirror + frontier → import dependency; Compatible → local-food capable). Phase-2 economy consumer; does not block this ticket.
|
||
|
||
CONSTRAINTS
|
||
- Authored input, not derivation (Arbour''s estate food must never be coin-flipped inedible).
|
||
- Semantic axes stay clade-agnostic (Forest = canopy whether oak or mega-fungus); the register skins niches, it does not change gameplay semantics.
|
||
- The mosaic geometry is chirality-blind — this work does NOT touch voxel geometry, only edibility/economy/naming/vocab.
|
||
|
||
Chirality decisions resolved (2026-07-02, with Jeroen):
|
||
- Locked exemplars: Arbour=NativeCompatible, Solandar=NativeMirror, Keid=NativeCompatible, Oshima=TerraformedSterile.
|
||
- Miri assignments accepted: GJ-524=Mirror, Freyburg(GJ-684A)=Compatible, Hạ Long(GJ-124)=Compatible (native-Compatible harvest, per her rationale).
|
||
- USER OVERRIDES: Puerto Último(GJ-197)=NativeCompatible (breadbasket identity over Miri''s balance-motivated Mirror). Edict/Sirius(GJ-244A)=Airless — keep the world harsh/frozen (deliberately-inconvenient below-grade transit capital is load-bearing canon); no climate change; below-grade sealed habitat = no open-air biosphere.
|
||
- Two-gate default rule ACCEPTED for canon-silent worlds: Gate 0 (habitability from atmosphere/hydrosphere frontmatter → Airless / TerraformedSterile / Alive), Gate 1 (Compatible vs Mirror from economic_base_primary; agriculture→Compatible near-lock, penal→Mirror, research→50/50 lever).
|
||
- NAMING: Keid''s habitable body renamed Cadwal→(pending final pick; rec Linnaeus — pairs with Solander, its student naturalist; or Beagle). Capital stays ''Vance'' (already the author tribute). Miri''s IP flag (Cadwal = Vance''s exact book title) is the driver.
|
||
- Still to APPLY: the 7 additive wiki continuity edits (Miri specified exact text), the biosphere_class frontmatter+schema+importer plumbing (workstream 3), and the Cadwal→<name> rename across wiki + the GJ166A atlas proposal.
|
||
|
||
NAMING CONFIRMED: Keid''s habitable body Cadwal → Linnaeus (the great classifier; ties to Solander/Solandar taxonomy + the ''five kingdoms''). Capital stays Vance.
|
||
|
||
PROGRESS 2026-07-03: Workstreams 1-2 DONE + committed (388168eef, branch micro-habitat-mosaic).
|
||
- Cadwal→Linnaeus rename applied (body frontmatter name + biosphere_class:NativeCompatible, GJ-166A infobox, atlas proposal, D-247 clarified). Capital stays Vance.
|
||
- 5 wiki continuity edits applied (GJ-524 Mirror, GJ-166A/Keid Compatible, GJ-684A Freyburg Compatible, GJ-124 Hạ Long Compatible, GJ-197 Puerto Último Compatible). Solandar/Oshima needed none.
|
||
REMAINING:
|
||
- Workstream 3 (biosphere_class plumbing): add nullable bodies.biosphere_class column to systems-schema.sql; teach tooling/db/wiki_sync.py import_from_wiki to read biosphere_class frontmatter + apply the two-gate DEFAULT for canon-silent bodies (Gate0 atmosphere/hydrosphere, Gate1 economic_role/economic_base); add explicit frontmatter for the 3 override bodies still needing it (Solandar=NativeMirror, GJ-524=NativeMirror [uninhabited-but-alive → default would mis-Airless it], Edict/GJ244Ad=Airless [standard-atm+ice edge case]); ensure generate_wiki round-trips biosphere_class; then the BAKE (run import_from_wiki + generate_wiki → systems.db + regenerated infoboxes, incl. the Linnaeus name propagation) + commit systems.db. Add biosphere_class to BodyParams read set (D-240) as the D-247 code hook. NOTE: the bake is a systems.db binary-artifact commit — consequential, do deliberately.
|
||
- Workstream 4 (alien-ecology vocab → palette): integrate Miri''s biome × register vocabulary (cane/vane/wrack/husk/drum-root native-mirror lexicon + Earth-register names, per her Deliverable 3) into atlas/mosaic.rs + mosaic_constants.toml — extends the temperate/native baseline to the full surface-class × climate-biome × register palette. This also completes T-1084''s biome-awareness. Determinism: lock before generation.
|
||
Miri''s full Deliverable 3 vocab (the source for workstream 4) is in her T-1085 agent report.
|
||
|
||
Workstream 4 DONE (partial) + committed (5fb34675e): grassland biome-awareness (ClimateBiome from temperature_c+moisture_q → savanna/temperate/boreal/tundra palettes; savanna Forest-copses, tundra lichen/sparse) + Miri''s full biome×register vocab preserved as docs/design/alien-ecology-vocabulary.md. Cold-barren districts now render structured-sparse (D-245 climate-appropriateness): vegetated_districts 8→20, 0→39 on cold bodies. Full suite green, believability golden regenerated. CONTINUATION (noted): Forest biomes (tropical/boreal), Wetland/extreme-class biomes, the introduced-Earth register (needs biosphere_class + the managed layer), and the §8 material follow-up. REMAINING on T-1085: workstream 3 (biosphere_class schema+importer+default-rule+bake) + this WS4 continuation.', NULL, '2026-07-04 18:31:00', '2026-07-04 18:31:00.300', '2026-07-04 18:31:00.300', NULL, 'ed85cfbb06787b402e2cd791d97c1156', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ91R8RV38BJXGB2V55FP3B8', 'description', 'Operationalize the D-247 native-biosphere premise. Full brief appended.
|
||
|
||
---
|
||
BRIEF (2026-07-02) — governing record: D-247 (governance/decisions/content.md); consumer: D-246 / T-1084 mosaic register.
|
||
|
||
WHAT THIS IS
|
||
D-247 established that habitable Reach worlds were alive before humans (the settlement timeline forbids terraforming from dead rock), and that an AUTHORED per-world chirality bit gates whether native life is edible. This ticket turns that canon into data + reconciled wiki + the vocabulary the mosaic needs. Owner: Miri (worldbuilding/continuity). Stakeholder: Burnelli (food-import economics). Co-maintainer for the vocab: Araminta (visual grammar, per the T-995 ObjectTag precedent).
|
||
|
||
THE MODEL (locked in D-247 — do not re-litigate, apply it):
|
||
- `biosphere_class ∈ {NativeCompatible, NativeMirror, TerraformedSterile, Airless}`. It is an AUTHORED INPUT, never seed-derived — it follows a world''s economic/cultural identity.
|
||
- Compatible ("levo") = edible; coupling *permits* an authored hazard but does not force it (most are benign gardens).
|
||
- Mirror ("dextro") = inedible but *guaranteed* inert (can''t infect/poison — safe to study).
|
||
- "Safe" ≠ "edible" — decoupled. Bio-safe is guaranteed on Mirror; food-safe is Compatible-only.
|
||
- Achiral seam (always works either way): breathe air, drink water, mine ore, burn/build with native biomass. Only eat/metabolize/medicate/infect/chirally-poison are gated.
|
||
- ~50/50 Compatible:Mirror is a DESIGN TARGET across canon-silent worlds, not a per-world draw.
|
||
|
||
WORKSTREAMS
|
||
1. CHIRALITY ASSIGNMENT (Miri). Give every inhabited body a biosphere_class by authored identity: principled default from `economic_base_primary` + `planet_class` (food/drink exporters → Compatible; dead+maintained-atmosphere → TerraformedSterile), explicit overrides where canon speaks. Locked exemplars: Arbour (GJ-338B)=Compatible; Solandar (GJ-827)=Mirror; Keid (GJ-166A)=Compatible (preserved *from exploitation* of edible alien life — the stronger conservation motive; Solandar is the Mirror-inert preserve); Oshima (GJ-79)=TerraformedSterile. Hit the ~50/50 target across the silent remainder.
|
||
2. WIKI CONTINUITY (Miri). Reconcile the entries that already gesture at native biochemistry so each is consistent with its assigned bit + the mechanism: GJ-827, GJ-524, GJ-166A, GJ-684A, GJ-197, GJ-79, GJ-124 (resolve whether Hạ Long''s "protein" is native-Compatible harvest or Earth aquaculture). Additive/explanatory, not contradictory — preserve deliberately-vague lines as intentional.
|
||
3. biosphere_class AUTHORING PATH (asset-pipeline discipline — schema + source + values together, per .claude/rules/asset-pipeline.md). Add `biosphere_class` to wiki body frontmatter (where `substrate:` already lives), a nullable `bodies.biosphere_class` column in systems-schema.sql + MIGRATION_SQL, and importer read. NOT needed for D-246; lands with this pass.
|
||
4. ALIEN-ECOLOGY VOCABULARY (Miri + Araminta) — feeds T-1084 directly. The mosaic palette is keyed on surface-class × climate-biome × biosphere-register (D-246 Palette-key). Provide the micro-habitat NAMES per biome × register: native-mirror niches get *alien* clade names (Solandar''s "five kingdoms" flavor); introduced-Earth niches get Earth names (wheatfield, orchard, pasture). Fill the fixed niche spine (canopy / understory / wet-hollow / pioneer / bare) per climate-biome (savanna gallery-copse, tundra thermokarst / lichen-heath, boreal muskeg / deadfall, …). DETERMINISM: the vocab must be fixed before T-1084 generates its first world (a later addition re-rolls affected voxels). Table size is not a perf/storage concern — author generously but to taste (~100k is headroom, not a target).
|
||
|
||
BURNELLI (stakeholder, follow-on): a food-supply demand primitive keyed on biosphere_class (Mirror + frontier → import dependency; Compatible → local-food capable). Phase-2 economy consumer; does not block this ticket.
|
||
|
||
CONSTRAINTS
|
||
- Authored input, not derivation (Arbour''s estate food must never be coin-flipped inedible).
|
||
- Semantic axes stay clade-agnostic (Forest = canopy whether oak or mega-fungus); the register skins niches, it does not change gameplay semantics.
|
||
- The mosaic geometry is chirality-blind — this work does NOT touch voxel geometry, only edibility/economy/naming/vocab.
|
||
|
||
Chirality decisions resolved (2026-07-02, with Jeroen):
|
||
- Locked exemplars: Arbour=NativeCompatible, Solandar=NativeMirror, Keid=NativeCompatible, Oshima=TerraformedSterile.
|
||
- Miri assignments accepted: GJ-524=Mirror, Freyburg(GJ-684A)=Compatible, Hạ Long(GJ-124)=Compatible (native-Compatible harvest, per her rationale).
|
||
- USER OVERRIDES: Puerto Último(GJ-197)=NativeCompatible (breadbasket identity over Miri''s balance-motivated Mirror). Edict/Sirius(GJ-244A)=Airless — keep the world harsh/frozen (deliberately-inconvenient below-grade transit capital is load-bearing canon); no climate change; below-grade sealed habitat = no open-air biosphere.
|
||
- Two-gate default rule ACCEPTED for canon-silent worlds: Gate 0 (habitability from atmosphere/hydrosphere frontmatter → Airless / TerraformedSterile / Alive), Gate 1 (Compatible vs Mirror from economic_base_primary; agriculture→Compatible near-lock, penal→Mirror, research→50/50 lever).
|
||
- NAMING: Keid''s habitable body renamed Cadwal→(pending final pick; rec Linnaeus — pairs with Solander, its student naturalist; or Beagle). Capital stays ''Vance'' (already the author tribute). Miri''s IP flag (Cadwal = Vance''s exact book title) is the driver.
|
||
- Still to APPLY: the 7 additive wiki continuity edits (Miri specified exact text), the biosphere_class frontmatter+schema+importer plumbing (workstream 3), and the Cadwal→<name> rename across wiki + the GJ166A atlas proposal.
|
||
|
||
NAMING CONFIRMED: Keid''s habitable body Cadwal → Linnaeus (the great classifier; ties to Solander/Solandar taxonomy + the ''five kingdoms''). Capital stays Vance.
|
||
|
||
PROGRESS 2026-07-03: Workstreams 1-2 DONE + committed (388168eef, branch micro-habitat-mosaic).
|
||
- Cadwal→Linnaeus rename applied (body frontmatter name + biosphere_class:NativeCompatible, GJ-166A infobox, atlas proposal, D-247 clarified). Capital stays Vance.
|
||
- 5 wiki continuity edits applied (GJ-524 Mirror, GJ-166A/Keid Compatible, GJ-684A Freyburg Compatible, GJ-124 Hạ Long Compatible, GJ-197 Puerto Último Compatible). Solandar/Oshima needed none.
|
||
REMAINING:
|
||
- Workstream 3 (biosphere_class plumbing): add nullable bodies.biosphere_class column to systems-schema.sql; teach tooling/db/wiki_sync.py import_from_wiki to read biosphere_class frontmatter + apply the two-gate DEFAULT for canon-silent bodies (Gate0 atmosphere/hydrosphere, Gate1 economic_role/economic_base); add explicit frontmatter for the 3 override bodies still needing it (Solandar=NativeMirror, GJ-524=NativeMirror [uninhabited-but-alive → default would mis-Airless it], Edict/GJ244Ad=Airless [standard-atm+ice edge case]); ensure generate_wiki round-trips biosphere_class; then the BAKE (run import_from_wiki + generate_wiki → systems.db + regenerated infoboxes, incl. the Linnaeus name propagation) + commit systems.db. Add biosphere_class to BodyParams read set (D-240) as the D-247 code hook. NOTE: the bake is a systems.db binary-artifact commit — consequential, do deliberately.
|
||
- Workstream 4 (alien-ecology vocab → palette): integrate Miri''s biome × register vocabulary (cane/vane/wrack/husk/drum-root native-mirror lexicon + Earth-register names, per her Deliverable 3) into atlas/mosaic.rs + mosaic_constants.toml — extends the temperate/native baseline to the full surface-class × climate-biome × register palette. This also completes T-1084''s biome-awareness. Determinism: lock before generation.
|
||
Miri''s full Deliverable 3 vocab (the source for workstream 4) is in her T-1085 agent report.
|
||
|
||
Workstream 4 DONE (partial) + committed (5fb34675e): grassland biome-awareness (ClimateBiome from temperature_c+moisture_q → savanna/temperate/boreal/tundra palettes; savanna Forest-copses, tundra lichen/sparse) + Miri''s full biome×register vocab preserved as docs/design/alien-ecology-vocabulary.md. Cold-barren districts now render structured-sparse (D-245 climate-appropriateness): vegetated_districts 8→20, 0→39 on cold bodies. Full suite green, believability golden regenerated. CONTINUATION (noted): Forest biomes (tropical/boreal), Wetland/extreme-class biomes, the introduced-Earth register (needs biosphere_class + the managed layer), and the §8 material follow-up. REMAINING on T-1085: workstream 3 (biosphere_class schema+importer+default-rule+bake) + this WS4 continuation.', 'Operationalize the D-247 native-biosphere premise. Full brief appended.
|
||
|
||
---
|
||
BRIEF (2026-07-02) — governing record: D-247 (governance/decisions/content.md); consumer: D-246 / T-1084 mosaic register.
|
||
|
||
WHAT THIS IS
|
||
D-247 established that habitable Reach worlds were alive before humans (the settlement timeline forbids terraforming from dead rock), and that an AUTHORED per-world chirality bit gates whether native life is edible. This ticket turns that canon into data + reconciled wiki + the vocabulary the mosaic needs. Owner: Miri (worldbuilding/continuity). Stakeholder: Burnelli (food-import economics). Co-maintainer for the vocab: Araminta (visual grammar, per the T-995 ObjectTag precedent).
|
||
|
||
THE MODEL (locked in D-247 — do not re-litigate, apply it):
|
||
- `biosphere_class ∈ {NativeCompatible, NativeMirror, TerraformedSterile, Airless}`. It is an AUTHORED INPUT, never seed-derived — it follows a world''s economic/cultural identity.
|
||
- Compatible ("levo") = edible; coupling *permits* an authored hazard but does not force it (most are benign gardens).
|
||
- Mirror ("dextro") = inedible but *guaranteed* inert (can''t infect/poison — safe to study).
|
||
- "Safe" ≠ "edible" — decoupled. Bio-safe is guaranteed on Mirror; food-safe is Compatible-only.
|
||
- Achiral seam (always works either way): breathe air, drink water, mine ore, burn/build with native biomass. Only eat/metabolize/medicate/infect/chirally-poison are gated.
|
||
- ~50/50 Compatible:Mirror is a DESIGN TARGET across canon-silent worlds, not a per-world draw.
|
||
|
||
WORKSTREAMS
|
||
1. CHIRALITY ASSIGNMENT (Miri). Give every inhabited body a biosphere_class by authored identity: principled default from `economic_base_primary` + `planet_class` (food/drink exporters → Compatible; dead+maintained-atmosphere → TerraformedSterile), explicit overrides where canon speaks. Locked exemplars: Arbour (GJ-338B)=Compatible; Solandar (GJ-827)=Mirror; Keid (GJ-166A)=Compatible (preserved *from exploitation* of edible alien life — the stronger conservation motive; Solandar is the Mirror-inert preserve); Oshima (GJ-79)=TerraformedSterile. Hit the ~50/50 target across the silent remainder.
|
||
2. WIKI CONTINUITY (Miri). Reconcile the entries that already gesture at native biochemistry so each is consistent with its assigned bit + the mechanism: GJ-827, GJ-524, GJ-166A, GJ-684A, GJ-197, GJ-79, GJ-124 (resolve whether Hạ Long''s "protein" is native-Compatible harvest or Earth aquaculture). Additive/explanatory, not contradictory — preserve deliberately-vague lines as intentional.
|
||
3. biosphere_class AUTHORING PATH (asset-pipeline discipline — schema + source + values together, per .claude/rules/asset-pipeline.md). Add `biosphere_class` to wiki body frontmatter (where `substrate:` already lives), a nullable `bodies.biosphere_class` column in systems-schema.sql + MIGRATION_SQL, and importer read. NOT needed for D-246; lands with this pass.
|
||
4. ALIEN-ECOLOGY VOCABULARY (Miri + Araminta) — feeds T-1084 directly. The mosaic palette is keyed on surface-class × climate-biome × biosphere-register (D-246 Palette-key). Provide the micro-habitat NAMES per biome × register: native-mirror niches get *alien* clade names (Solandar''s "five kingdoms" flavor); introduced-Earth niches get Earth names (wheatfield, orchard, pasture). Fill the fixed niche spine (canopy / understory / wet-hollow / pioneer / bare) per climate-biome (savanna gallery-copse, tundra thermokarst / lichen-heath, boreal muskeg / deadfall, …). DETERMINISM: the vocab must be fixed before T-1084 generates its first world (a later addition re-rolls affected voxels). Table size is not a perf/storage concern — author generously but to taste (~100k is headroom, not a target).
|
||
|
||
BURNELLI (stakeholder, follow-on): a food-supply demand primitive keyed on biosphere_class (Mirror + frontier → import dependency; Compatible → local-food capable). Phase-2 economy consumer; does not block this ticket.
|
||
|
||
CONSTRAINTS
|
||
- Authored input, not derivation (Arbour''s estate food must never be coin-flipped inedible).
|
||
- Semantic axes stay clade-agnostic (Forest = canopy whether oak or mega-fungus); the register skins niches, it does not change gameplay semantics.
|
||
- The mosaic geometry is chirality-blind — this work does NOT touch voxel geometry, only edibility/economy/naming/vocab.
|
||
|
||
Chirality decisions resolved (2026-07-02, with Jeroen):
|
||
- Locked exemplars: Arbour=NativeCompatible, Solandar=NativeMirror, Keid=NativeCompatible, Oshima=TerraformedSterile.
|
||
- Miri assignments accepted: GJ-524=Mirror, Freyburg(GJ-684A)=Compatible, Hạ Long(GJ-124)=Compatible (native-Compatible harvest, per her rationale).
|
||
- USER OVERRIDES: Puerto Último(GJ-197)=NativeCompatible (breadbasket identity over Miri''s balance-motivated Mirror). Edict/Sirius(GJ-244A)=Airless — keep the world harsh/frozen (deliberately-inconvenient below-grade transit capital is load-bearing canon); no climate change; below-grade sealed habitat = no open-air biosphere.
|
||
- Two-gate default rule ACCEPTED for canon-silent worlds: Gate 0 (habitability from atmosphere/hydrosphere frontmatter → Airless / TerraformedSterile / Alive), Gate 1 (Compatible vs Mirror from economic_base_primary; agriculture→Compatible near-lock, penal→Mirror, research→50/50 lever).
|
||
- NAMING: Keid''s habitable body renamed Cadwal→(pending final pick; rec Linnaeus — pairs with Solander, its student naturalist; or Beagle). Capital stays ''Vance'' (already the author tribute). Miri''s IP flag (Cadwal = Vance''s exact book title) is the driver.
|
||
- Still to APPLY: the 7 additive wiki continuity edits (Miri specified exact text), the biosphere_class frontmatter+schema+importer plumbing (workstream 3), and the Cadwal→<name> rename across wiki + the GJ166A atlas proposal.
|
||
|
||
NAMING CONFIRMED: Keid''s habitable body Cadwal → Linnaeus (the great classifier; ties to Solander/Solandar taxonomy + the ''five kingdoms''). Capital stays Vance.
|
||
|
||
PROGRESS 2026-07-03: Workstreams 1-2 DONE + committed (388168eef, branch micro-habitat-mosaic).
|
||
- Cadwal→Linnaeus rename applied (body frontmatter name + biosphere_class:NativeCompatible, GJ-166A infobox, atlas proposal, D-247 clarified). Capital stays Vance.
|
||
- 5 wiki continuity edits applied (GJ-524 Mirror, GJ-166A/Keid Compatible, GJ-684A Freyburg Compatible, GJ-124 Hạ Long Compatible, GJ-197 Puerto Último Compatible). Solandar/Oshima needed none.
|
||
REMAINING:
|
||
- Workstream 3 (biosphere_class plumbing): add nullable bodies.biosphere_class column to systems-schema.sql; teach tooling/db/wiki_sync.py import_from_wiki to read biosphere_class frontmatter + apply the two-gate DEFAULT for canon-silent bodies (Gate0 atmosphere/hydrosphere, Gate1 economic_role/economic_base); add explicit frontmatter for the 3 override bodies still needing it (Solandar=NativeMirror, GJ-524=NativeMirror [uninhabited-but-alive → default would mis-Airless it], Edict/GJ244Ad=Airless [standard-atm+ice edge case]); ensure generate_wiki round-trips biosphere_class; then the BAKE (run import_from_wiki + generate_wiki → systems.db + regenerated infoboxes, incl. the Linnaeus name propagation) + commit systems.db. Add biosphere_class to BodyParams read set (D-240) as the D-247 code hook. NOTE: the bake is a systems.db binary-artifact commit — consequential, do deliberately.
|
||
- Workstream 4 (alien-ecology vocab → palette): integrate Miri''s biome × register vocabulary (cane/vane/wrack/husk/drum-root native-mirror lexicon + Earth-register names, per her Deliverable 3) into atlas/mosaic.rs + mosaic_constants.toml — extends the temperate/native baseline to the full surface-class × climate-biome × register palette. This also completes T-1084''s biome-awareness. Determinism: lock before generation.
|
||
Miri''s full Deliverable 3 vocab (the source for workstream 4) is in her T-1085 agent report.
|
||
|
||
Workstream 4 DONE (partial) + committed (5fb34675e): grassland biome-awareness (ClimateBiome from temperature_c+moisture_q → savanna/temperate/boreal/tundra palettes; savanna Forest-copses, tundra lichen/sparse) + Miri''s full biome×register vocab preserved as docs/design/alien-ecology-vocabulary.md. Cold-barren districts now render structured-sparse (D-245 climate-appropriateness): vegetated_districts 8→20, 0→39 on cold bodies. Full suite green, believability golden regenerated. CONTINUATION (noted): Forest biomes (tropical/boreal), Wetland/extreme-class biomes, the introduced-Earth register (needs biosphere_class + the managed layer), and the §8 material follow-up. REMAINING on T-1085: workstream 3 (biosphere_class schema+importer+default-rule+bake) + this WS4 continuation.
|
||
|
||
Workstream 3 DONE + committed (cc7c5ada0): biosphere_class plumbing via the stamped regen-db path. Nullable bodies.biosphere_class column (schema + migration); economy_import/bodies.py populate_biosphere_class (frontmatter override + D-247 two-gate default, recompute-all); wired as import step 17; frontmatter overrides for Solandar/GJ-524/Hạ Long (the 3 whose default deviated). systems.db regenerated + stamped (make regen-db). VERIFIED: all 9 canon exemplars correct; distribution 111 Compatible : 108 Mirror among inhabited alive (~50/50), Airless for uninhabited, TerraformedSterile for thin-atm. BodyParams Rust hook deferred (no consumer yet — mosaic is chirality-blind; Burnelli economy is the future consumer).
|
||
|
||
T-1085 STATUS: WS1 (chirality assignment) DONE, WS2 (wiki continuity) DONE, WS3 (biosphere plumbing) DONE, WS4 (vocab→palette) DONE-partial (grassland biome-awareness + vocab doc; Forest/register/§8-material continuation noted). REMAINING: (a) rename completion — propagate Linnaeus to bodies.proper_name in the DB (still Cadwal; proper_name is atlas-CLI-owned, wipe+reimport would drop non-proposal cols → needs a targeted approach); (b) WS4 continuation; (c) Burnelli food-economy consumer (separate stakeholder follow-on).', NULL, '2026-07-05 09:57:14', '2026-07-05 09:57:14.888', '2026-07-05 09:57:14.888', NULL, '869fe82bcfe88a3270abefd09e0e941d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSK19FGZAC3H25VRAV4JRFW', 'status', 'in_progress', 'review', NULL, '2026-07-05 11:04:20', '2026-07-05 11:04:20.117', '2026-07-05 11:04:20.117', NULL, 'a7164036d1b3711d22d912020fc4dde9', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ91R8RV38BJXGB2V55FP3B8', 'status', 'in_progress', 'review', NULL, '2026-07-05 11:04:20', '2026-07-05 11:04:20.119', '2026-07-05 11:04:20.119', NULL, '75373d6899b3793b3b8a33526ad01d48', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ91R8RV38BJXGB2V55FP3B8', 'description', 'Operationalize the D-247 native-biosphere premise. Full brief appended.
|
||
|
||
---
|
||
BRIEF (2026-07-02) — governing record: D-247 (governance/decisions/content.md); consumer: D-246 / T-1084 mosaic register.
|
||
|
||
WHAT THIS IS
|
||
D-247 established that habitable Reach worlds were alive before humans (the settlement timeline forbids terraforming from dead rock), and that an AUTHORED per-world chirality bit gates whether native life is edible. This ticket turns that canon into data + reconciled wiki + the vocabulary the mosaic needs. Owner: Miri (worldbuilding/continuity). Stakeholder: Burnelli (food-import economics). Co-maintainer for the vocab: Araminta (visual grammar, per the T-995 ObjectTag precedent).
|
||
|
||
THE MODEL (locked in D-247 — do not re-litigate, apply it):
|
||
- `biosphere_class ∈ {NativeCompatible, NativeMirror, TerraformedSterile, Airless}`. It is an AUTHORED INPUT, never seed-derived — it follows a world''s economic/cultural identity.
|
||
- Compatible ("levo") = edible; coupling *permits* an authored hazard but does not force it (most are benign gardens).
|
||
- Mirror ("dextro") = inedible but *guaranteed* inert (can''t infect/poison — safe to study).
|
||
- "Safe" ≠ "edible" — decoupled. Bio-safe is guaranteed on Mirror; food-safe is Compatible-only.
|
||
- Achiral seam (always works either way): breathe air, drink water, mine ore, burn/build with native biomass. Only eat/metabolize/medicate/infect/chirally-poison are gated.
|
||
- ~50/50 Compatible:Mirror is a DESIGN TARGET across canon-silent worlds, not a per-world draw.
|
||
|
||
WORKSTREAMS
|
||
1. CHIRALITY ASSIGNMENT (Miri). Give every inhabited body a biosphere_class by authored identity: principled default from `economic_base_primary` + `planet_class` (food/drink exporters → Compatible; dead+maintained-atmosphere → TerraformedSterile), explicit overrides where canon speaks. Locked exemplars: Arbour (GJ-338B)=Compatible; Solandar (GJ-827)=Mirror; Keid (GJ-166A)=Compatible (preserved *from exploitation* of edible alien life — the stronger conservation motive; Solandar is the Mirror-inert preserve); Oshima (GJ-79)=TerraformedSterile. Hit the ~50/50 target across the silent remainder.
|
||
2. WIKI CONTINUITY (Miri). Reconcile the entries that already gesture at native biochemistry so each is consistent with its assigned bit + the mechanism: GJ-827, GJ-524, GJ-166A, GJ-684A, GJ-197, GJ-79, GJ-124 (resolve whether Hạ Long''s "protein" is native-Compatible harvest or Earth aquaculture). Additive/explanatory, not contradictory — preserve deliberately-vague lines as intentional.
|
||
3. biosphere_class AUTHORING PATH (asset-pipeline discipline — schema + source + values together, per .claude/rules/asset-pipeline.md). Add `biosphere_class` to wiki body frontmatter (where `substrate:` already lives), a nullable `bodies.biosphere_class` column in systems-schema.sql + MIGRATION_SQL, and importer read. NOT needed for D-246; lands with this pass.
|
||
4. ALIEN-ECOLOGY VOCABULARY (Miri + Araminta) — feeds T-1084 directly. The mosaic palette is keyed on surface-class × climate-biome × biosphere-register (D-246 Palette-key). Provide the micro-habitat NAMES per biome × register: native-mirror niches get *alien* clade names (Solandar''s "five kingdoms" flavor); introduced-Earth niches get Earth names (wheatfield, orchard, pasture). Fill the fixed niche spine (canopy / understory / wet-hollow / pioneer / bare) per climate-biome (savanna gallery-copse, tundra thermokarst / lichen-heath, boreal muskeg / deadfall, …). DETERMINISM: the vocab must be fixed before T-1084 generates its first world (a later addition re-rolls affected voxels). Table size is not a perf/storage concern — author generously but to taste (~100k is headroom, not a target).
|
||
|
||
BURNELLI (stakeholder, follow-on): a food-supply demand primitive keyed on biosphere_class (Mirror + frontier → import dependency; Compatible → local-food capable). Phase-2 economy consumer; does not block this ticket.
|
||
|
||
CONSTRAINTS
|
||
- Authored input, not derivation (Arbour''s estate food must never be coin-flipped inedible).
|
||
- Semantic axes stay clade-agnostic (Forest = canopy whether oak or mega-fungus); the register skins niches, it does not change gameplay semantics.
|
||
- The mosaic geometry is chirality-blind — this work does NOT touch voxel geometry, only edibility/economy/naming/vocab.
|
||
|
||
Chirality decisions resolved (2026-07-02, with Jeroen):
|
||
- Locked exemplars: Arbour=NativeCompatible, Solandar=NativeMirror, Keid=NativeCompatible, Oshima=TerraformedSterile.
|
||
- Miri assignments accepted: GJ-524=Mirror, Freyburg(GJ-684A)=Compatible, Hạ Long(GJ-124)=Compatible (native-Compatible harvest, per her rationale).
|
||
- USER OVERRIDES: Puerto Último(GJ-197)=NativeCompatible (breadbasket identity over Miri''s balance-motivated Mirror). Edict/Sirius(GJ-244A)=Airless — keep the world harsh/frozen (deliberately-inconvenient below-grade transit capital is load-bearing canon); no climate change; below-grade sealed habitat = no open-air biosphere.
|
||
- Two-gate default rule ACCEPTED for canon-silent worlds: Gate 0 (habitability from atmosphere/hydrosphere frontmatter → Airless / TerraformedSterile / Alive), Gate 1 (Compatible vs Mirror from economic_base_primary; agriculture→Compatible near-lock, penal→Mirror, research→50/50 lever).
|
||
- NAMING: Keid''s habitable body renamed Cadwal→(pending final pick; rec Linnaeus — pairs with Solander, its student naturalist; or Beagle). Capital stays ''Vance'' (already the author tribute). Miri''s IP flag (Cadwal = Vance''s exact book title) is the driver.
|
||
- Still to APPLY: the 7 additive wiki continuity edits (Miri specified exact text), the biosphere_class frontmatter+schema+importer plumbing (workstream 3), and the Cadwal→<name> rename across wiki + the GJ166A atlas proposal.
|
||
|
||
NAMING CONFIRMED: Keid''s habitable body Cadwal → Linnaeus (the great classifier; ties to Solander/Solandar taxonomy + the ''five kingdoms''). Capital stays Vance.
|
||
|
||
PROGRESS 2026-07-03: Workstreams 1-2 DONE + committed (388168eef, branch micro-habitat-mosaic).
|
||
- Cadwal→Linnaeus rename applied (body frontmatter name + biosphere_class:NativeCompatible, GJ-166A infobox, atlas proposal, D-247 clarified). Capital stays Vance.
|
||
- 5 wiki continuity edits applied (GJ-524 Mirror, GJ-166A/Keid Compatible, GJ-684A Freyburg Compatible, GJ-124 Hạ Long Compatible, GJ-197 Puerto Último Compatible). Solandar/Oshima needed none.
|
||
REMAINING:
|
||
- Workstream 3 (biosphere_class plumbing): add nullable bodies.biosphere_class column to systems-schema.sql; teach tooling/db/wiki_sync.py import_from_wiki to read biosphere_class frontmatter + apply the two-gate DEFAULT for canon-silent bodies (Gate0 atmosphere/hydrosphere, Gate1 economic_role/economic_base); add explicit frontmatter for the 3 override bodies still needing it (Solandar=NativeMirror, GJ-524=NativeMirror [uninhabited-but-alive → default would mis-Airless it], Edict/GJ244Ad=Airless [standard-atm+ice edge case]); ensure generate_wiki round-trips biosphere_class; then the BAKE (run import_from_wiki + generate_wiki → systems.db + regenerated infoboxes, incl. the Linnaeus name propagation) + commit systems.db. Add biosphere_class to BodyParams read set (D-240) as the D-247 code hook. NOTE: the bake is a systems.db binary-artifact commit — consequential, do deliberately.
|
||
- Workstream 4 (alien-ecology vocab → palette): integrate Miri''s biome × register vocabulary (cane/vane/wrack/husk/drum-root native-mirror lexicon + Earth-register names, per her Deliverable 3) into atlas/mosaic.rs + mosaic_constants.toml — extends the temperate/native baseline to the full surface-class × climate-biome × register palette. This also completes T-1084''s biome-awareness. Determinism: lock before generation.
|
||
Miri''s full Deliverable 3 vocab (the source for workstream 4) is in her T-1085 agent report.
|
||
|
||
Workstream 4 DONE (partial) + committed (5fb34675e): grassland biome-awareness (ClimateBiome from temperature_c+moisture_q → savanna/temperate/boreal/tundra palettes; savanna Forest-copses, tundra lichen/sparse) + Miri''s full biome×register vocab preserved as docs/design/alien-ecology-vocabulary.md. Cold-barren districts now render structured-sparse (D-245 climate-appropriateness): vegetated_districts 8→20, 0→39 on cold bodies. Full suite green, believability golden regenerated. CONTINUATION (noted): Forest biomes (tropical/boreal), Wetland/extreme-class biomes, the introduced-Earth register (needs biosphere_class + the managed layer), and the §8 material follow-up. REMAINING on T-1085: workstream 3 (biosphere_class schema+importer+default-rule+bake) + this WS4 continuation.
|
||
|
||
Workstream 3 DONE + committed (cc7c5ada0): biosphere_class plumbing via the stamped regen-db path. Nullable bodies.biosphere_class column (schema + migration); economy_import/bodies.py populate_biosphere_class (frontmatter override + D-247 two-gate default, recompute-all); wired as import step 17; frontmatter overrides for Solandar/GJ-524/Hạ Long (the 3 whose default deviated). systems.db regenerated + stamped (make regen-db). VERIFIED: all 9 canon exemplars correct; distribution 111 Compatible : 108 Mirror among inhabited alive (~50/50), Airless for uninhabited, TerraformedSterile for thin-atm. BodyParams Rust hook deferred (no consumer yet — mosaic is chirality-blind; Burnelli economy is the future consumer).
|
||
|
||
T-1085 STATUS: WS1 (chirality assignment) DONE, WS2 (wiki continuity) DONE, WS3 (biosphere plumbing) DONE, WS4 (vocab→palette) DONE-partial (grassland biome-awareness + vocab doc; Forest/register/§8-material continuation noted). REMAINING: (a) rename completion — propagate Linnaeus to bodies.proper_name in the DB (still Cadwal; proper_name is atlas-CLI-owned, wipe+reimport would drop non-proposal cols → needs a targeted approach); (b) WS4 continuation; (c) Burnelli food-economy consumer (separate stakeholder follow-on).', 'Operationalize the D-247 native-biosphere premise. Full brief appended.
|
||
|
||
---
|
||
BRIEF (2026-07-02) — governing record: D-247 (governance/decisions/content.md); consumer: D-246 / T-1084 mosaic register.
|
||
|
||
WHAT THIS IS
|
||
D-247 established that habitable Reach worlds were alive before humans (the settlement timeline forbids terraforming from dead rock), and that an AUTHORED per-world chirality bit gates whether native life is edible. This ticket turns that canon into data + reconciled wiki + the vocabulary the mosaic needs. Owner: Miri (worldbuilding/continuity). Stakeholder: Burnelli (food-import economics). Co-maintainer for the vocab: Araminta (visual grammar, per the T-995 ObjectTag precedent).
|
||
|
||
THE MODEL (locked in D-247 — do not re-litigate, apply it):
|
||
- `biosphere_class ∈ {NativeCompatible, NativeMirror, TerraformedSterile, Airless}`. It is an AUTHORED INPUT, never seed-derived — it follows a world''s economic/cultural identity.
|
||
- Compatible ("levo") = edible; coupling *permits* an authored hazard but does not force it (most are benign gardens).
|
||
- Mirror ("dextro") = inedible but *guaranteed* inert (can''t infect/poison — safe to study).
|
||
- "Safe" ≠ "edible" — decoupled. Bio-safe is guaranteed on Mirror; food-safe is Compatible-only.
|
||
- Achiral seam (always works either way): breathe air, drink water, mine ore, burn/build with native biomass. Only eat/metabolize/medicate/infect/chirally-poison are gated.
|
||
- ~50/50 Compatible:Mirror is a DESIGN TARGET across canon-silent worlds, not a per-world draw.
|
||
|
||
WORKSTREAMS
|
||
1. CHIRALITY ASSIGNMENT (Miri). Give every inhabited body a biosphere_class by authored identity: principled default from `economic_base_primary` + `planet_class` (food/drink exporters → Compatible; dead+maintained-atmosphere → TerraformedSterile), explicit overrides where canon speaks. Locked exemplars: Arbour (GJ-338B)=Compatible; Solandar (GJ-827)=Mirror; Keid (GJ-166A)=Compatible (preserved *from exploitation* of edible alien life — the stronger conservation motive; Solandar is the Mirror-inert preserve); Oshima (GJ-79)=TerraformedSterile. Hit the ~50/50 target across the silent remainder.
|
||
2. WIKI CONTINUITY (Miri). Reconcile the entries that already gesture at native biochemistry so each is consistent with its assigned bit + the mechanism: GJ-827, GJ-524, GJ-166A, GJ-684A, GJ-197, GJ-79, GJ-124 (resolve whether Hạ Long''s "protein" is native-Compatible harvest or Earth aquaculture). Additive/explanatory, not contradictory — preserve deliberately-vague lines as intentional.
|
||
3. biosphere_class AUTHORING PATH (asset-pipeline discipline — schema + source + values together, per .claude/rules/asset-pipeline.md). Add `biosphere_class` to wiki body frontmatter (where `substrate:` already lives), a nullable `bodies.biosphere_class` column in systems-schema.sql + MIGRATION_SQL, and importer read. NOT needed for D-246; lands with this pass.
|
||
4. ALIEN-ECOLOGY VOCABULARY (Miri + Araminta) — feeds T-1084 directly. The mosaic palette is keyed on surface-class × climate-biome × biosphere-register (D-246 Palette-key). Provide the micro-habitat NAMES per biome × register: native-mirror niches get *alien* clade names (Solandar''s "five kingdoms" flavor); introduced-Earth niches get Earth names (wheatfield, orchard, pasture). Fill the fixed niche spine (canopy / understory / wet-hollow / pioneer / bare) per climate-biome (savanna gallery-copse, tundra thermokarst / lichen-heath, boreal muskeg / deadfall, …). DETERMINISM: the vocab must be fixed before T-1084 generates its first world (a later addition re-rolls affected voxels). Table size is not a perf/storage concern — author generously but to taste (~100k is headroom, not a target).
|
||
|
||
BURNELLI (stakeholder, follow-on): a food-supply demand primitive keyed on biosphere_class (Mirror + frontier → import dependency; Compatible → local-food capable). Phase-2 economy consumer; does not block this ticket.
|
||
|
||
CONSTRAINTS
|
||
- Authored input, not derivation (Arbour''s estate food must never be coin-flipped inedible).
|
||
- Semantic axes stay clade-agnostic (Forest = canopy whether oak or mega-fungus); the register skins niches, it does not change gameplay semantics.
|
||
- The mosaic geometry is chirality-blind — this work does NOT touch voxel geometry, only edibility/economy/naming/vocab.
|
||
|
||
Chirality decisions resolved (2026-07-02, with Jeroen):
|
||
- Locked exemplars: Arbour=NativeCompatible, Solandar=NativeMirror, Keid=NativeCompatible, Oshima=TerraformedSterile.
|
||
- Miri assignments accepted: GJ-524=Mirror, Freyburg(GJ-684A)=Compatible, Hạ Long(GJ-124)=Compatible (native-Compatible harvest, per her rationale).
|
||
- USER OVERRIDES: Puerto Último(GJ-197)=NativeCompatible (breadbasket identity over Miri''s balance-motivated Mirror). Edict/Sirius(GJ-244A)=Airless — keep the world harsh/frozen (deliberately-inconvenient below-grade transit capital is load-bearing canon); no climate change; below-grade sealed habitat = no open-air biosphere.
|
||
- Two-gate default rule ACCEPTED for canon-silent worlds: Gate 0 (habitability from atmosphere/hydrosphere frontmatter → Airless / TerraformedSterile / Alive), Gate 1 (Compatible vs Mirror from economic_base_primary; agriculture→Compatible near-lock, penal→Mirror, research→50/50 lever).
|
||
- NAMING: Keid''s habitable body renamed Cadwal→(pending final pick; rec Linnaeus — pairs with Solander, its student naturalist; or Beagle). Capital stays ''Vance'' (already the author tribute). Miri''s IP flag (Cadwal = Vance''s exact book title) is the driver.
|
||
- Still to APPLY: the 7 additive wiki continuity edits (Miri specified exact text), the biosphere_class frontmatter+schema+importer plumbing (workstream 3), and the Cadwal→<name> rename across wiki + the GJ166A atlas proposal.
|
||
|
||
NAMING CONFIRMED: Keid''s habitable body Cadwal → Linnaeus (the great classifier; ties to Solander/Solandar taxonomy + the ''five kingdoms''). Capital stays Vance.
|
||
|
||
PROGRESS 2026-07-03: Workstreams 1-2 DONE + committed (388168eef, branch micro-habitat-mosaic).
|
||
- Cadwal→Linnaeus rename applied (body frontmatter name + biosphere_class:NativeCompatible, GJ-166A infobox, atlas proposal, D-247 clarified). Capital stays Vance.
|
||
- 5 wiki continuity edits applied (GJ-524 Mirror, GJ-166A/Keid Compatible, GJ-684A Freyburg Compatible, GJ-124 Hạ Long Compatible, GJ-197 Puerto Último Compatible). Solandar/Oshima needed none.
|
||
REMAINING:
|
||
- Workstream 3 (biosphere_class plumbing): add nullable bodies.biosphere_class column to systems-schema.sql; teach tooling/db/wiki_sync.py import_from_wiki to read biosphere_class frontmatter + apply the two-gate DEFAULT for canon-silent bodies (Gate0 atmosphere/hydrosphere, Gate1 economic_role/economic_base); add explicit frontmatter for the 3 override bodies still needing it (Solandar=NativeMirror, GJ-524=NativeMirror [uninhabited-but-alive → default would mis-Airless it], Edict/GJ244Ad=Airless [standard-atm+ice edge case]); ensure generate_wiki round-trips biosphere_class; then the BAKE (run import_from_wiki + generate_wiki → systems.db + regenerated infoboxes, incl. the Linnaeus name propagation) + commit systems.db. Add biosphere_class to BodyParams read set (D-240) as the D-247 code hook. NOTE: the bake is a systems.db binary-artifact commit — consequential, do deliberately.
|
||
- Workstream 4 (alien-ecology vocab → palette): integrate Miri''s biome × register vocabulary (cane/vane/wrack/husk/drum-root native-mirror lexicon + Earth-register names, per her Deliverable 3) into atlas/mosaic.rs + mosaic_constants.toml — extends the temperate/native baseline to the full surface-class × climate-biome × register palette. This also completes T-1084''s biome-awareness. Determinism: lock before generation.
|
||
Miri''s full Deliverable 3 vocab (the source for workstream 4) is in her T-1085 agent report.
|
||
|
||
Workstream 4 DONE (partial) + committed (5fb34675e): grassland biome-awareness (ClimateBiome from temperature_c+moisture_q → savanna/temperate/boreal/tundra palettes; savanna Forest-copses, tundra lichen/sparse) + Miri''s full biome×register vocab preserved as docs/design/alien-ecology-vocabulary.md. Cold-barren districts now render structured-sparse (D-245 climate-appropriateness): vegetated_districts 8→20, 0→39 on cold bodies. Full suite green, believability golden regenerated. CONTINUATION (noted): Forest biomes (tropical/boreal), Wetland/extreme-class biomes, the introduced-Earth register (needs biosphere_class + the managed layer), and the §8 material follow-up. REMAINING on T-1085: workstream 3 (biosphere_class schema+importer+default-rule+bake) + this WS4 continuation.
|
||
|
||
Workstream 3 DONE + committed (cc7c5ada0): biosphere_class plumbing via the stamped regen-db path. Nullable bodies.biosphere_class column (schema + migration); economy_import/bodies.py populate_biosphere_class (frontmatter override + D-247 two-gate default, recompute-all); wired as import step 17; frontmatter overrides for Solandar/GJ-524/Hạ Long (the 3 whose default deviated). systems.db regenerated + stamped (make regen-db). VERIFIED: all 9 canon exemplars correct; distribution 111 Compatible : 108 Mirror among inhabited alive (~50/50), Airless for uninhabited, TerraformedSterile for thin-atm. BodyParams Rust hook deferred (no consumer yet — mosaic is chirality-blind; Burnelli economy is the future consumer).
|
||
|
||
T-1085 STATUS: WS1 (chirality assignment) DONE, WS2 (wiki continuity) DONE, WS3 (biosphere plumbing) DONE, WS4 (vocab→palette) DONE-partial (grassland biome-awareness + vocab doc; Forest/register/§8-material continuation noted). REMAINING: (a) rename completion — propagate Linnaeus to bodies.proper_name in the DB (still Cadwal; proper_name is atlas-CLI-owned, wipe+reimport would drop non-proposal cols → needs a targeted approach); (b) WS4 continuation; (c) Burnelli food-economy consumer (separate stakeholder follow-on).
|
||
|
||
CLOSED 2026-07-05 (PR #172 merged to main @ 895bb83ba). Core deliverable shipped: WS1 chirality assignment, WS2 wiki continuity, WS3 biosphere_class plumbing (stamped regen-db), WS4 grassland biome-awareness + vocab doc. Both blocking review findings (C1 over-vegetation, H1 biosphere gate) fixed + N1 (Wetland gate) folded in; both reviewers approved. Remaining work split into follow-ups: T-1086 (propagate Linnaeus to bodies.proper_name) and T-1087 (Forest/Wetland biome palettes + introduced-Earth register + §8 material). Burnelli food-economy consumer stays a Phase-2 stakeholder follow-on (noted, not filed — cross-phase).', NULL, '2026-07-05 17:46:33', '2026-07-05 17:46:33.511', '2026-07-05 17:46:33.511', NULL, '3cae4321f60cc166089db5d3c656ef6f', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FGSK19FGZAC3H25VRAV4JRFW', 'status', 'review', 'done', NULL, '2026-07-05 17:46:36', '2026-07-05 17:46:36.690', '2026-07-05 17:46:36.690', NULL, '75db59fc46ee90ad66e9c61eadf627ac', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ91R8RV38BJXGB2V55FP3B8', 'status', 'review', 'done', NULL, '2026-07-05 17:46:36', '2026-07-05 17:46:36.698', '2026-07-05 17:46:36.698', NULL, '09edd98de1f765ba1a946b57f54533d9', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKCER95EK266H8RWPW8XT1F0', 'description', 'Fable-5-window sidequest (sanctioned cascade exception, 2026-07-05): the presentation layer that turns discrete server tile steps into a believable walking 3D character. Scope: 3D sandbox dev scene (SR_LIVE=1, greybox tiles derived from server snapshots, no hand-authored map), CharacterVisual instantiated in-world, locomotion rig (tile-step + facing-octant interpolation, stance-aware speeds), UAL animation state machine (idle/walk/sprint/careful/crouch), D-148 camera rig (30deg low-angle follow, 45deg rotation). Server-authoritative from day one — no client-local movement model. Builds on D-148/D-149/D-244/D-066 and the T-417 stance system. If the Fable 5 window closes mid-flight, work parks here.', 'Fable-5-window sidequest (sanctioned cascade exception, 2026-07-05): the presentation layer that turns discrete server tile steps into a believable walking 3D character. Scope: 3D sandbox dev scene (SR_LIVE=1, greybox tiles derived from server snapshots, no hand-authored map), CharacterVisual instantiated in-world, locomotion rig (tile-step + facing-octant interpolation, stance-aware speeds), UAL animation state machine (idle/walk/sprint/careful/crouch), D-148 camera rig (30deg low-angle follow, 45deg rotation). Server-authoritative from day one — no client-local movement model. Builds on D-148/D-149/D-244/D-066 and the T-417 stance system. If the Fable 5 window closes mid-flight, work parks here.
|
||
|
||
Visual reference (user, 2026-07-06): Xenonauts 2 nails the target tiles/occlusion/character perspective — readable tile grid, low-angle tactical camera with angle options (matches D-148 30deg low-angle + 45deg rotation steps and the spikes/3dpipeline angle presets), and crucially its wall/roof occlusion treatment: camera-facing walls cut down/ghosted so interiors stay readable, floors peel per z-level. One deliberate difference: our camera locks to the player character (D-015/T-116) — no free map panning. Implication for the locomotion sandbox: greybox walls should prototype camera-facing cutaway occlusion early, since wall readability interacts with the locked low-angle camera.', NULL, '2026-07-06 07:10:07', '2026-07-06 07:10:07.799', '2026-07-06 07:10:07.799', NULL, '81c7180578510141745792125328712b', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKCER95EK266H8RWPW8XT1F0', 'description', 'Fable-5-window sidequest (sanctioned cascade exception, 2026-07-05): the presentation layer that turns discrete server tile steps into a believable walking 3D character. Scope: 3D sandbox dev scene (SR_LIVE=1, greybox tiles derived from server snapshots, no hand-authored map), CharacterVisual instantiated in-world, locomotion rig (tile-step + facing-octant interpolation, stance-aware speeds), UAL animation state machine (idle/walk/sprint/careful/crouch), D-148 camera rig (30deg low-angle follow, 45deg rotation). Server-authoritative from day one — no client-local movement model. Builds on D-148/D-149/D-244/D-066 and the T-417 stance system. If the Fable 5 window closes mid-flight, work parks here.
|
||
|
||
Visual reference (user, 2026-07-06): Xenonauts 2 nails the target tiles/occlusion/character perspective — readable tile grid, low-angle tactical camera with angle options (matches D-148 30deg low-angle + 45deg rotation steps and the spikes/3dpipeline angle presets), and crucially its wall/roof occlusion treatment: camera-facing walls cut down/ghosted so interiors stay readable, floors peel per z-level. One deliberate difference: our camera locks to the player character (D-015/T-116) — no free map panning. Implication for the locomotion sandbox: greybox walls should prototype camera-facing cutaway occlusion early, since wall readability interacts with the locked low-angle camera.', 'Fable-5-window sidequest (sanctioned cascade exception, 2026-07-05): the presentation layer that turns discrete server tile steps into a believable walking 3D character. Scope: 3D sandbox dev scene (SR_LIVE=1, greybox tiles derived from server snapshots, no hand-authored map), CharacterVisual instantiated in-world, locomotion rig (tile-step + facing-octant interpolation, stance-aware speeds), UAL animation state machine (idle/walk/sprint/careful/crouch), D-148 camera rig (30deg low-angle follow, 45deg rotation). Server-authoritative from day one — no client-local movement model. Builds on D-148/D-149/D-244/D-066 and the T-417 stance system. If the Fable 5 window closes mid-flight, work parks here.
|
||
|
||
Visual reference (user, 2026-07-06): Xenonauts 2 nails the target tiles/occlusion/character perspective — readable tile grid, low-angle tactical camera with angle options (matches D-148 30deg low-angle + 45deg rotation steps and the spikes/3dpipeline angle presets), and crucially its wall/roof occlusion treatment: camera-facing walls cut down/ghosted so interiors stay readable, floors peel per z-level. One deliberate difference: our camera locks to the player character (D-015/T-116) — no free map panning. Implication for the locomotion sandbox: greybox walls should prototype camera-facing cutaway occlusion early, since wall readability interacts with the locked low-angle camera.
|
||
|
||
Scoping call (user + lead agreement, 2026-07-06): wall cutaway is CLIENT-SIDE presentation, decoupled from fog-of-perception. Rationale: two occlusion systems with different subjects — perception/fog governs what the CHARACTER knows (server-enforced info boundary; client only receives observer-filtered geometry), cutaway governs what the PLAYER''S CAMERA sees (pure render mode on wall data the client already holds). They compose: cutaway cuts render height; fog overlay still gates what is visible behind. Walls remain first-class client data objects (future destruction/explosion interactions), cutaway is a render mode on them like tint/LOD. Nuance parked for Phase 5 proper: destroyed-while-unobserved walls should render in remembered state (fog-memory applied to geometry). If this holds through implementation, mint a D-record (perception domain) when the sidequest lands.', NULL, '2026-07-06 07:14:14', '2026-07-06 07:14:14.484', '2026-07-06 07:14:14.484', NULL, '307b68ca9c7b56692d32a4c7bb8fe50e', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKCPBF41RWK9PW9M22Q7961C', 'description', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.', NULL, '2026-07-06 07:39:21', '2026-07-06 07:39:21.760', '2026-07-06 07:39:21.760', NULL, '4a859683cd2d1dfe39692711789a2bb7', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKCPBF41RWK9PW9M22Q7961C', 'description', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.
|
||
|
||
Art direction (user, 2026-07-06): garments read CYBERPUNK/MODERN — near-future everyday civilian + corporate wear — NOT fantasy/medieval. The owned Fantasy pack is at most a topology donor (low-poly base shapes like pants/shirts are genre-neutral; genre lives in silhouette details, textures, trims, and accessories) — no medieval trim/textures may survive into shipped garments. Weight the authoring routes accordingly: texture identity matters as much as mesh. Canon hook: the wiki already ships a garment brand — thrds (wiki/star-systems/GJ-475/index.md, Braemar fiber cooperative, corridor fashion markets) — so branded clothing connects to Phase-1 lore, not only generated_brands.toml. This emphasis also feeds the Quaternius-pivot evaluation: commercial alternatives skew sci-fi/urban while Quaternius clothing is fantasy-only.', NULL, '2026-07-06 07:42:06', '2026-07-06 07:42:06.637', '2026-07-06 07:42:06.637', NULL, '3698f7e9fa21e699b9bf86b31d76f70d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKCPBF41RWK9PW9M22Q7961C', 'description', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.
|
||
|
||
Art direction (user, 2026-07-06): garments read CYBERPUNK/MODERN — near-future everyday civilian + corporate wear — NOT fantasy/medieval. The owned Fantasy pack is at most a topology donor (low-poly base shapes like pants/shirts are genre-neutral; genre lives in silhouette details, textures, trims, and accessories) — no medieval trim/textures may survive into shipped garments. Weight the authoring routes accordingly: texture identity matters as much as mesh. Canon hook: the wiki already ships a garment brand — thrds (wiki/star-systems/GJ-475/index.md, Braemar fiber cooperative, corridor fashion markets) — so branded clothing connects to Phase-1 lore, not only generated_brands.toml. This emphasis also feeds the Quaternius-pivot evaluation: commercial alternatives skew sci-fi/urban while Quaternius clothing is fantasy-only.', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.
|
||
|
||
Art direction (user, 2026-07-06): garments read CYBERPUNK/MODERN — near-future everyday civilian + corporate wear — NOT fantasy/medieval. The owned Fantasy pack is at most a topology donor (low-poly base shapes like pants/shirts are genre-neutral; genre lives in silhouette details, textures, trims, and accessories) — no medieval trim/textures may survive into shipped garments. Weight the authoring routes accordingly: texture identity matters as much as mesh. Canon hook: the wiki already ships a garment brand — thrds (wiki/star-systems/GJ-475/index.md, Braemar fiber cooperative, corridor fashion markets) — so branded clothing connects to Phase-1 lore, not only generated_brands.toml. This emphasis also feeds the Quaternius-pivot evaluation: commercial alternatives skew sci-fi/urban while Quaternius clothing is fantasy-only.
|
||
|
||
Nuance (user, 2026-07-06): the cyberpunk/modern direction is the DEFAULT, not a prohibition — fashion in the Reach is cyclical, so fantasy/medieval-flavored garments may appear here and there as deliberate fashion statements (subculture pieces, luxury/revival trims, statement outerwear). Supersedes the previous note''s hard ''no medieval trim may survive'' line. Practical consequence: a small number of Fantasy-pack pieces may ship near-as-is where they read as intentional fashion; the basic set itself stays modern.', NULL, '2026-07-06 07:42:24', '2026-07-06 07:42:24.025', '2026-07-06 07:42:24.025', NULL, 'a9974a42f7017c372b5f35eadac019cd', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKCPBF41RWK9PW9M22Q7961C', 'description', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.
|
||
|
||
Art direction (user, 2026-07-06): garments read CYBERPUNK/MODERN — near-future everyday civilian + corporate wear — NOT fantasy/medieval. The owned Fantasy pack is at most a topology donor (low-poly base shapes like pants/shirts are genre-neutral; genre lives in silhouette details, textures, trims, and accessories) — no medieval trim/textures may survive into shipped garments. Weight the authoring routes accordingly: texture identity matters as much as mesh. Canon hook: the wiki already ships a garment brand — thrds (wiki/star-systems/GJ-475/index.md, Braemar fiber cooperative, corridor fashion markets) — so branded clothing connects to Phase-1 lore, not only generated_brands.toml. This emphasis also feeds the Quaternius-pivot evaluation: commercial alternatives skew sci-fi/urban while Quaternius clothing is fantasy-only.
|
||
|
||
Nuance (user, 2026-07-06): the cyberpunk/modern direction is the DEFAULT, not a prohibition — fashion in the Reach is cyclical, so fantasy/medieval-flavored garments may appear here and there as deliberate fashion statements (subculture pieces, luxury/revival trims, statement outerwear). Supersedes the previous note''s hard ''no medieval trim may survive'' line. Practical consequence: a small number of Fantasy-pack pieces may ship near-as-is where they read as intentional fashion; the basic set itself stays modern.', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.
|
||
|
||
Art direction (user, 2026-07-06): garments read CYBERPUNK/MODERN — near-future everyday civilian + corporate wear — NOT fantasy/medieval. The owned Fantasy pack is at most a topology donor (low-poly base shapes like pants/shirts are genre-neutral; genre lives in silhouette details, textures, trims, and accessories) — no medieval trim/textures may survive into shipped garments. Weight the authoring routes accordingly: texture identity matters as much as mesh. Canon hook: the wiki already ships a garment brand — thrds (wiki/star-systems/GJ-475/index.md, Braemar fiber cooperative, corridor fashion markets) — so branded clothing connects to Phase-1 lore, not only generated_brands.toml. This emphasis also feeds the Quaternius-pivot evaluation: commercial alternatives skew sci-fi/urban while Quaternius clothing is fantasy-only.
|
||
|
||
Nuance (user, 2026-07-06): the cyberpunk/modern direction is the DEFAULT, not a prohibition — fashion in the Reach is cyclical, so fantasy/medieval-flavored garments may appear here and there as deliberate fashion statements (subculture pieces, luxury/revival trims, statement outerwear). Supersedes the previous note''s hard ''no medieval trim may survive'' line. Practical consequence: a small number of Fantasy-pack pieces may ship near-as-is where they read as intentional fashion; the basic set itself stays modern.
|
||
|
||
Art direction CONSOLIDATED (user, 2026-07-06 — supersedes the two notes above): the Reach has no single clothing style — ALL styles coexist, with modern/cyberpunk probably the most prevalent. Style is a prevalence DISTRIBUTION, not a genre rule, and may eventually vary by culture/settlement (fits the simulation DNA; fashion-as-cultural-data is a later phase concern, not this ticket). Consequences now: (1) the engine is style-agnostic by construction (slots/tints/logos carry no genre); (2) the basic set targets the prevalent center — modern casual + corporate — because it dresses the most NPCs and the shopping experience; (3) garments get a lightweight style tag in the manifest (e.g. style: modern|formal|fantasy|utility) as the cheap seam so per-culture distributions can be authored later without retrofitting; (4) Fantasy-pack pieces are legitimate catalogue members under their own tag, prevalence-weighted low.', NULL, '2026-07-06 07:43:12', '2026-07-06 07:43:12.193', '2026-07-06 07:43:12.193', NULL, '22061e346caf924cbf501beb836e802e', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKCPBF41RWK9PW9M22Q7961C', 'description', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.
|
||
|
||
Art direction (user, 2026-07-06): garments read CYBERPUNK/MODERN — near-future everyday civilian + corporate wear — NOT fantasy/medieval. The owned Fantasy pack is at most a topology donor (low-poly base shapes like pants/shirts are genre-neutral; genre lives in silhouette details, textures, trims, and accessories) — no medieval trim/textures may survive into shipped garments. Weight the authoring routes accordingly: texture identity matters as much as mesh. Canon hook: the wiki already ships a garment brand — thrds (wiki/star-systems/GJ-475/index.md, Braemar fiber cooperative, corridor fashion markets) — so branded clothing connects to Phase-1 lore, not only generated_brands.toml. This emphasis also feeds the Quaternius-pivot evaluation: commercial alternatives skew sci-fi/urban while Quaternius clothing is fantasy-only.
|
||
|
||
Nuance (user, 2026-07-06): the cyberpunk/modern direction is the DEFAULT, not a prohibition — fashion in the Reach is cyclical, so fantasy/medieval-flavored garments may appear here and there as deliberate fashion statements (subculture pieces, luxury/revival trims, statement outerwear). Supersedes the previous note''s hard ''no medieval trim may survive'' line. Practical consequence: a small number of Fantasy-pack pieces may ship near-as-is where they read as intentional fashion; the basic set itself stays modern.
|
||
|
||
Art direction CONSOLIDATED (user, 2026-07-06 — supersedes the two notes above): the Reach has no single clothing style — ALL styles coexist, with modern/cyberpunk probably the most prevalent. Style is a prevalence DISTRIBUTION, not a genre rule, and may eventually vary by culture/settlement (fits the simulation DNA; fashion-as-cultural-data is a later phase concern, not this ticket). Consequences now: (1) the engine is style-agnostic by construction (slots/tints/logos carry no genre); (2) the basic set targets the prevalent center — modern casual + corporate — because it dresses the most NPCs and the shopping experience; (3) garments get a lightweight style tag in the manifest (e.g. style: modern|formal|fantasy|utility) as the cheap seam so per-culture distributions can be authored later without retrofitting; (4) Fantasy-pack pieces are legitimate catalogue members under their own tag, prevalence-weighted low.', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.
|
||
|
||
Art direction (user, 2026-07-06): garments read CYBERPUNK/MODERN — near-future everyday civilian + corporate wear — NOT fantasy/medieval. The owned Fantasy pack is at most a topology donor (low-poly base shapes like pants/shirts are genre-neutral; genre lives in silhouette details, textures, trims, and accessories) — no medieval trim/textures may survive into shipped garments. Weight the authoring routes accordingly: texture identity matters as much as mesh. Canon hook: the wiki already ships a garment brand — thrds (wiki/star-systems/GJ-475/index.md, Braemar fiber cooperative, corridor fashion markets) — so branded clothing connects to Phase-1 lore, not only generated_brands.toml. This emphasis also feeds the Quaternius-pivot evaluation: commercial alternatives skew sci-fi/urban while Quaternius clothing is fantasy-only.
|
||
|
||
Nuance (user, 2026-07-06): the cyberpunk/modern direction is the DEFAULT, not a prohibition — fashion in the Reach is cyclical, so fantasy/medieval-flavored garments may appear here and there as deliberate fashion statements (subculture pieces, luxury/revival trims, statement outerwear). Supersedes the previous note''s hard ''no medieval trim may survive'' line. Practical consequence: a small number of Fantasy-pack pieces may ship near-as-is where they read as intentional fashion; the basic set itself stays modern.
|
||
|
||
Art direction CONSOLIDATED (user, 2026-07-06 — supersedes the two notes above): the Reach has no single clothing style — ALL styles coexist, with modern/cyberpunk probably the most prevalent. Style is a prevalence DISTRIBUTION, not a genre rule, and may eventually vary by culture/settlement (fits the simulation DNA; fashion-as-cultural-data is a later phase concern, not this ticket). Consequences now: (1) the engine is style-agnostic by construction (slots/tints/logos carry no genre); (2) the basic set targets the prevalent center — modern casual + corporate — because it dresses the most NPCs and the shopping experience; (3) garments get a lightweight style tag in the manifest (e.g. style: modern|formal|fantasy|utility) as the cheap seam so per-culture distributions can be authored later without retrofitting; (4) Fantasy-pack pieces are legitimate catalogue members under their own tag, prevalence-weighted low.
|
||
|
||
Scope pin (user, 2026-07-06, final word on style): for simplicity, THIS ticket ships ONE style only — cyberpunk/modern. The pluralistic distribution model above remains the long-term truth (keep the manifest style tag as the seam), but the v1 basic set is single-style; other styles are catalogue growth, not scope.', NULL, '2026-07-06 07:43:39', '2026-07-06 07:43:39.155', '2026-07-06 07:43:39.155', NULL, '11a05e0b8646bf168f5866245b3dbdb5', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKCPBF41RWK9PW9M22Q7961C', 'description', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.
|
||
|
||
Art direction (user, 2026-07-06): garments read CYBERPUNK/MODERN — near-future everyday civilian + corporate wear — NOT fantasy/medieval. The owned Fantasy pack is at most a topology donor (low-poly base shapes like pants/shirts are genre-neutral; genre lives in silhouette details, textures, trims, and accessories) — no medieval trim/textures may survive into shipped garments. Weight the authoring routes accordingly: texture identity matters as much as mesh. Canon hook: the wiki already ships a garment brand — thrds (wiki/star-systems/GJ-475/index.md, Braemar fiber cooperative, corridor fashion markets) — so branded clothing connects to Phase-1 lore, not only generated_brands.toml. This emphasis also feeds the Quaternius-pivot evaluation: commercial alternatives skew sci-fi/urban while Quaternius clothing is fantasy-only.
|
||
|
||
Nuance (user, 2026-07-06): the cyberpunk/modern direction is the DEFAULT, not a prohibition — fashion in the Reach is cyclical, so fantasy/medieval-flavored garments may appear here and there as deliberate fashion statements (subculture pieces, luxury/revival trims, statement outerwear). Supersedes the previous note''s hard ''no medieval trim may survive'' line. Practical consequence: a small number of Fantasy-pack pieces may ship near-as-is where they read as intentional fashion; the basic set itself stays modern.
|
||
|
||
Art direction CONSOLIDATED (user, 2026-07-06 — supersedes the two notes above): the Reach has no single clothing style — ALL styles coexist, with modern/cyberpunk probably the most prevalent. Style is a prevalence DISTRIBUTION, not a genre rule, and may eventually vary by culture/settlement (fits the simulation DNA; fashion-as-cultural-data is a later phase concern, not this ticket). Consequences now: (1) the engine is style-agnostic by construction (slots/tints/logos carry no genre); (2) the basic set targets the prevalent center — modern casual + corporate — because it dresses the most NPCs and the shopping experience; (3) garments get a lightweight style tag in the manifest (e.g. style: modern|formal|fantasy|utility) as the cheap seam so per-culture distributions can be authored later without retrofitting; (4) Fantasy-pack pieces are legitimate catalogue members under their own tag, prevalence-weighted low.
|
||
|
||
Scope pin (user, 2026-07-06, final word on style): for simplicity, THIS ticket ships ONE style only — cyberpunk/modern. The pluralistic distribution model above remains the long-term truth (keep the manifest style tag as the seam), but the v1 basic set is single-style; other styles are catalogue growth, not scope.', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.
|
||
|
||
Art direction (user, 2026-07-06): garments read CYBERPUNK/MODERN — near-future everyday civilian + corporate wear — NOT fantasy/medieval. The owned Fantasy pack is at most a topology donor (low-poly base shapes like pants/shirts are genre-neutral; genre lives in silhouette details, textures, trims, and accessories) — no medieval trim/textures may survive into shipped garments. Weight the authoring routes accordingly: texture identity matters as much as mesh. Canon hook: the wiki already ships a garment brand — thrds (wiki/star-systems/GJ-475/index.md, Braemar fiber cooperative, corridor fashion markets) — so branded clothing connects to Phase-1 lore, not only generated_brands.toml. This emphasis also feeds the Quaternius-pivot evaluation: commercial alternatives skew sci-fi/urban while Quaternius clothing is fantasy-only.
|
||
|
||
Nuance (user, 2026-07-06): the cyberpunk/modern direction is the DEFAULT, not a prohibition — fashion in the Reach is cyclical, so fantasy/medieval-flavored garments may appear here and there as deliberate fashion statements (subculture pieces, luxury/revival trims, statement outerwear). Supersedes the previous note''s hard ''no medieval trim may survive'' line. Practical consequence: a small number of Fantasy-pack pieces may ship near-as-is where they read as intentional fashion; the basic set itself stays modern.
|
||
|
||
Art direction CONSOLIDATED (user, 2026-07-06 — supersedes the two notes above): the Reach has no single clothing style — ALL styles coexist, with modern/cyberpunk probably the most prevalent. Style is a prevalence DISTRIBUTION, not a genre rule, and may eventually vary by culture/settlement (fits the simulation DNA; fashion-as-cultural-data is a later phase concern, not this ticket). Consequences now: (1) the engine is style-agnostic by construction (slots/tints/logos carry no genre); (2) the basic set targets the prevalent center — modern casual + corporate — because it dresses the most NPCs and the shopping experience; (3) garments get a lightweight style tag in the manifest (e.g. style: modern|formal|fantasy|utility) as the cheap seam so per-culture distributions can be authored later without retrofitting; (4) Fantasy-pack pieces are legitimate catalogue members under their own tag, prevalence-weighted low.
|
||
|
||
Scope pin (user, 2026-07-06, final word on style): for simplicity, THIS ticket ships ONE style only — cyberpunk/modern. The pluralistic distribution model above remains the long-term truth (keep the manifest style tag as the seam), but the v1 basic set is single-style; other styles are catalogue growth, not scope.
|
||
|
||
Route challenge (user, 2026-07-06): not sold on staying Quaternius-primary — ''Quaternius is limited and will move the wall at too slow a pace; I''d rather pick something that has what we need now.'' Fresh store verification (2026-07-06): Sidekick packs are one-time USD199.99, perpetual, engine-agnostic license (Godot legal, unsupported); NO raw FBX — extraction from unitypackage (community-proven: unitypackage_godot, third-party Sidekick Creator Godot plugin incl. body blend shapes); ''Sold out'' labels are a broken-theme artifact per Shopify JSON (needs one browser cart check); SyntyPass rejected (assets stop being developable after cancel). Relevant packs: Starter (FREE, 57+91 parts), Modern Civilians (165 parts = v1 basic set territory), Sci-Fi Civilians (103 parts, cyberpunk accents), Modern Police (uniforms/officials). DECISION NOW GATED ON THE FREE SPIKE: user downloads free Starter Pack -> Bridge-C spike (extract garment -> Robust Weight Transfer onto our rig -> 11-body batch -> animation QA in T-1088 sandbox). Pass -> buy Modern Civilians, Synty = primary garment supply (+UAL1/UAL2 Source ~USD30 for clips — no Synty substitute exists for Godot animations; Fantasy Outfits Source drops to low priority under the single-style pin). Fail -> hand-author route stands. Stay-vs-pivot governance record HELD until spike evidence lands.', NULL, '2026-07-06 08:14:11', '2026-07-06 08:14:11.037', '2026-07-06 08:14:11.037', NULL, '8d8631fb2a7bd74e481972a7728af370', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKCPBF41RWK9PW9M22Q7961C', 'description', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.
|
||
|
||
Art direction (user, 2026-07-06): garments read CYBERPUNK/MODERN — near-future everyday civilian + corporate wear — NOT fantasy/medieval. The owned Fantasy pack is at most a topology donor (low-poly base shapes like pants/shirts are genre-neutral; genre lives in silhouette details, textures, trims, and accessories) — no medieval trim/textures may survive into shipped garments. Weight the authoring routes accordingly: texture identity matters as much as mesh. Canon hook: the wiki already ships a garment brand — thrds (wiki/star-systems/GJ-475/index.md, Braemar fiber cooperative, corridor fashion markets) — so branded clothing connects to Phase-1 lore, not only generated_brands.toml. This emphasis also feeds the Quaternius-pivot evaluation: commercial alternatives skew sci-fi/urban while Quaternius clothing is fantasy-only.
|
||
|
||
Nuance (user, 2026-07-06): the cyberpunk/modern direction is the DEFAULT, not a prohibition — fashion in the Reach is cyclical, so fantasy/medieval-flavored garments may appear here and there as deliberate fashion statements (subculture pieces, luxury/revival trims, statement outerwear). Supersedes the previous note''s hard ''no medieval trim may survive'' line. Practical consequence: a small number of Fantasy-pack pieces may ship near-as-is where they read as intentional fashion; the basic set itself stays modern.
|
||
|
||
Art direction CONSOLIDATED (user, 2026-07-06 — supersedes the two notes above): the Reach has no single clothing style — ALL styles coexist, with modern/cyberpunk probably the most prevalent. Style is a prevalence DISTRIBUTION, not a genre rule, and may eventually vary by culture/settlement (fits the simulation DNA; fashion-as-cultural-data is a later phase concern, not this ticket). Consequences now: (1) the engine is style-agnostic by construction (slots/tints/logos carry no genre); (2) the basic set targets the prevalent center — modern casual + corporate — because it dresses the most NPCs and the shopping experience; (3) garments get a lightweight style tag in the manifest (e.g. style: modern|formal|fantasy|utility) as the cheap seam so per-culture distributions can be authored later without retrofitting; (4) Fantasy-pack pieces are legitimate catalogue members under their own tag, prevalence-weighted low.
|
||
|
||
Scope pin (user, 2026-07-06, final word on style): for simplicity, THIS ticket ships ONE style only — cyberpunk/modern. The pluralistic distribution model above remains the long-term truth (keep the manifest style tag as the seam), but the v1 basic set is single-style; other styles are catalogue growth, not scope.
|
||
|
||
Route challenge (user, 2026-07-06): not sold on staying Quaternius-primary — ''Quaternius is limited and will move the wall at too slow a pace; I''d rather pick something that has what we need now.'' Fresh store verification (2026-07-06): Sidekick packs are one-time USD199.99, perpetual, engine-agnostic license (Godot legal, unsupported); NO raw FBX — extraction from unitypackage (community-proven: unitypackage_godot, third-party Sidekick Creator Godot plugin incl. body blend shapes); ''Sold out'' labels are a broken-theme artifact per Shopify JSON (needs one browser cart check); SyntyPass rejected (assets stop being developable after cancel). Relevant packs: Starter (FREE, 57+91 parts), Modern Civilians (165 parts = v1 basic set territory), Sci-Fi Civilians (103 parts, cyberpunk accents), Modern Police (uniforms/officials). DECISION NOW GATED ON THE FREE SPIKE: user downloads free Starter Pack -> Bridge-C spike (extract garment -> Robust Weight Transfer onto our rig -> 11-body batch -> animation QA in T-1088 sandbox). Pass -> buy Modern Civilians, Synty = primary garment supply (+UAL1/UAL2 Source ~USD30 for clips — no Synty substitute exists for Godot animations; Fantasy Outfits Source drops to low priority under the single-style pin). Fail -> hand-author route stands. Stay-vs-pivot governance record HELD until spike evidence lands.', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.
|
||
|
||
Art direction (user, 2026-07-06): garments read CYBERPUNK/MODERN — near-future everyday civilian + corporate wear — NOT fantasy/medieval. The owned Fantasy pack is at most a topology donor (low-poly base shapes like pants/shirts are genre-neutral; genre lives in silhouette details, textures, trims, and accessories) — no medieval trim/textures may survive into shipped garments. Weight the authoring routes accordingly: texture identity matters as much as mesh. Canon hook: the wiki already ships a garment brand — thrds (wiki/star-systems/GJ-475/index.md, Braemar fiber cooperative, corridor fashion markets) — so branded clothing connects to Phase-1 lore, not only generated_brands.toml. This emphasis also feeds the Quaternius-pivot evaluation: commercial alternatives skew sci-fi/urban while Quaternius clothing is fantasy-only.
|
||
|
||
Nuance (user, 2026-07-06): the cyberpunk/modern direction is the DEFAULT, not a prohibition — fashion in the Reach is cyclical, so fantasy/medieval-flavored garments may appear here and there as deliberate fashion statements (subculture pieces, luxury/revival trims, statement outerwear). Supersedes the previous note''s hard ''no medieval trim may survive'' line. Practical consequence: a small number of Fantasy-pack pieces may ship near-as-is where they read as intentional fashion; the basic set itself stays modern.
|
||
|
||
Art direction CONSOLIDATED (user, 2026-07-06 — supersedes the two notes above): the Reach has no single clothing style — ALL styles coexist, with modern/cyberpunk probably the most prevalent. Style is a prevalence DISTRIBUTION, not a genre rule, and may eventually vary by culture/settlement (fits the simulation DNA; fashion-as-cultural-data is a later phase concern, not this ticket). Consequences now: (1) the engine is style-agnostic by construction (slots/tints/logos carry no genre); (2) the basic set targets the prevalent center — modern casual + corporate — because it dresses the most NPCs and the shopping experience; (3) garments get a lightweight style tag in the manifest (e.g. style: modern|formal|fantasy|utility) as the cheap seam so per-culture distributions can be authored later without retrofitting; (4) Fantasy-pack pieces are legitimate catalogue members under their own tag, prevalence-weighted low.
|
||
|
||
Scope pin (user, 2026-07-06, final word on style): for simplicity, THIS ticket ships ONE style only — cyberpunk/modern. The pluralistic distribution model above remains the long-term truth (keep the manifest style tag as the seam), but the v1 basic set is single-style; other styles are catalogue growth, not scope.
|
||
|
||
Route challenge (user, 2026-07-06): not sold on staying Quaternius-primary — ''Quaternius is limited and will move the wall at too slow a pace; I''d rather pick something that has what we need now.'' Fresh store verification (2026-07-06): Sidekick packs are one-time USD199.99, perpetual, engine-agnostic license (Godot legal, unsupported); NO raw FBX — extraction from unitypackage (community-proven: unitypackage_godot, third-party Sidekick Creator Godot plugin incl. body blend shapes); ''Sold out'' labels are a broken-theme artifact per Shopify JSON (needs one browser cart check); SyntyPass rejected (assets stop being developable after cancel). Relevant packs: Starter (FREE, 57+91 parts), Modern Civilians (165 parts = v1 basic set territory), Sci-Fi Civilians (103 parts, cyberpunk accents), Modern Police (uniforms/officials). DECISION NOW GATED ON THE FREE SPIKE: user downloads free Starter Pack -> Bridge-C spike (extract garment -> Robust Weight Transfer onto our rig -> 11-body batch -> animation QA in T-1088 sandbox). Pass -> buy Modern Civilians, Synty = primary garment supply (+UAL1/UAL2 Source ~USD30 for clips — no Synty substitute exists for Godot animations; Fantasy Outfits Source drops to low priority under the single-style pin). Fail -> hand-author route stands. Stay-vs-pivot governance record HELD until spike evidence lands.
|
||
|
||
Scope guard (user concern, 2026-07-06): Synty intake must NOT displace the create-stuff-yourself pipeline — the user''s goal includes in-house garment creation capability, not just swapping vendor catalogs. Resolution: three-route portfolio sharing one engine — (a) Synty intake = variety bootstrap only; (b) derivation scripting (cuts/merges/retexture, agent-automatable) = create-yourself lite, turns any donor topology into original designs; (c) TRUE AUTHORING on owned UBC Source body .blends = the pipeline proper. GUARANTEE: the colorable uniform and black suit (no donor exists in any pack) are built via route (c) as the authoring pipeline''s end-to-end proof — non-negotiable deliverable of this ticket, so the pipeline exists even if Synty covers everything else. Spike status: extraction done inline by lead (158 FBX, sci-fi civilian theme confirmed); DECISIVE finding — Sidekick rig is UE-Mannequin-named, 52/65 bone-name overlap with our rig, sample garment binds to 12 vgroups of which 11 match ours exactly (only head->Head case rename) => transplant likely rename-and-rebind, far cheaper than the weight-transfer the pivot eval assumed; body blend shapes travel in the FBX. Transplant phase parked pending API recovery / token-window reset.', NULL, '2026-07-06 08:59:05', '2026-07-06 08:59:05.485', '2026-07-06 08:59:05.485', NULL, '18eabf5907931a8feb925b614cc4478c', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKCPBF41RWK9PW9M22Q7961C', 'description', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.
|
||
|
||
Art direction (user, 2026-07-06): garments read CYBERPUNK/MODERN — near-future everyday civilian + corporate wear — NOT fantasy/medieval. The owned Fantasy pack is at most a topology donor (low-poly base shapes like pants/shirts are genre-neutral; genre lives in silhouette details, textures, trims, and accessories) — no medieval trim/textures may survive into shipped garments. Weight the authoring routes accordingly: texture identity matters as much as mesh. Canon hook: the wiki already ships a garment brand — thrds (wiki/star-systems/GJ-475/index.md, Braemar fiber cooperative, corridor fashion markets) — so branded clothing connects to Phase-1 lore, not only generated_brands.toml. This emphasis also feeds the Quaternius-pivot evaluation: commercial alternatives skew sci-fi/urban while Quaternius clothing is fantasy-only.
|
||
|
||
Nuance (user, 2026-07-06): the cyberpunk/modern direction is the DEFAULT, not a prohibition — fashion in the Reach is cyclical, so fantasy/medieval-flavored garments may appear here and there as deliberate fashion statements (subculture pieces, luxury/revival trims, statement outerwear). Supersedes the previous note''s hard ''no medieval trim may survive'' line. Practical consequence: a small number of Fantasy-pack pieces may ship near-as-is where they read as intentional fashion; the basic set itself stays modern.
|
||
|
||
Art direction CONSOLIDATED (user, 2026-07-06 — supersedes the two notes above): the Reach has no single clothing style — ALL styles coexist, with modern/cyberpunk probably the most prevalent. Style is a prevalence DISTRIBUTION, not a genre rule, and may eventually vary by culture/settlement (fits the simulation DNA; fashion-as-cultural-data is a later phase concern, not this ticket). Consequences now: (1) the engine is style-agnostic by construction (slots/tints/logos carry no genre); (2) the basic set targets the prevalent center — modern casual + corporate — because it dresses the most NPCs and the shopping experience; (3) garments get a lightweight style tag in the manifest (e.g. style: modern|formal|fantasy|utility) as the cheap seam so per-culture distributions can be authored later without retrofitting; (4) Fantasy-pack pieces are legitimate catalogue members under their own tag, prevalence-weighted low.
|
||
|
||
Scope pin (user, 2026-07-06, final word on style): for simplicity, THIS ticket ships ONE style only — cyberpunk/modern. The pluralistic distribution model above remains the long-term truth (keep the manifest style tag as the seam), but the v1 basic set is single-style; other styles are catalogue growth, not scope.
|
||
|
||
Route challenge (user, 2026-07-06): not sold on staying Quaternius-primary — ''Quaternius is limited and will move the wall at too slow a pace; I''d rather pick something that has what we need now.'' Fresh store verification (2026-07-06): Sidekick packs are one-time USD199.99, perpetual, engine-agnostic license (Godot legal, unsupported); NO raw FBX — extraction from unitypackage (community-proven: unitypackage_godot, third-party Sidekick Creator Godot plugin incl. body blend shapes); ''Sold out'' labels are a broken-theme artifact per Shopify JSON (needs one browser cart check); SyntyPass rejected (assets stop being developable after cancel). Relevant packs: Starter (FREE, 57+91 parts), Modern Civilians (165 parts = v1 basic set territory), Sci-Fi Civilians (103 parts, cyberpunk accents), Modern Police (uniforms/officials). DECISION NOW GATED ON THE FREE SPIKE: user downloads free Starter Pack -> Bridge-C spike (extract garment -> Robust Weight Transfer onto our rig -> 11-body batch -> animation QA in T-1088 sandbox). Pass -> buy Modern Civilians, Synty = primary garment supply (+UAL1/UAL2 Source ~USD30 for clips — no Synty substitute exists for Godot animations; Fantasy Outfits Source drops to low priority under the single-style pin). Fail -> hand-author route stands. Stay-vs-pivot governance record HELD until spike evidence lands.
|
||
|
||
Scope guard (user concern, 2026-07-06): Synty intake must NOT displace the create-stuff-yourself pipeline — the user''s goal includes in-house garment creation capability, not just swapping vendor catalogs. Resolution: three-route portfolio sharing one engine — (a) Synty intake = variety bootstrap only; (b) derivation scripting (cuts/merges/retexture, agent-automatable) = create-yourself lite, turns any donor topology into original designs; (c) TRUE AUTHORING on owned UBC Source body .blends = the pipeline proper. GUARANTEE: the colorable uniform and black suit (no donor exists in any pack) are built via route (c) as the authoring pipeline''s end-to-end proof — non-negotiable deliverable of this ticket, so the pipeline exists even if Synty covers everything else. Spike status: extraction done inline by lead (158 FBX, sci-fi civilian theme confirmed); DECISIVE finding — Sidekick rig is UE-Mannequin-named, 52/65 bone-name overlap with our rig, sample garment binds to 12 vgroups of which 11 match ours exactly (only head->Head case rename) => transplant likely rename-and-rebind, far cheaper than the weight-transfer the pivot eval assumed; body blend shapes travel in the FBX. Transplant phase parked pending API recovery / token-window reset.', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.
|
||
|
||
Art direction (user, 2026-07-06): garments read CYBERPUNK/MODERN — near-future everyday civilian + corporate wear — NOT fantasy/medieval. The owned Fantasy pack is at most a topology donor (low-poly base shapes like pants/shirts are genre-neutral; genre lives in silhouette details, textures, trims, and accessories) — no medieval trim/textures may survive into shipped garments. Weight the authoring routes accordingly: texture identity matters as much as mesh. Canon hook: the wiki already ships a garment brand — thrds (wiki/star-systems/GJ-475/index.md, Braemar fiber cooperative, corridor fashion markets) — so branded clothing connects to Phase-1 lore, not only generated_brands.toml. This emphasis also feeds the Quaternius-pivot evaluation: commercial alternatives skew sci-fi/urban while Quaternius clothing is fantasy-only.
|
||
|
||
Nuance (user, 2026-07-06): the cyberpunk/modern direction is the DEFAULT, not a prohibition — fashion in the Reach is cyclical, so fantasy/medieval-flavored garments may appear here and there as deliberate fashion statements (subculture pieces, luxury/revival trims, statement outerwear). Supersedes the previous note''s hard ''no medieval trim may survive'' line. Practical consequence: a small number of Fantasy-pack pieces may ship near-as-is where they read as intentional fashion; the basic set itself stays modern.
|
||
|
||
Art direction CONSOLIDATED (user, 2026-07-06 — supersedes the two notes above): the Reach has no single clothing style — ALL styles coexist, with modern/cyberpunk probably the most prevalent. Style is a prevalence DISTRIBUTION, not a genre rule, and may eventually vary by culture/settlement (fits the simulation DNA; fashion-as-cultural-data is a later phase concern, not this ticket). Consequences now: (1) the engine is style-agnostic by construction (slots/tints/logos carry no genre); (2) the basic set targets the prevalent center — modern casual + corporate — because it dresses the most NPCs and the shopping experience; (3) garments get a lightweight style tag in the manifest (e.g. style: modern|formal|fantasy|utility) as the cheap seam so per-culture distributions can be authored later without retrofitting; (4) Fantasy-pack pieces are legitimate catalogue members under their own tag, prevalence-weighted low.
|
||
|
||
Scope pin (user, 2026-07-06, final word on style): for simplicity, THIS ticket ships ONE style only — cyberpunk/modern. The pluralistic distribution model above remains the long-term truth (keep the manifest style tag as the seam), but the v1 basic set is single-style; other styles are catalogue growth, not scope.
|
||
|
||
Route challenge (user, 2026-07-06): not sold on staying Quaternius-primary — ''Quaternius is limited and will move the wall at too slow a pace; I''d rather pick something that has what we need now.'' Fresh store verification (2026-07-06): Sidekick packs are one-time USD199.99, perpetual, engine-agnostic license (Godot legal, unsupported); NO raw FBX — extraction from unitypackage (community-proven: unitypackage_godot, third-party Sidekick Creator Godot plugin incl. body blend shapes); ''Sold out'' labels are a broken-theme artifact per Shopify JSON (needs one browser cart check); SyntyPass rejected (assets stop being developable after cancel). Relevant packs: Starter (FREE, 57+91 parts), Modern Civilians (165 parts = v1 basic set territory), Sci-Fi Civilians (103 parts, cyberpunk accents), Modern Police (uniforms/officials). DECISION NOW GATED ON THE FREE SPIKE: user downloads free Starter Pack -> Bridge-C spike (extract garment -> Robust Weight Transfer onto our rig -> 11-body batch -> animation QA in T-1088 sandbox). Pass -> buy Modern Civilians, Synty = primary garment supply (+UAL1/UAL2 Source ~USD30 for clips — no Synty substitute exists for Godot animations; Fantasy Outfits Source drops to low priority under the single-style pin). Fail -> hand-author route stands. Stay-vs-pivot governance record HELD until spike evidence lands.
|
||
|
||
Scope guard (user concern, 2026-07-06): Synty intake must NOT displace the create-stuff-yourself pipeline — the user''s goal includes in-house garment creation capability, not just swapping vendor catalogs. Resolution: three-route portfolio sharing one engine — (a) Synty intake = variety bootstrap only; (b) derivation scripting (cuts/merges/retexture, agent-automatable) = create-yourself lite, turns any donor topology into original designs; (c) TRUE AUTHORING on owned UBC Source body .blends = the pipeline proper. GUARANTEE: the colorable uniform and black suit (no donor exists in any pack) are built via route (c) as the authoring pipeline''s end-to-end proof — non-negotiable deliverable of this ticket, so the pipeline exists even if Synty covers everything else. Spike status: extraction done inline by lead (158 FBX, sci-fi civilian theme confirmed); DECISIVE finding — Sidekick rig is UE-Mannequin-named, 52/65 bone-name overlap with our rig, sample garment binds to 12 vgroups of which 11 match ours exactly (only head->Head case rename) => transplant likely rename-and-rebind, far cheaper than the weight-transfer the pivot eval assumed; body blend shapes travel in the FBX. Transplant phase parked pending API recovery / token-window reset.
|
||
|
||
ROUTE DECISION (user, 2026-07-06, final): Synty intake REJECTED despite the spike''s technical PASS — (1) USD199.99/pack is too expensive; (2) Sidekick modularity is baked body-segment swap (clothes fused to body chunks), incompatible with our layered clothing-over-body system (11 bodies, skin tones, slot swapping); (3) user dislikes the Synty style. The spike still paid: transplant/batch scripts are source-agnostic and become the G1-family production pipeline; T-1090 (5 bodies broken bare) discovered; the Synty question is closed with evidence, not parked. OPERATIVE ROUTE: (b) derive from owned Fantasy parts + (c) hand-author — with a new preferred authoring technique: OFFSET-SHELL FROM OUR OWN BODY MESHES (extract body segment surface, offset outward into garment shell, cut neckline/hem/sleeves; weights inherited by construction, style fully ours, USD0). Suit + uniform remain the full hand-author proof. Purchases still open (separate concerns): UAL1/UAL2 Source ~USD30 for animation clips; Fantasy Outfits Source USD20 low-priority convenience.', NULL, '2026-07-06 11:09:40', '2026-07-06 11:09:40.351', '2026-07-06 11:09:40.351', NULL, '0121b9bd7a9fb6c32a4974973a9614d6', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKCER95EK266H8RWPW8XT1F0', 'description', 'Fable-5-window sidequest (sanctioned cascade exception, 2026-07-05): the presentation layer that turns discrete server tile steps into a believable walking 3D character. Scope: 3D sandbox dev scene (SR_LIVE=1, greybox tiles derived from server snapshots, no hand-authored map), CharacterVisual instantiated in-world, locomotion rig (tile-step + facing-octant interpolation, stance-aware speeds), UAL animation state machine (idle/walk/sprint/careful/crouch), D-148 camera rig (30deg low-angle follow, 45deg rotation). Server-authoritative from day one — no client-local movement model. Builds on D-148/D-149/D-244/D-066 and the T-417 stance system. If the Fable 5 window closes mid-flight, work parks here.
|
||
|
||
Visual reference (user, 2026-07-06): Xenonauts 2 nails the target tiles/occlusion/character perspective — readable tile grid, low-angle tactical camera with angle options (matches D-148 30deg low-angle + 45deg rotation steps and the spikes/3dpipeline angle presets), and crucially its wall/roof occlusion treatment: camera-facing walls cut down/ghosted so interiors stay readable, floors peel per z-level. One deliberate difference: our camera locks to the player character (D-015/T-116) — no free map panning. Implication for the locomotion sandbox: greybox walls should prototype camera-facing cutaway occlusion early, since wall readability interacts with the locked low-angle camera.
|
||
|
||
Scoping call (user + lead agreement, 2026-07-06): wall cutaway is CLIENT-SIDE presentation, decoupled from fog-of-perception. Rationale: two occlusion systems with different subjects — perception/fog governs what the CHARACTER knows (server-enforced info boundary; client only receives observer-filtered geometry), cutaway governs what the PLAYER''S CAMERA sees (pure render mode on wall data the client already holds). They compose: cutaway cuts render height; fog overlay still gates what is visible behind. Walls remain first-class client data objects (future destruction/explosion interactions), cutaway is a render mode on them like tint/LOD. Nuance parked for Phase 5 proper: destroyed-while-unobserved walls should render in remembered state (fog-memory applied to geometry). If this holds through implementation, mint a D-record (perception domain) when the sidequest lands.', 'Fable-5-window sidequest (sanctioned cascade exception, 2026-07-05): the presentation layer that turns discrete server tile steps into a believable walking 3D character. Scope: 3D sandbox dev scene (SR_LIVE=1, greybox tiles derived from server snapshots, no hand-authored map), CharacterVisual instantiated in-world, locomotion rig (tile-step + facing-octant interpolation, stance-aware speeds), UAL animation state machine (idle/walk/sprint/careful/crouch), D-148 camera rig (30deg low-angle follow, 45deg rotation). Server-authoritative from day one — no client-local movement model. Builds on D-148/D-149/D-244/D-066 and the T-417 stance system. If the Fable 5 window closes mid-flight, work parks here.
|
||
|
||
Visual reference (user, 2026-07-06): Xenonauts 2 nails the target tiles/occlusion/character perspective — readable tile grid, low-angle tactical camera with angle options (matches D-148 30deg low-angle + 45deg rotation steps and the spikes/3dpipeline angle presets), and crucially its wall/roof occlusion treatment: camera-facing walls cut down/ghosted so interiors stay readable, floors peel per z-level. One deliberate difference: our camera locks to the player character (D-015/T-116) — no free map panning. Implication for the locomotion sandbox: greybox walls should prototype camera-facing cutaway occlusion early, since wall readability interacts with the locked low-angle camera.
|
||
|
||
Scoping call (user + lead agreement, 2026-07-06): wall cutaway is CLIENT-SIDE presentation, decoupled from fog-of-perception. Rationale: two occlusion systems with different subjects — perception/fog governs what the CHARACTER knows (server-enforced info boundary; client only receives observer-filtered geometry), cutaway governs what the PLAYER''S CAMERA sees (pure render mode on wall data the client already holds). They compose: cutaway cuts render height; fog overlay still gates what is visible behind. Walls remain first-class client data objects (future destruction/explosion interactions), cutaway is a render mode on them like tint/LOD. Nuance parked for Phase 5 proper: destroyed-while-unobserved walls should render in remembered state (fog-memory applied to geometry). If this holds through implementation, mint a D-record (perception domain) when the sidequest lands.
|
||
|
||
Animation supply resolved (2026-07-06): user purchased UAL1[Source+Pro] (120 clips, identical lists) + UAL2[Source] (134 clips), unzipped in docs/assets/downloads/. Gains: Turn90_L/R + Turn180_L/R (turn-in-place), Sprint_Enter/Exit + Crouch_Enter/Exit (stance transitions), full 8-direction Walk/Jog/Crouch sets incl. diagonals, Counter_Idle + talking/phone/sitting idles (life-sim verbs), plus _RM root-motion variants (unused — in-place is correct for server-authoritative interpolation). Still absent everywhere: walk start/stop + stairs — the only remaining custom clips. Integration is NOT a drop-in swap: upstream renamed clips (Walk_Loop -> Walk_Fwd_Loop etc.), so wire via the design''s recorded plan — explicit library names + lib/Clip addressing + gait-table update. NOTE for facing design: the 8-dir walk sets unlock Q-084''s parked walk-vs-aim split (direction-matched clips relative to facing) — revisit during the S9 tuning session.', NULL, '2026-07-06 11:17:25', '2026-07-06 11:17:25.652', '2026-07-06 11:17:25.652', NULL, '5c337857bf33c1a3bbb2bd33152e955e', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKCPBF41RWK9PW9M22Q7961C', 'description', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.
|
||
|
||
Art direction (user, 2026-07-06): garments read CYBERPUNK/MODERN — near-future everyday civilian + corporate wear — NOT fantasy/medieval. The owned Fantasy pack is at most a topology donor (low-poly base shapes like pants/shirts are genre-neutral; genre lives in silhouette details, textures, trims, and accessories) — no medieval trim/textures may survive into shipped garments. Weight the authoring routes accordingly: texture identity matters as much as mesh. Canon hook: the wiki already ships a garment brand — thrds (wiki/star-systems/GJ-475/index.md, Braemar fiber cooperative, corridor fashion markets) — so branded clothing connects to Phase-1 lore, not only generated_brands.toml. This emphasis also feeds the Quaternius-pivot evaluation: commercial alternatives skew sci-fi/urban while Quaternius clothing is fantasy-only.
|
||
|
||
Nuance (user, 2026-07-06): the cyberpunk/modern direction is the DEFAULT, not a prohibition — fashion in the Reach is cyclical, so fantasy/medieval-flavored garments may appear here and there as deliberate fashion statements (subculture pieces, luxury/revival trims, statement outerwear). Supersedes the previous note''s hard ''no medieval trim may survive'' line. Practical consequence: a small number of Fantasy-pack pieces may ship near-as-is where they read as intentional fashion; the basic set itself stays modern.
|
||
|
||
Art direction CONSOLIDATED (user, 2026-07-06 — supersedes the two notes above): the Reach has no single clothing style — ALL styles coexist, with modern/cyberpunk probably the most prevalent. Style is a prevalence DISTRIBUTION, not a genre rule, and may eventually vary by culture/settlement (fits the simulation DNA; fashion-as-cultural-data is a later phase concern, not this ticket). Consequences now: (1) the engine is style-agnostic by construction (slots/tints/logos carry no genre); (2) the basic set targets the prevalent center — modern casual + corporate — because it dresses the most NPCs and the shopping experience; (3) garments get a lightweight style tag in the manifest (e.g. style: modern|formal|fantasy|utility) as the cheap seam so per-culture distributions can be authored later without retrofitting; (4) Fantasy-pack pieces are legitimate catalogue members under their own tag, prevalence-weighted low.
|
||
|
||
Scope pin (user, 2026-07-06, final word on style): for simplicity, THIS ticket ships ONE style only — cyberpunk/modern. The pluralistic distribution model above remains the long-term truth (keep the manifest style tag as the seam), but the v1 basic set is single-style; other styles are catalogue growth, not scope.
|
||
|
||
Route challenge (user, 2026-07-06): not sold on staying Quaternius-primary — ''Quaternius is limited and will move the wall at too slow a pace; I''d rather pick something that has what we need now.'' Fresh store verification (2026-07-06): Sidekick packs are one-time USD199.99, perpetual, engine-agnostic license (Godot legal, unsupported); NO raw FBX — extraction from unitypackage (community-proven: unitypackage_godot, third-party Sidekick Creator Godot plugin incl. body blend shapes); ''Sold out'' labels are a broken-theme artifact per Shopify JSON (needs one browser cart check); SyntyPass rejected (assets stop being developable after cancel). Relevant packs: Starter (FREE, 57+91 parts), Modern Civilians (165 parts = v1 basic set territory), Sci-Fi Civilians (103 parts, cyberpunk accents), Modern Police (uniforms/officials). DECISION NOW GATED ON THE FREE SPIKE: user downloads free Starter Pack -> Bridge-C spike (extract garment -> Robust Weight Transfer onto our rig -> 11-body batch -> animation QA in T-1088 sandbox). Pass -> buy Modern Civilians, Synty = primary garment supply (+UAL1/UAL2 Source ~USD30 for clips — no Synty substitute exists for Godot animations; Fantasy Outfits Source drops to low priority under the single-style pin). Fail -> hand-author route stands. Stay-vs-pivot governance record HELD until spike evidence lands.
|
||
|
||
Scope guard (user concern, 2026-07-06): Synty intake must NOT displace the create-stuff-yourself pipeline — the user''s goal includes in-house garment creation capability, not just swapping vendor catalogs. Resolution: three-route portfolio sharing one engine — (a) Synty intake = variety bootstrap only; (b) derivation scripting (cuts/merges/retexture, agent-automatable) = create-yourself lite, turns any donor topology into original designs; (c) TRUE AUTHORING on owned UBC Source body .blends = the pipeline proper. GUARANTEE: the colorable uniform and black suit (no donor exists in any pack) are built via route (c) as the authoring pipeline''s end-to-end proof — non-negotiable deliverable of this ticket, so the pipeline exists even if Synty covers everything else. Spike status: extraction done inline by lead (158 FBX, sci-fi civilian theme confirmed); DECISIVE finding — Sidekick rig is UE-Mannequin-named, 52/65 bone-name overlap with our rig, sample garment binds to 12 vgroups of which 11 match ours exactly (only head->Head case rename) => transplant likely rename-and-rebind, far cheaper than the weight-transfer the pivot eval assumed; body blend shapes travel in the FBX. Transplant phase parked pending API recovery / token-window reset.
|
||
|
||
ROUTE DECISION (user, 2026-07-06, final): Synty intake REJECTED despite the spike''s technical PASS — (1) USD199.99/pack is too expensive; (2) Sidekick modularity is baked body-segment swap (clothes fused to body chunks), incompatible with our layered clothing-over-body system (11 bodies, skin tones, slot swapping); (3) user dislikes the Synty style. The spike still paid: transplant/batch scripts are source-agnostic and become the G1-family production pipeline; T-1090 (5 bodies broken bare) discovered; the Synty question is closed with evidence, not parked. OPERATIVE ROUTE: (b) derive from owned Fantasy parts + (c) hand-author — with a new preferred authoring technique: OFFSET-SHELL FROM OUR OWN BODY MESHES (extract body segment surface, offset outward into garment shell, cut neckline/hem/sleeves; weights inherited by construction, style fully ours, USD0). Suit + uniform remain the full hand-author proof. Purchases still open (separate concerns): UAL1/UAL2 Source ~USD30 for animation clips; Fantasy Outfits Source USD20 low-priority convenience.', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.
|
||
|
||
Art direction (user, 2026-07-06): garments read CYBERPUNK/MODERN — near-future everyday civilian + corporate wear — NOT fantasy/medieval. The owned Fantasy pack is at most a topology donor (low-poly base shapes like pants/shirts are genre-neutral; genre lives in silhouette details, textures, trims, and accessories) — no medieval trim/textures may survive into shipped garments. Weight the authoring routes accordingly: texture identity matters as much as mesh. Canon hook: the wiki already ships a garment brand — thrds (wiki/star-systems/GJ-475/index.md, Braemar fiber cooperative, corridor fashion markets) — so branded clothing connects to Phase-1 lore, not only generated_brands.toml. This emphasis also feeds the Quaternius-pivot evaluation: commercial alternatives skew sci-fi/urban while Quaternius clothing is fantasy-only.
|
||
|
||
Nuance (user, 2026-07-06): the cyberpunk/modern direction is the DEFAULT, not a prohibition — fashion in the Reach is cyclical, so fantasy/medieval-flavored garments may appear here and there as deliberate fashion statements (subculture pieces, luxury/revival trims, statement outerwear). Supersedes the previous note''s hard ''no medieval trim may survive'' line. Practical consequence: a small number of Fantasy-pack pieces may ship near-as-is where they read as intentional fashion; the basic set itself stays modern.
|
||
|
||
Art direction CONSOLIDATED (user, 2026-07-06 — supersedes the two notes above): the Reach has no single clothing style — ALL styles coexist, with modern/cyberpunk probably the most prevalent. Style is a prevalence DISTRIBUTION, not a genre rule, and may eventually vary by culture/settlement (fits the simulation DNA; fashion-as-cultural-data is a later phase concern, not this ticket). Consequences now: (1) the engine is style-agnostic by construction (slots/tints/logos carry no genre); (2) the basic set targets the prevalent center — modern casual + corporate — because it dresses the most NPCs and the shopping experience; (3) garments get a lightweight style tag in the manifest (e.g. style: modern|formal|fantasy|utility) as the cheap seam so per-culture distributions can be authored later without retrofitting; (4) Fantasy-pack pieces are legitimate catalogue members under their own tag, prevalence-weighted low.
|
||
|
||
Scope pin (user, 2026-07-06, final word on style): for simplicity, THIS ticket ships ONE style only — cyberpunk/modern. The pluralistic distribution model above remains the long-term truth (keep the manifest style tag as the seam), but the v1 basic set is single-style; other styles are catalogue growth, not scope.
|
||
|
||
Route challenge (user, 2026-07-06): not sold on staying Quaternius-primary — ''Quaternius is limited and will move the wall at too slow a pace; I''d rather pick something that has what we need now.'' Fresh store verification (2026-07-06): Sidekick packs are one-time USD199.99, perpetual, engine-agnostic license (Godot legal, unsupported); NO raw FBX — extraction from unitypackage (community-proven: unitypackage_godot, third-party Sidekick Creator Godot plugin incl. body blend shapes); ''Sold out'' labels are a broken-theme artifact per Shopify JSON (needs one browser cart check); SyntyPass rejected (assets stop being developable after cancel). Relevant packs: Starter (FREE, 57+91 parts), Modern Civilians (165 parts = v1 basic set territory), Sci-Fi Civilians (103 parts, cyberpunk accents), Modern Police (uniforms/officials). DECISION NOW GATED ON THE FREE SPIKE: user downloads free Starter Pack -> Bridge-C spike (extract garment -> Robust Weight Transfer onto our rig -> 11-body batch -> animation QA in T-1088 sandbox). Pass -> buy Modern Civilians, Synty = primary garment supply (+UAL1/UAL2 Source ~USD30 for clips — no Synty substitute exists for Godot animations; Fantasy Outfits Source drops to low priority under the single-style pin). Fail -> hand-author route stands. Stay-vs-pivot governance record HELD until spike evidence lands.
|
||
|
||
Scope guard (user concern, 2026-07-06): Synty intake must NOT displace the create-stuff-yourself pipeline — the user''s goal includes in-house garment creation capability, not just swapping vendor catalogs. Resolution: three-route portfolio sharing one engine — (a) Synty intake = variety bootstrap only; (b) derivation scripting (cuts/merges/retexture, agent-automatable) = create-yourself lite, turns any donor topology into original designs; (c) TRUE AUTHORING on owned UBC Source body .blends = the pipeline proper. GUARANTEE: the colorable uniform and black suit (no donor exists in any pack) are built via route (c) as the authoring pipeline''s end-to-end proof — non-negotiable deliverable of this ticket, so the pipeline exists even if Synty covers everything else. Spike status: extraction done inline by lead (158 FBX, sci-fi civilian theme confirmed); DECISIVE finding — Sidekick rig is UE-Mannequin-named, 52/65 bone-name overlap with our rig, sample garment binds to 12 vgroups of which 11 match ours exactly (only head->Head case rename) => transplant likely rename-and-rebind, far cheaper than the weight-transfer the pivot eval assumed; body blend shapes travel in the FBX. Transplant phase parked pending API recovery / token-window reset.
|
||
|
||
ROUTE DECISION (user, 2026-07-06, final): Synty intake REJECTED despite the spike''s technical PASS — (1) USD199.99/pack is too expensive; (2) Sidekick modularity is baked body-segment swap (clothes fused to body chunks), incompatible with our layered clothing-over-body system (11 bodies, skin tones, slot swapping); (3) user dislikes the Synty style. The spike still paid: transplant/batch scripts are source-agnostic and become the G1-family production pipeline; T-1090 (5 bodies broken bare) discovered; the Synty question is closed with evidence, not parked. OPERATIVE ROUTE: (b) derive from owned Fantasy parts + (c) hand-author — with a new preferred authoring technique: OFFSET-SHELL FROM OUR OWN BODY MESHES (extract body segment surface, offset outward into garment shell, cut neckline/hem/sleeves; weights inherited by construction, style fully ours, USD0). Suit + uniform remain the full hand-author proof. Purchases still open (separate concerns): UAL1/UAL2 Source ~USD30 for animation clips; Fantasy Outfits Source USD20 low-priority convenience.
|
||
|
||
Chromakey garment-QA harness DELIVERED (2026-07-06, commits eaca6c8c4/74fa16260/b09a50efb): two-pass depth-proximity clip detection — pass A keys covered body segments magenta, pass B re-renders garment-only with a depth-only 3cm epsilon bias toward camera; analyzer splits key pixels into exposed_skin (informational — sleeveless arms, collars) vs clip_through (gating — skin within 3cm in front of cloth). Run: tooling/garment-qa/run-garment-qa <config>. Verified on the peasant set (avg_m/f x Walk/Sprint/Crouch_Fwd x 3 frames x 4 yaws): 0/18 front-view false positives; genuine findings = sleeveless armhole seam (avg_f, sides), deep-crouch waist gap (worst 150px, back), collar nape. First real fit observations already on record for the peasant set. Sensitivity: clip_epsilon_m + --min-pixels, to calibrate against the first modern garments. This is the acceptance gate for every garment the wardrobe pipeline produces; pair with the T-1088 sandbox for in-world walk QA.', NULL, '2026-07-06 12:59:45', '2026-07-06 12:59:45.213', '2026-07-06 12:59:45.213', NULL, 'd416d57aec826414cd29d739238749cf', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKCER95EK266H8RWPW8XT1F0', 'description', 'Fable-5-window sidequest (sanctioned cascade exception, 2026-07-05): the presentation layer that turns discrete server tile steps into a believable walking 3D character. Scope: 3D sandbox dev scene (SR_LIVE=1, greybox tiles derived from server snapshots, no hand-authored map), CharacterVisual instantiated in-world, locomotion rig (tile-step + facing-octant interpolation, stance-aware speeds), UAL animation state machine (idle/walk/sprint/careful/crouch), D-148 camera rig (30deg low-angle follow, 45deg rotation). Server-authoritative from day one — no client-local movement model. Builds on D-148/D-149/D-244/D-066 and the T-417 stance system. If the Fable 5 window closes mid-flight, work parks here.
|
||
|
||
Visual reference (user, 2026-07-06): Xenonauts 2 nails the target tiles/occlusion/character perspective — readable tile grid, low-angle tactical camera with angle options (matches D-148 30deg low-angle + 45deg rotation steps and the spikes/3dpipeline angle presets), and crucially its wall/roof occlusion treatment: camera-facing walls cut down/ghosted so interiors stay readable, floors peel per z-level. One deliberate difference: our camera locks to the player character (D-015/T-116) — no free map panning. Implication for the locomotion sandbox: greybox walls should prototype camera-facing cutaway occlusion early, since wall readability interacts with the locked low-angle camera.
|
||
|
||
Scoping call (user + lead agreement, 2026-07-06): wall cutaway is CLIENT-SIDE presentation, decoupled from fog-of-perception. Rationale: two occlusion systems with different subjects — perception/fog governs what the CHARACTER knows (server-enforced info boundary; client only receives observer-filtered geometry), cutaway governs what the PLAYER''S CAMERA sees (pure render mode on wall data the client already holds). They compose: cutaway cuts render height; fog overlay still gates what is visible behind. Walls remain first-class client data objects (future destruction/explosion interactions), cutaway is a render mode on them like tint/LOD. Nuance parked for Phase 5 proper: destroyed-while-unobserved walls should render in remembered state (fog-memory applied to geometry). If this holds through implementation, mint a D-record (perception domain) when the sidequest lands.
|
||
|
||
Animation supply resolved (2026-07-06): user purchased UAL1[Source+Pro] (120 clips, identical lists) + UAL2[Source] (134 clips), unzipped in docs/assets/downloads/. Gains: Turn90_L/R + Turn180_L/R (turn-in-place), Sprint_Enter/Exit + Crouch_Enter/Exit (stance transitions), full 8-direction Walk/Jog/Crouch sets incl. diagonals, Counter_Idle + talking/phone/sitting idles (life-sim verbs), plus _RM root-motion variants (unused — in-place is correct for server-authoritative interpolation). Still absent everywhere: walk start/stop + stairs — the only remaining custom clips. Integration is NOT a drop-in swap: upstream renamed clips (Walk_Loop -> Walk_Fwd_Loop etc.), so wire via the design''s recorded plan — explicit library names + lib/Clip addressing + gait-table update. NOTE for facing design: the 8-dir walk sets unlock Q-084''s parked walk-vs-aim split (direction-matched clips relative to facing) — revisit during the S9 tuning session.', 'Fable-5-window sidequest (sanctioned cascade exception, 2026-07-05): the presentation layer that turns discrete server tile steps into a believable walking 3D character. Scope: 3D sandbox dev scene (SR_LIVE=1, greybox tiles derived from server snapshots, no hand-authored map), CharacterVisual instantiated in-world, locomotion rig (tile-step + facing-octant interpolation, stance-aware speeds), UAL animation state machine (idle/walk/sprint/careful/crouch), D-148 camera rig (30deg low-angle follow, 45deg rotation). Server-authoritative from day one — no client-local movement model. Builds on D-148/D-149/D-244/D-066 and the T-417 stance system. If the Fable 5 window closes mid-flight, work parks here.
|
||
|
||
Visual reference (user, 2026-07-06): Xenonauts 2 nails the target tiles/occlusion/character perspective — readable tile grid, low-angle tactical camera with angle options (matches D-148 30deg low-angle + 45deg rotation steps and the spikes/3dpipeline angle presets), and crucially its wall/roof occlusion treatment: camera-facing walls cut down/ghosted so interiors stay readable, floors peel per z-level. One deliberate difference: our camera locks to the player character (D-015/T-116) — no free map panning. Implication for the locomotion sandbox: greybox walls should prototype camera-facing cutaway occlusion early, since wall readability interacts with the locked low-angle camera.
|
||
|
||
Scoping call (user + lead agreement, 2026-07-06): wall cutaway is CLIENT-SIDE presentation, decoupled from fog-of-perception. Rationale: two occlusion systems with different subjects — perception/fog governs what the CHARACTER knows (server-enforced info boundary; client only receives observer-filtered geometry), cutaway governs what the PLAYER''S CAMERA sees (pure render mode on wall data the client already holds). They compose: cutaway cuts render height; fog overlay still gates what is visible behind. Walls remain first-class client data objects (future destruction/explosion interactions), cutaway is a render mode on them like tint/LOD. Nuance parked for Phase 5 proper: destroyed-while-unobserved walls should render in remembered state (fog-memory applied to geometry). If this holds through implementation, mint a D-record (perception domain) when the sidequest lands.
|
||
|
||
Animation supply resolved (2026-07-06): user purchased UAL1[Source+Pro] (120 clips, identical lists) + UAL2[Source] (134 clips), unzipped in docs/assets/downloads/. Gains: Turn90_L/R + Turn180_L/R (turn-in-place), Sprint_Enter/Exit + Crouch_Enter/Exit (stance transitions), full 8-direction Walk/Jog/Crouch sets incl. diagonals, Counter_Idle + talking/phone/sitting idles (life-sim verbs), plus _RM root-motion variants (unused — in-place is correct for server-authoritative interpolation). Still absent everywhere: walk start/stop + stairs — the only remaining custom clips. Integration is NOT a drop-in swap: upstream renamed clips (Walk_Loop -> Walk_Fwd_Loop etc.), so wire via the design''s recorded plan — explicit library names + lib/Clip addressing + gait-table update. NOTE for facing design: the 8-dir walk sets unlock Q-084''s parked walk-vs-aim split (direction-matched clips relative to facing) — revisit during the S9 tuning session.
|
||
|
||
Live-session feedback (user, 2026-07-06): (1) Corridor cutaway verdict — two minds: ''extremely trippy, could be the game''s own look'' vs ''player cannot see what is in the room unless close''. Resolution: cutaway MODES, toggled live in the sandbox (corridor / bottom-walls-low / both) — bottom-wall rule is data-driven (wall drops to stub when a KNOWN floor tile sits on its camera-far side; camera-facing directions derived from WorldRoot basis at runtime, not hand-derived). Default picked by feel during the session; the trippy corridor stays available as a signature-look option. (2) NEW: mouse-over move-here marker on the hovered tile + optimal path line — client-side A* over the never-evict KNOWN tile store (info-boundary-honest: the character plans only through known tiles; fog is unpathable), 8-dir with diagonal step cost 1 (time-optimal per the no-sqrt2 wire), terrain-cost provider seam (uniform today, Phase-4 terrain later), click executes by streaming ordinary Move* step commands through the existing throttle (zero protocol change, server validates every step), cancelled by WASD override / path invalidation / arrival. Settles more of Q-084 (click-to-move half).', NULL, '2026-07-06 17:12:09', '2026-07-06 17:12:09.008', '2026-07-06 17:12:09.008', NULL, 'c973d0c7b4460d39520d95a4693a87d0', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKCER95EK266H8RWPW8XT1F0', 'description', 'Fable-5-window sidequest (sanctioned cascade exception, 2026-07-05): the presentation layer that turns discrete server tile steps into a believable walking 3D character. Scope: 3D sandbox dev scene (SR_LIVE=1, greybox tiles derived from server snapshots, no hand-authored map), CharacterVisual instantiated in-world, locomotion rig (tile-step + facing-octant interpolation, stance-aware speeds), UAL animation state machine (idle/walk/sprint/careful/crouch), D-148 camera rig (30deg low-angle follow, 45deg rotation). Server-authoritative from day one — no client-local movement model. Builds on D-148/D-149/D-244/D-066 and the T-417 stance system. If the Fable 5 window closes mid-flight, work parks here.
|
||
|
||
Visual reference (user, 2026-07-06): Xenonauts 2 nails the target tiles/occlusion/character perspective — readable tile grid, low-angle tactical camera with angle options (matches D-148 30deg low-angle + 45deg rotation steps and the spikes/3dpipeline angle presets), and crucially its wall/roof occlusion treatment: camera-facing walls cut down/ghosted so interiors stay readable, floors peel per z-level. One deliberate difference: our camera locks to the player character (D-015/T-116) — no free map panning. Implication for the locomotion sandbox: greybox walls should prototype camera-facing cutaway occlusion early, since wall readability interacts with the locked low-angle camera.
|
||
|
||
Scoping call (user + lead agreement, 2026-07-06): wall cutaway is CLIENT-SIDE presentation, decoupled from fog-of-perception. Rationale: two occlusion systems with different subjects — perception/fog governs what the CHARACTER knows (server-enforced info boundary; client only receives observer-filtered geometry), cutaway governs what the PLAYER''S CAMERA sees (pure render mode on wall data the client already holds). They compose: cutaway cuts render height; fog overlay still gates what is visible behind. Walls remain first-class client data objects (future destruction/explosion interactions), cutaway is a render mode on them like tint/LOD. Nuance parked for Phase 5 proper: destroyed-while-unobserved walls should render in remembered state (fog-memory applied to geometry). If this holds through implementation, mint a D-record (perception domain) when the sidequest lands.
|
||
|
||
Animation supply resolved (2026-07-06): user purchased UAL1[Source+Pro] (120 clips, identical lists) + UAL2[Source] (134 clips), unzipped in docs/assets/downloads/. Gains: Turn90_L/R + Turn180_L/R (turn-in-place), Sprint_Enter/Exit + Crouch_Enter/Exit (stance transitions), full 8-direction Walk/Jog/Crouch sets incl. diagonals, Counter_Idle + talking/phone/sitting idles (life-sim verbs), plus _RM root-motion variants (unused — in-place is correct for server-authoritative interpolation). Still absent everywhere: walk start/stop + stairs — the only remaining custom clips. Integration is NOT a drop-in swap: upstream renamed clips (Walk_Loop -> Walk_Fwd_Loop etc.), so wire via the design''s recorded plan — explicit library names + lib/Clip addressing + gait-table update. NOTE for facing design: the 8-dir walk sets unlock Q-084''s parked walk-vs-aim split (direction-matched clips relative to facing) — revisit during the S9 tuning session.
|
||
|
||
Live-session feedback (user, 2026-07-06): (1) Corridor cutaway verdict — two minds: ''extremely trippy, could be the game''s own look'' vs ''player cannot see what is in the room unless close''. Resolution: cutaway MODES, toggled live in the sandbox (corridor / bottom-walls-low / both) — bottom-wall rule is data-driven (wall drops to stub when a KNOWN floor tile sits on its camera-far side; camera-facing directions derived from WorldRoot basis at runtime, not hand-derived). Default picked by feel during the session; the trippy corridor stays available as a signature-look option. (2) NEW: mouse-over move-here marker on the hovered tile + optimal path line — client-side A* over the never-evict KNOWN tile store (info-boundary-honest: the character plans only through known tiles; fog is unpathable), 8-dir with diagonal step cost 1 (time-optimal per the no-sqrt2 wire), terrain-cost provider seam (uniform today, Phase-4 terrain later), click executes by streaming ordinary Move* step commands through the existing throttle (zero protocol change, server validates every step), cancelled by WASD override / path invalidation / arrival. Settles more of Q-084 (click-to-move half).', 'Fable-5-window sidequest (sanctioned cascade exception, 2026-07-05): the presentation layer that turns discrete server tile steps into a believable walking 3D character. Scope: 3D sandbox dev scene (SR_LIVE=1, greybox tiles derived from server snapshots, no hand-authored map), CharacterVisual instantiated in-world, locomotion rig (tile-step + facing-octant interpolation, stance-aware speeds), UAL animation state machine (idle/walk/sprint/careful/crouch), D-148 camera rig (30deg low-angle follow, 45deg rotation). Server-authoritative from day one — no client-local movement model. Builds on D-148/D-149/D-244/D-066 and the T-417 stance system. If the Fable 5 window closes mid-flight, work parks here.
|
||
|
||
Visual reference (user, 2026-07-06): Xenonauts 2 nails the target tiles/occlusion/character perspective — readable tile grid, low-angle tactical camera with angle options (matches D-148 30deg low-angle + 45deg rotation steps and the spikes/3dpipeline angle presets), and crucially its wall/roof occlusion treatment: camera-facing walls cut down/ghosted so interiors stay readable, floors peel per z-level. One deliberate difference: our camera locks to the player character (D-015/T-116) — no free map panning. Implication for the locomotion sandbox: greybox walls should prototype camera-facing cutaway occlusion early, since wall readability interacts with the locked low-angle camera.
|
||
|
||
Scoping call (user + lead agreement, 2026-07-06): wall cutaway is CLIENT-SIDE presentation, decoupled from fog-of-perception. Rationale: two occlusion systems with different subjects — perception/fog governs what the CHARACTER knows (server-enforced info boundary; client only receives observer-filtered geometry), cutaway governs what the PLAYER''S CAMERA sees (pure render mode on wall data the client already holds). They compose: cutaway cuts render height; fog overlay still gates what is visible behind. Walls remain first-class client data objects (future destruction/explosion interactions), cutaway is a render mode on them like tint/LOD. Nuance parked for Phase 5 proper: destroyed-while-unobserved walls should render in remembered state (fog-memory applied to geometry). If this holds through implementation, mint a D-record (perception domain) when the sidequest lands.
|
||
|
||
Animation supply resolved (2026-07-06): user purchased UAL1[Source+Pro] (120 clips, identical lists) + UAL2[Source] (134 clips), unzipped in docs/assets/downloads/. Gains: Turn90_L/R + Turn180_L/R (turn-in-place), Sprint_Enter/Exit + Crouch_Enter/Exit (stance transitions), full 8-direction Walk/Jog/Crouch sets incl. diagonals, Counter_Idle + talking/phone/sitting idles (life-sim verbs), plus _RM root-motion variants (unused — in-place is correct for server-authoritative interpolation). Still absent everywhere: walk start/stop + stairs — the only remaining custom clips. Integration is NOT a drop-in swap: upstream renamed clips (Walk_Loop -> Walk_Fwd_Loop etc.), so wire via the design''s recorded plan — explicit library names + lib/Clip addressing + gait-table update. NOTE for facing design: the 8-dir walk sets unlock Q-084''s parked walk-vs-aim split (direction-matched clips relative to facing) — revisit during the S9 tuning session.
|
||
|
||
Live-session feedback (user, 2026-07-06): (1) Corridor cutaway verdict — two minds: ''extremely trippy, could be the game''s own look'' vs ''player cannot see what is in the room unless close''. Resolution: cutaway MODES, toggled live in the sandbox (corridor / bottom-walls-low / both) — bottom-wall rule is data-driven (wall drops to stub when a KNOWN floor tile sits on its camera-far side; camera-facing directions derived from WorldRoot basis at runtime, not hand-derived). Default picked by feel during the session; the trippy corridor stays available as a signature-look option. (2) NEW: mouse-over move-here marker on the hovered tile + optimal path line — client-side A* over the never-evict KNOWN tile store (info-boundary-honest: the character plans only through known tiles; fog is unpathable), 8-dir with diagonal step cost 1 (time-optimal per the no-sqrt2 wire), terrain-cost provider seam (uniform today, Phase-4 terrain later), click executes by streaming ordinary Move* step commands through the existing throttle (zero protocol change, server validates every step), cancelled by WASD override / path invalidation / arrival. Settles more of Q-084 (click-to-move half).
|
||
|
||
RMB gesture vocabulary (user, live session 2026-07-06, added to the path-preview feature): single right-click = walk there (current stance); DOUBLE right-click = sprint there (ladder ToggleStanceUp burst to Sprint via the ordinary command queue, pre-sprint stance RESTORED on arrival; a double upgrades the already-started follow in place); LONG-PRESS right-click (~0.4s, commit on release) = ''take cover at location'', prototyped as go-there-then-Crouch-on-arrival (no restore — crouching was the point). Real cover mechanics (wall adjacency, directional protection) are future combat design; the gesture is the input-vocabulary prototype. WASD always cancels any follow without stance restore (player override is deliberate).', NULL, '2026-07-06 17:37:13', '2026-07-06 17:37:13.480', '2026-07-06 17:37:13.480', NULL, '32dbbffd0e953374ed22104cae0e636c', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKCER95EK266H8RWPW8XT1F0', 'description', 'Fable-5-window sidequest (sanctioned cascade exception, 2026-07-05): the presentation layer that turns discrete server tile steps into a believable walking 3D character. Scope: 3D sandbox dev scene (SR_LIVE=1, greybox tiles derived from server snapshots, no hand-authored map), CharacterVisual instantiated in-world, locomotion rig (tile-step + facing-octant interpolation, stance-aware speeds), UAL animation state machine (idle/walk/sprint/careful/crouch), D-148 camera rig (30deg low-angle follow, 45deg rotation). Server-authoritative from day one — no client-local movement model. Builds on D-148/D-149/D-244/D-066 and the T-417 stance system. If the Fable 5 window closes mid-flight, work parks here.
|
||
|
||
Visual reference (user, 2026-07-06): Xenonauts 2 nails the target tiles/occlusion/character perspective — readable tile grid, low-angle tactical camera with angle options (matches D-148 30deg low-angle + 45deg rotation steps and the spikes/3dpipeline angle presets), and crucially its wall/roof occlusion treatment: camera-facing walls cut down/ghosted so interiors stay readable, floors peel per z-level. One deliberate difference: our camera locks to the player character (D-015/T-116) — no free map panning. Implication for the locomotion sandbox: greybox walls should prototype camera-facing cutaway occlusion early, since wall readability interacts with the locked low-angle camera.
|
||
|
||
Scoping call (user + lead agreement, 2026-07-06): wall cutaway is CLIENT-SIDE presentation, decoupled from fog-of-perception. Rationale: two occlusion systems with different subjects — perception/fog governs what the CHARACTER knows (server-enforced info boundary; client only receives observer-filtered geometry), cutaway governs what the PLAYER''S CAMERA sees (pure render mode on wall data the client already holds). They compose: cutaway cuts render height; fog overlay still gates what is visible behind. Walls remain first-class client data objects (future destruction/explosion interactions), cutaway is a render mode on them like tint/LOD. Nuance parked for Phase 5 proper: destroyed-while-unobserved walls should render in remembered state (fog-memory applied to geometry). If this holds through implementation, mint a D-record (perception domain) when the sidequest lands.
|
||
|
||
Animation supply resolved (2026-07-06): user purchased UAL1[Source+Pro] (120 clips, identical lists) + UAL2[Source] (134 clips), unzipped in docs/assets/downloads/. Gains: Turn90_L/R + Turn180_L/R (turn-in-place), Sprint_Enter/Exit + Crouch_Enter/Exit (stance transitions), full 8-direction Walk/Jog/Crouch sets incl. diagonals, Counter_Idle + talking/phone/sitting idles (life-sim verbs), plus _RM root-motion variants (unused — in-place is correct for server-authoritative interpolation). Still absent everywhere: walk start/stop + stairs — the only remaining custom clips. Integration is NOT a drop-in swap: upstream renamed clips (Walk_Loop -> Walk_Fwd_Loop etc.), so wire via the design''s recorded plan — explicit library names + lib/Clip addressing + gait-table update. NOTE for facing design: the 8-dir walk sets unlock Q-084''s parked walk-vs-aim split (direction-matched clips relative to facing) — revisit during the S9 tuning session.
|
||
|
||
Live-session feedback (user, 2026-07-06): (1) Corridor cutaway verdict — two minds: ''extremely trippy, could be the game''s own look'' vs ''player cannot see what is in the room unless close''. Resolution: cutaway MODES, toggled live in the sandbox (corridor / bottom-walls-low / both) — bottom-wall rule is data-driven (wall drops to stub when a KNOWN floor tile sits on its camera-far side; camera-facing directions derived from WorldRoot basis at runtime, not hand-derived). Default picked by feel during the session; the trippy corridor stays available as a signature-look option. (2) NEW: mouse-over move-here marker on the hovered tile + optimal path line — client-side A* over the never-evict KNOWN tile store (info-boundary-honest: the character plans only through known tiles; fog is unpathable), 8-dir with diagonal step cost 1 (time-optimal per the no-sqrt2 wire), terrain-cost provider seam (uniform today, Phase-4 terrain later), click executes by streaming ordinary Move* step commands through the existing throttle (zero protocol change, server validates every step), cancelled by WASD override / path invalidation / arrival. Settles more of Q-084 (click-to-move half).
|
||
|
||
RMB gesture vocabulary (user, live session 2026-07-06, added to the path-preview feature): single right-click = walk there (current stance); DOUBLE right-click = sprint there (ladder ToggleStanceUp burst to Sprint via the ordinary command queue, pre-sprint stance RESTORED on arrival; a double upgrades the already-started follow in place); LONG-PRESS right-click (~0.4s, commit on release) = ''take cover at location'', prototyped as go-there-then-Crouch-on-arrival (no restore — crouching was the point). Real cover mechanics (wall adjacency, directional protection) are future combat design; the gesture is the input-vocabulary prototype. WASD always cancels any follow without stance restore (player override is deliberate).', 'Fable-5-window sidequest (sanctioned cascade exception, 2026-07-05): the presentation layer that turns discrete server tile steps into a believable walking 3D character. Scope: 3D sandbox dev scene (SR_LIVE=1, greybox tiles derived from server snapshots, no hand-authored map), CharacterVisual instantiated in-world, locomotion rig (tile-step + facing-octant interpolation, stance-aware speeds), UAL animation state machine (idle/walk/sprint/careful/crouch), D-148 camera rig (30deg low-angle follow, 45deg rotation). Server-authoritative from day one — no client-local movement model. Builds on D-148/D-149/D-244/D-066 and the T-417 stance system. If the Fable 5 window closes mid-flight, work parks here.
|
||
|
||
Visual reference (user, 2026-07-06): Xenonauts 2 nails the target tiles/occlusion/character perspective — readable tile grid, low-angle tactical camera with angle options (matches D-148 30deg low-angle + 45deg rotation steps and the spikes/3dpipeline angle presets), and crucially its wall/roof occlusion treatment: camera-facing walls cut down/ghosted so interiors stay readable, floors peel per z-level. One deliberate difference: our camera locks to the player character (D-015/T-116) — no free map panning. Implication for the locomotion sandbox: greybox walls should prototype camera-facing cutaway occlusion early, since wall readability interacts with the locked low-angle camera.
|
||
|
||
Scoping call (user + lead agreement, 2026-07-06): wall cutaway is CLIENT-SIDE presentation, decoupled from fog-of-perception. Rationale: two occlusion systems with different subjects — perception/fog governs what the CHARACTER knows (server-enforced info boundary; client only receives observer-filtered geometry), cutaway governs what the PLAYER''S CAMERA sees (pure render mode on wall data the client already holds). They compose: cutaway cuts render height; fog overlay still gates what is visible behind. Walls remain first-class client data objects (future destruction/explosion interactions), cutaway is a render mode on them like tint/LOD. Nuance parked for Phase 5 proper: destroyed-while-unobserved walls should render in remembered state (fog-memory applied to geometry). If this holds through implementation, mint a D-record (perception domain) when the sidequest lands.
|
||
|
||
Animation supply resolved (2026-07-06): user purchased UAL1[Source+Pro] (120 clips, identical lists) + UAL2[Source] (134 clips), unzipped in docs/assets/downloads/. Gains: Turn90_L/R + Turn180_L/R (turn-in-place), Sprint_Enter/Exit + Crouch_Enter/Exit (stance transitions), full 8-direction Walk/Jog/Crouch sets incl. diagonals, Counter_Idle + talking/phone/sitting idles (life-sim verbs), plus _RM root-motion variants (unused — in-place is correct for server-authoritative interpolation). Still absent everywhere: walk start/stop + stairs — the only remaining custom clips. Integration is NOT a drop-in swap: upstream renamed clips (Walk_Loop -> Walk_Fwd_Loop etc.), so wire via the design''s recorded plan — explicit library names + lib/Clip addressing + gait-table update. NOTE for facing design: the 8-dir walk sets unlock Q-084''s parked walk-vs-aim split (direction-matched clips relative to facing) — revisit during the S9 tuning session.
|
||
|
||
Live-session feedback (user, 2026-07-06): (1) Corridor cutaway verdict — two minds: ''extremely trippy, could be the game''s own look'' vs ''player cannot see what is in the room unless close''. Resolution: cutaway MODES, toggled live in the sandbox (corridor / bottom-walls-low / both) — bottom-wall rule is data-driven (wall drops to stub when a KNOWN floor tile sits on its camera-far side; camera-facing directions derived from WorldRoot basis at runtime, not hand-derived). Default picked by feel during the session; the trippy corridor stays available as a signature-look option. (2) NEW: mouse-over move-here marker on the hovered tile + optimal path line — client-side A* over the never-evict KNOWN tile store (info-boundary-honest: the character plans only through known tiles; fog is unpathable), 8-dir with diagonal step cost 1 (time-optimal per the no-sqrt2 wire), terrain-cost provider seam (uniform today, Phase-4 terrain later), click executes by streaming ordinary Move* step commands through the existing throttle (zero protocol change, server validates every step), cancelled by WASD override / path invalidation / arrival. Settles more of Q-084 (click-to-move half).
|
||
|
||
RMB gesture vocabulary (user, live session 2026-07-06, added to the path-preview feature): single right-click = walk there (current stance); DOUBLE right-click = sprint there (ladder ToggleStanceUp burst to Sprint via the ordinary command queue, pre-sprint stance RESTORED on arrival; a double upgrades the already-started follow in place); LONG-PRESS right-click (~0.4s, commit on release) = ''take cover at location'', prototyped as go-there-then-Crouch-on-arrival (no restore — crouching was the point). Real cover mechanics (wall adjacency, directional protection) are future combat design; the gesture is the input-vocabulary prototype. WASD always cancels any follow without stance restore (player override is deliberate).
|
||
|
||
Follow-facing refinement (user, live session 2026-07-06): during an RMB path-follow the BODY commits to the leg/movement direction (mouse no longer swings body yaw); the mouse instead drives a LAYERED LOOK-AT — Head bone (~70deg limit) plus torso twist via a spine bone (~30deg) for looking far lateral/behind; beyond their sum the character physically cannot look further without turning (correct). Pure client presentation on the D-249 model; SetFacing continues to ride the wire during follows, so the SERVER vision cone still follows the mouse (diegetic: the character looks where the player points while walking a committed path). Implementation: Godot LookAtModifier3D pair under the CharacterVisual skeleton, influence-faded in/out on follow start/end; rig gains a commit_body_to_motion flag (yaw from leg velocity while set).', NULL, '2026-07-06 18:29:55', '2026-07-06 18:29:55.012', '2026-07-06 18:29:55.012', NULL, '890daaabcde4a85a222f9d206dcda2d0', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKHFRCP5R0VBA9BKR97RRBJ0', 'status', 'backlog', 'in_progress', NULL, '2026-07-06 18:55:29', '2026-07-06 18:55:29.038', '2026-07-06 18:55:29.038', NULL, 'da64cb6b48dd4311c5b257cbd70d891b', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKHFRCP5R0VBA9BKR97RRBJ0', 'status', 'in_progress', 'done', NULL, '2026-07-06 19:18:30', '2026-07-06 19:18:30.658', '2026-07-06 19:18:30.658', NULL, '5bcddf023648706d42815d7aaf08255a', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKE0EW2617K9VE4QHSYSR9HW', 'status', 'backlog', 'in_progress', NULL, '2026-07-06 19:25:35', '2026-07-06 19:25:35.248', '2026-07-06 19:25:35.248', NULL, '8fa2e4eba023cb3ae1577a5f16c9cfd2', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKE0EW2617K9VE4QHSYSR9HW', 'description', 'Found by the T-1089 Synty intake spike (2026-07-06), body-only controls with NO garment attached: thin_f/m, heavy_f/m, child misrender in CharacterVisual (exploded/spider arms, detached head/hair; child 303mm max warp, 87 collapsed edges; f-bodies bust-through). These are the newer high-poly bodies (no seg_hips, different segmentation) — exactly the 5 with no production peasant-clothing variants. Upstream of ANY clothing route; blocks T-1089''s 11-of-11 acceptance criterion and resolves part of Q-060. Evidence: spikes/synty-intake/out/bodies_fit_log.json + out/qa_bodies/ (44 screenshots) + out/bodies_recon.json.', 'Found by the T-1089 Synty intake spike (2026-07-06), body-only controls with NO garment attached: thin_f/m, heavy_f/m, child misrender in CharacterVisual (exploded/spider arms, detached head/hair; child 303mm max warp, 87 collapsed edges; f-bodies bust-through). These are the newer high-poly bodies (no seg_hips, different segmentation) — exactly the 5 with no production peasant-clothing variants. Upstream of ANY clothing route; blocks T-1089''s 11-of-11 acceptance criterion and resolves part of Q-060. Evidence: spikes/synty-intake/out/bodies_fit_log.json + out/qa_bodies/ (44 screenshots) + out/bodies_recon.json.
|
||
|
||
RESOLVED (pending review). Root cause: fork bodies (thin/heavy/child) had a mesh<->armature mismatch. blender_segment_body.py apply_scale scaled mesh vertices ONLY, leaving the embedded armature at source scale; since character_visual.gd binds every segment onto ONE shared skeleton (skeleton/armature.glb) by bone name, each segment must be internally consistent with its own embedded armature — the mesh-only scale dropped the head ~0.35m below the Head bone and flung limbs apart on relocation. thin/heavy were additionally stale high-poly artifacts (torso 1419-1704v vs 375v) missing seg_hips entirely. Fix: replaced apply_scale with apply_fork_scale (tooling/blender_segment_body.py) which scales mesh AND armature together and BAKES via Blender transform_apply (edit-bone poking alone shears connected chains — arms/fingers still exploded). Rebuilt all 5 via new tooling/blender_rebuild_forks.py from Source-tier gltf; now 19 segments incl seg_hips, low-poly matching the healthy six. Bare-body QA (idle+walk, front+side, real CharacterVisual): all 5 coherent, head/hair attached, no explosion; healthy 6 untouched. Q-060: all 3 peasant garments Surface-Deform-fit onto all 5 forks (15/15 surface_deform, 0 shrinkwrap fallback) — Surface Deform HOLDS at the extremes on repaired bodies. No manifest change (body ids/paths unchanged).', NULL, '2026-07-06 20:02:30', '2026-07-06 20:02:30.990', '2026-07-06 20:02:30.990', NULL, '7606f8b27d88884fcb7d4a2e3a5663bb', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKE0EW2617K9VE4QHSYSR9HW', 'status', 'in_progress', 'review', NULL, '2026-07-06 20:02:31', '2026-07-06 20:02:31.013', '2026-07-06 20:02:31.013', NULL, '942bea5d7db30ea972e6ba64341369a1', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKE0EW2617K9VE4QHSYSR9HW', 'status', 'review', 'done', NULL, '2026-07-06 20:06:22', '2026-07-06 20:06:22.078', '2026-07-06 20:06:22.078', NULL, '10bec531a986c8b28b68229637a1297f', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKCPBF41RWK9PW9M22Q7961C', 'description', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.
|
||
|
||
Art direction (user, 2026-07-06): garments read CYBERPUNK/MODERN — near-future everyday civilian + corporate wear — NOT fantasy/medieval. The owned Fantasy pack is at most a topology donor (low-poly base shapes like pants/shirts are genre-neutral; genre lives in silhouette details, textures, trims, and accessories) — no medieval trim/textures may survive into shipped garments. Weight the authoring routes accordingly: texture identity matters as much as mesh. Canon hook: the wiki already ships a garment brand — thrds (wiki/star-systems/GJ-475/index.md, Braemar fiber cooperative, corridor fashion markets) — so branded clothing connects to Phase-1 lore, not only generated_brands.toml. This emphasis also feeds the Quaternius-pivot evaluation: commercial alternatives skew sci-fi/urban while Quaternius clothing is fantasy-only.
|
||
|
||
Nuance (user, 2026-07-06): the cyberpunk/modern direction is the DEFAULT, not a prohibition — fashion in the Reach is cyclical, so fantasy/medieval-flavored garments may appear here and there as deliberate fashion statements (subculture pieces, luxury/revival trims, statement outerwear). Supersedes the previous note''s hard ''no medieval trim may survive'' line. Practical consequence: a small number of Fantasy-pack pieces may ship near-as-is where they read as intentional fashion; the basic set itself stays modern.
|
||
|
||
Art direction CONSOLIDATED (user, 2026-07-06 — supersedes the two notes above): the Reach has no single clothing style — ALL styles coexist, with modern/cyberpunk probably the most prevalent. Style is a prevalence DISTRIBUTION, not a genre rule, and may eventually vary by culture/settlement (fits the simulation DNA; fashion-as-cultural-data is a later phase concern, not this ticket). Consequences now: (1) the engine is style-agnostic by construction (slots/tints/logos carry no genre); (2) the basic set targets the prevalent center — modern casual + corporate — because it dresses the most NPCs and the shopping experience; (3) garments get a lightweight style tag in the manifest (e.g. style: modern|formal|fantasy|utility) as the cheap seam so per-culture distributions can be authored later without retrofitting; (4) Fantasy-pack pieces are legitimate catalogue members under their own tag, prevalence-weighted low.
|
||
|
||
Scope pin (user, 2026-07-06, final word on style): for simplicity, THIS ticket ships ONE style only — cyberpunk/modern. The pluralistic distribution model above remains the long-term truth (keep the manifest style tag as the seam), but the v1 basic set is single-style; other styles are catalogue growth, not scope.
|
||
|
||
Route challenge (user, 2026-07-06): not sold on staying Quaternius-primary — ''Quaternius is limited and will move the wall at too slow a pace; I''d rather pick something that has what we need now.'' Fresh store verification (2026-07-06): Sidekick packs are one-time USD199.99, perpetual, engine-agnostic license (Godot legal, unsupported); NO raw FBX — extraction from unitypackage (community-proven: unitypackage_godot, third-party Sidekick Creator Godot plugin incl. body blend shapes); ''Sold out'' labels are a broken-theme artifact per Shopify JSON (needs one browser cart check); SyntyPass rejected (assets stop being developable after cancel). Relevant packs: Starter (FREE, 57+91 parts), Modern Civilians (165 parts = v1 basic set territory), Sci-Fi Civilians (103 parts, cyberpunk accents), Modern Police (uniforms/officials). DECISION NOW GATED ON THE FREE SPIKE: user downloads free Starter Pack -> Bridge-C spike (extract garment -> Robust Weight Transfer onto our rig -> 11-body batch -> animation QA in T-1088 sandbox). Pass -> buy Modern Civilians, Synty = primary garment supply (+UAL1/UAL2 Source ~USD30 for clips — no Synty substitute exists for Godot animations; Fantasy Outfits Source drops to low priority under the single-style pin). Fail -> hand-author route stands. Stay-vs-pivot governance record HELD until spike evidence lands.
|
||
|
||
Scope guard (user concern, 2026-07-06): Synty intake must NOT displace the create-stuff-yourself pipeline — the user''s goal includes in-house garment creation capability, not just swapping vendor catalogs. Resolution: three-route portfolio sharing one engine — (a) Synty intake = variety bootstrap only; (b) derivation scripting (cuts/merges/retexture, agent-automatable) = create-yourself lite, turns any donor topology into original designs; (c) TRUE AUTHORING on owned UBC Source body .blends = the pipeline proper. GUARANTEE: the colorable uniform and black suit (no donor exists in any pack) are built via route (c) as the authoring pipeline''s end-to-end proof — non-negotiable deliverable of this ticket, so the pipeline exists even if Synty covers everything else. Spike status: extraction done inline by lead (158 FBX, sci-fi civilian theme confirmed); DECISIVE finding — Sidekick rig is UE-Mannequin-named, 52/65 bone-name overlap with our rig, sample garment binds to 12 vgroups of which 11 match ours exactly (only head->Head case rename) => transplant likely rename-and-rebind, far cheaper than the weight-transfer the pivot eval assumed; body blend shapes travel in the FBX. Transplant phase parked pending API recovery / token-window reset.
|
||
|
||
ROUTE DECISION (user, 2026-07-06, final): Synty intake REJECTED despite the spike''s technical PASS — (1) USD199.99/pack is too expensive; (2) Sidekick modularity is baked body-segment swap (clothes fused to body chunks), incompatible with our layered clothing-over-body system (11 bodies, skin tones, slot swapping); (3) user dislikes the Synty style. The spike still paid: transplant/batch scripts are source-agnostic and become the G1-family production pipeline; T-1090 (5 bodies broken bare) discovered; the Synty question is closed with evidence, not parked. OPERATIVE ROUTE: (b) derive from owned Fantasy parts + (c) hand-author — with a new preferred authoring technique: OFFSET-SHELL FROM OUR OWN BODY MESHES (extract body segment surface, offset outward into garment shell, cut neckline/hem/sleeves; weights inherited by construction, style fully ours, USD0). Suit + uniform remain the full hand-author proof. Purchases still open (separate concerns): UAL1/UAL2 Source ~USD30 for animation clips; Fantasy Outfits Source USD20 low-priority convenience.
|
||
|
||
Chromakey garment-QA harness DELIVERED (2026-07-06, commits eaca6c8c4/74fa16260/b09a50efb): two-pass depth-proximity clip detection — pass A keys covered body segments magenta, pass B re-renders garment-only with a depth-only 3cm epsilon bias toward camera; analyzer splits key pixels into exposed_skin (informational — sleeveless arms, collars) vs clip_through (gating — skin within 3cm in front of cloth). Run: tooling/garment-qa/run-garment-qa <config>. Verified on the peasant set (avg_m/f x Walk/Sprint/Crouch_Fwd x 3 frames x 4 yaws): 0/18 front-view false positives; genuine findings = sleeveless armhole seam (avg_f, sides), deep-crouch waist gap (worst 150px, back), collar nape. First real fit observations already on record for the peasant set. Sensitivity: clip_epsilon_m + --min-pixels, to calibrate against the first modern garments. This is the acceptance gate for every garment the wardrobe pipeline produces; pair with the T-1088 sandbox for in-world walk QA.', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.
|
||
|
||
Art direction (user, 2026-07-06): garments read CYBERPUNK/MODERN — near-future everyday civilian + corporate wear — NOT fantasy/medieval. The owned Fantasy pack is at most a topology donor (low-poly base shapes like pants/shirts are genre-neutral; genre lives in silhouette details, textures, trims, and accessories) — no medieval trim/textures may survive into shipped garments. Weight the authoring routes accordingly: texture identity matters as much as mesh. Canon hook: the wiki already ships a garment brand — thrds (wiki/star-systems/GJ-475/index.md, Braemar fiber cooperative, corridor fashion markets) — so branded clothing connects to Phase-1 lore, not only generated_brands.toml. This emphasis also feeds the Quaternius-pivot evaluation: commercial alternatives skew sci-fi/urban while Quaternius clothing is fantasy-only.
|
||
|
||
Nuance (user, 2026-07-06): the cyberpunk/modern direction is the DEFAULT, not a prohibition — fashion in the Reach is cyclical, so fantasy/medieval-flavored garments may appear here and there as deliberate fashion statements (subculture pieces, luxury/revival trims, statement outerwear). Supersedes the previous note''s hard ''no medieval trim may survive'' line. Practical consequence: a small number of Fantasy-pack pieces may ship near-as-is where they read as intentional fashion; the basic set itself stays modern.
|
||
|
||
Art direction CONSOLIDATED (user, 2026-07-06 — supersedes the two notes above): the Reach has no single clothing style — ALL styles coexist, with modern/cyberpunk probably the most prevalent. Style is a prevalence DISTRIBUTION, not a genre rule, and may eventually vary by culture/settlement (fits the simulation DNA; fashion-as-cultural-data is a later phase concern, not this ticket). Consequences now: (1) the engine is style-agnostic by construction (slots/tints/logos carry no genre); (2) the basic set targets the prevalent center — modern casual + corporate — because it dresses the most NPCs and the shopping experience; (3) garments get a lightweight style tag in the manifest (e.g. style: modern|formal|fantasy|utility) as the cheap seam so per-culture distributions can be authored later without retrofitting; (4) Fantasy-pack pieces are legitimate catalogue members under their own tag, prevalence-weighted low.
|
||
|
||
Scope pin (user, 2026-07-06, final word on style): for simplicity, THIS ticket ships ONE style only — cyberpunk/modern. The pluralistic distribution model above remains the long-term truth (keep the manifest style tag as the seam), but the v1 basic set is single-style; other styles are catalogue growth, not scope.
|
||
|
||
Route challenge (user, 2026-07-06): not sold on staying Quaternius-primary — ''Quaternius is limited and will move the wall at too slow a pace; I''d rather pick something that has what we need now.'' Fresh store verification (2026-07-06): Sidekick packs are one-time USD199.99, perpetual, engine-agnostic license (Godot legal, unsupported); NO raw FBX — extraction from unitypackage (community-proven: unitypackage_godot, third-party Sidekick Creator Godot plugin incl. body blend shapes); ''Sold out'' labels are a broken-theme artifact per Shopify JSON (needs one browser cart check); SyntyPass rejected (assets stop being developable after cancel). Relevant packs: Starter (FREE, 57+91 parts), Modern Civilians (165 parts = v1 basic set territory), Sci-Fi Civilians (103 parts, cyberpunk accents), Modern Police (uniforms/officials). DECISION NOW GATED ON THE FREE SPIKE: user downloads free Starter Pack -> Bridge-C spike (extract garment -> Robust Weight Transfer onto our rig -> 11-body batch -> animation QA in T-1088 sandbox). Pass -> buy Modern Civilians, Synty = primary garment supply (+UAL1/UAL2 Source ~USD30 for clips — no Synty substitute exists for Godot animations; Fantasy Outfits Source drops to low priority under the single-style pin). Fail -> hand-author route stands. Stay-vs-pivot governance record HELD until spike evidence lands.
|
||
|
||
Scope guard (user concern, 2026-07-06): Synty intake must NOT displace the create-stuff-yourself pipeline — the user''s goal includes in-house garment creation capability, not just swapping vendor catalogs. Resolution: three-route portfolio sharing one engine — (a) Synty intake = variety bootstrap only; (b) derivation scripting (cuts/merges/retexture, agent-automatable) = create-yourself lite, turns any donor topology into original designs; (c) TRUE AUTHORING on owned UBC Source body .blends = the pipeline proper. GUARANTEE: the colorable uniform and black suit (no donor exists in any pack) are built via route (c) as the authoring pipeline''s end-to-end proof — non-negotiable deliverable of this ticket, so the pipeline exists even if Synty covers everything else. Spike status: extraction done inline by lead (158 FBX, sci-fi civilian theme confirmed); DECISIVE finding — Sidekick rig is UE-Mannequin-named, 52/65 bone-name overlap with our rig, sample garment binds to 12 vgroups of which 11 match ours exactly (only head->Head case rename) => transplant likely rename-and-rebind, far cheaper than the weight-transfer the pivot eval assumed; body blend shapes travel in the FBX. Transplant phase parked pending API recovery / token-window reset.
|
||
|
||
ROUTE DECISION (user, 2026-07-06, final): Synty intake REJECTED despite the spike''s technical PASS — (1) USD199.99/pack is too expensive; (2) Sidekick modularity is baked body-segment swap (clothes fused to body chunks), incompatible with our layered clothing-over-body system (11 bodies, skin tones, slot swapping); (3) user dislikes the Synty style. The spike still paid: transplant/batch scripts are source-agnostic and become the G1-family production pipeline; T-1090 (5 bodies broken bare) discovered; the Synty question is closed with evidence, not parked. OPERATIVE ROUTE: (b) derive from owned Fantasy parts + (c) hand-author — with a new preferred authoring technique: OFFSET-SHELL FROM OUR OWN BODY MESHES (extract body segment surface, offset outward into garment shell, cut neckline/hem/sleeves; weights inherited by construction, style fully ours, USD0). Suit + uniform remain the full hand-author proof. Purchases still open (separate concerns): UAL1/UAL2 Source ~USD30 for animation clips; Fantasy Outfits Source USD20 low-priority convenience.
|
||
|
||
Chromakey garment-QA harness DELIVERED (2026-07-06, commits eaca6c8c4/74fa16260/b09a50efb): two-pass depth-proximity clip detection — pass A keys covered body segments magenta, pass B re-renders garment-only with a depth-only 3cm epsilon bias toward camera; analyzer splits key pixels into exposed_skin (informational — sleeveless arms, collars) vs clip_through (gating — skin within 3cm in front of cloth). Run: tooling/garment-qa/run-garment-qa <config>. Verified on the peasant set (avg_m/f x Walk/Sprint/Crouch_Fwd x 3 frames x 4 yaws): 0/18 front-view false positives; genuine findings = sleeveless armhole seam (avg_f, sides), deep-crouch waist gap (worst 150px, back), collar nape. First real fit observations already on record for the peasant set. Sensitivity: clip_epsilon_m + --min-pixels, to calibrate against the first modern garments. This is the acceptance gate for every garment the wardrobe pipeline produces; pair with the T-1088 sandbox for in-world walk QA.
|
||
|
||
ENGINE DELIVERED (2026-07-06, commits e22ea0fa4 + 278e8b7c2; earlier eaca6c8c4/74fa16260/b09a50efb chromakey, b54b8189d bodies): G1 skinned batch-fit (blender_batch_fit_skinned.py), offset-shell authoring (blender_author_offset_shell.py — route c create-yourself, weights by construction, procedural RGBA masks, UV2 chest channel), toon_garment.gdshader (channel-blended 4-region tint + logo after-tint/before-toon), compositor plumb (multi_region coverage flag -> garment shader; descriptor clothing_logos: per-character brand choice), thrds logo stub, manifest style tag + logo_capable. PROOF: tshirt_modern on 6 healthy bodies, 18-assertion suite green, 216-capture chromakey QA. ROUTE GUIDANCE from QA evidence (Q-060): single-reference SD-fit of offset-shells degrades with girth divergence (muscular_m worst 859px clip at 24mm standoff; reference body clean) — offset-shell garments should be authored PER BODY (needs per-body masks + runtime <body>_mask.png loading, small change); SD-fit remains right for derived/hand-authored garments sharing one mask (suit, uniform, Fantasy cuts). REMAINING for this ticket: refit tshirt to the 5 repaired forks (T-1090 done — add to --only and rerun), per-body shell mode, then the basic set: hoodie, button-down, shorts, jeans, formal pants, jacket + the suit/uniform hand-author proof; creation-screen try-on UI for tints/logos.', NULL, '2026-07-06 20:22:08', '2026-07-06 20:22:08.752', '2026-07-06 20:22:08.752', NULL, 'b2e49bf9d2fcab1df28108db784e8b8f', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKCPBF41RWK9PW9M22Q7961C', 'description', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.
|
||
|
||
Art direction (user, 2026-07-06): garments read CYBERPUNK/MODERN — near-future everyday civilian + corporate wear — NOT fantasy/medieval. The owned Fantasy pack is at most a topology donor (low-poly base shapes like pants/shirts are genre-neutral; genre lives in silhouette details, textures, trims, and accessories) — no medieval trim/textures may survive into shipped garments. Weight the authoring routes accordingly: texture identity matters as much as mesh. Canon hook: the wiki already ships a garment brand — thrds (wiki/star-systems/GJ-475/index.md, Braemar fiber cooperative, corridor fashion markets) — so branded clothing connects to Phase-1 lore, not only generated_brands.toml. This emphasis also feeds the Quaternius-pivot evaluation: commercial alternatives skew sci-fi/urban while Quaternius clothing is fantasy-only.
|
||
|
||
Nuance (user, 2026-07-06): the cyberpunk/modern direction is the DEFAULT, not a prohibition — fashion in the Reach is cyclical, so fantasy/medieval-flavored garments may appear here and there as deliberate fashion statements (subculture pieces, luxury/revival trims, statement outerwear). Supersedes the previous note''s hard ''no medieval trim may survive'' line. Practical consequence: a small number of Fantasy-pack pieces may ship near-as-is where they read as intentional fashion; the basic set itself stays modern.
|
||
|
||
Art direction CONSOLIDATED (user, 2026-07-06 — supersedes the two notes above): the Reach has no single clothing style — ALL styles coexist, with modern/cyberpunk probably the most prevalent. Style is a prevalence DISTRIBUTION, not a genre rule, and may eventually vary by culture/settlement (fits the simulation DNA; fashion-as-cultural-data is a later phase concern, not this ticket). Consequences now: (1) the engine is style-agnostic by construction (slots/tints/logos carry no genre); (2) the basic set targets the prevalent center — modern casual + corporate — because it dresses the most NPCs and the shopping experience; (3) garments get a lightweight style tag in the manifest (e.g. style: modern|formal|fantasy|utility) as the cheap seam so per-culture distributions can be authored later without retrofitting; (4) Fantasy-pack pieces are legitimate catalogue members under their own tag, prevalence-weighted low.
|
||
|
||
Scope pin (user, 2026-07-06, final word on style): for simplicity, THIS ticket ships ONE style only — cyberpunk/modern. The pluralistic distribution model above remains the long-term truth (keep the manifest style tag as the seam), but the v1 basic set is single-style; other styles are catalogue growth, not scope.
|
||
|
||
Route challenge (user, 2026-07-06): not sold on staying Quaternius-primary — ''Quaternius is limited and will move the wall at too slow a pace; I''d rather pick something that has what we need now.'' Fresh store verification (2026-07-06): Sidekick packs are one-time USD199.99, perpetual, engine-agnostic license (Godot legal, unsupported); NO raw FBX — extraction from unitypackage (community-proven: unitypackage_godot, third-party Sidekick Creator Godot plugin incl. body blend shapes); ''Sold out'' labels are a broken-theme artifact per Shopify JSON (needs one browser cart check); SyntyPass rejected (assets stop being developable after cancel). Relevant packs: Starter (FREE, 57+91 parts), Modern Civilians (165 parts = v1 basic set territory), Sci-Fi Civilians (103 parts, cyberpunk accents), Modern Police (uniforms/officials). DECISION NOW GATED ON THE FREE SPIKE: user downloads free Starter Pack -> Bridge-C spike (extract garment -> Robust Weight Transfer onto our rig -> 11-body batch -> animation QA in T-1088 sandbox). Pass -> buy Modern Civilians, Synty = primary garment supply (+UAL1/UAL2 Source ~USD30 for clips — no Synty substitute exists for Godot animations; Fantasy Outfits Source drops to low priority under the single-style pin). Fail -> hand-author route stands. Stay-vs-pivot governance record HELD until spike evidence lands.
|
||
|
||
Scope guard (user concern, 2026-07-06): Synty intake must NOT displace the create-stuff-yourself pipeline — the user''s goal includes in-house garment creation capability, not just swapping vendor catalogs. Resolution: three-route portfolio sharing one engine — (a) Synty intake = variety bootstrap only; (b) derivation scripting (cuts/merges/retexture, agent-automatable) = create-yourself lite, turns any donor topology into original designs; (c) TRUE AUTHORING on owned UBC Source body .blends = the pipeline proper. GUARANTEE: the colorable uniform and black suit (no donor exists in any pack) are built via route (c) as the authoring pipeline''s end-to-end proof — non-negotiable deliverable of this ticket, so the pipeline exists even if Synty covers everything else. Spike status: extraction done inline by lead (158 FBX, sci-fi civilian theme confirmed); DECISIVE finding — Sidekick rig is UE-Mannequin-named, 52/65 bone-name overlap with our rig, sample garment binds to 12 vgroups of which 11 match ours exactly (only head->Head case rename) => transplant likely rename-and-rebind, far cheaper than the weight-transfer the pivot eval assumed; body blend shapes travel in the FBX. Transplant phase parked pending API recovery / token-window reset.
|
||
|
||
ROUTE DECISION (user, 2026-07-06, final): Synty intake REJECTED despite the spike''s technical PASS — (1) USD199.99/pack is too expensive; (2) Sidekick modularity is baked body-segment swap (clothes fused to body chunks), incompatible with our layered clothing-over-body system (11 bodies, skin tones, slot swapping); (3) user dislikes the Synty style. The spike still paid: transplant/batch scripts are source-agnostic and become the G1-family production pipeline; T-1090 (5 bodies broken bare) discovered; the Synty question is closed with evidence, not parked. OPERATIVE ROUTE: (b) derive from owned Fantasy parts + (c) hand-author — with a new preferred authoring technique: OFFSET-SHELL FROM OUR OWN BODY MESHES (extract body segment surface, offset outward into garment shell, cut neckline/hem/sleeves; weights inherited by construction, style fully ours, USD0). Suit + uniform remain the full hand-author proof. Purchases still open (separate concerns): UAL1/UAL2 Source ~USD30 for animation clips; Fantasy Outfits Source USD20 low-priority convenience.
|
||
|
||
Chromakey garment-QA harness DELIVERED (2026-07-06, commits eaca6c8c4/74fa16260/b09a50efb): two-pass depth-proximity clip detection — pass A keys covered body segments magenta, pass B re-renders garment-only with a depth-only 3cm epsilon bias toward camera; analyzer splits key pixels into exposed_skin (informational — sleeveless arms, collars) vs clip_through (gating — skin within 3cm in front of cloth). Run: tooling/garment-qa/run-garment-qa <config>. Verified on the peasant set (avg_m/f x Walk/Sprint/Crouch_Fwd x 3 frames x 4 yaws): 0/18 front-view false positives; genuine findings = sleeveless armhole seam (avg_f, sides), deep-crouch waist gap (worst 150px, back), collar nape. First real fit observations already on record for the peasant set. Sensitivity: clip_epsilon_m + --min-pixels, to calibrate against the first modern garments. This is the acceptance gate for every garment the wardrobe pipeline produces; pair with the T-1088 sandbox for in-world walk QA.
|
||
|
||
ENGINE DELIVERED (2026-07-06, commits e22ea0fa4 + 278e8b7c2; earlier eaca6c8c4/74fa16260/b09a50efb chromakey, b54b8189d bodies): G1 skinned batch-fit (blender_batch_fit_skinned.py), offset-shell authoring (blender_author_offset_shell.py — route c create-yourself, weights by construction, procedural RGBA masks, UV2 chest channel), toon_garment.gdshader (channel-blended 4-region tint + logo after-tint/before-toon), compositor plumb (multi_region coverage flag -> garment shader; descriptor clothing_logos: per-character brand choice), thrds logo stub, manifest style tag + logo_capable. PROOF: tshirt_modern on 6 healthy bodies, 18-assertion suite green, 216-capture chromakey QA. ROUTE GUIDANCE from QA evidence (Q-060): single-reference SD-fit of offset-shells degrades with girth divergence (muscular_m worst 859px clip at 24mm standoff; reference body clean) — offset-shell garments should be authored PER BODY (needs per-body masks + runtime <body>_mask.png loading, small change); SD-fit remains right for derived/hand-authored garments sharing one mask (suit, uniform, Fantasy cuts). REMAINING for this ticket: refit tshirt to the 5 repaired forks (T-1090 done — add to --only and rerun), per-body shell mode, then the basic set: hoodie, button-down, shorts, jeans, formal pants, jacket + the suit/uniform hand-author proof; creation-screen try-on UI for tints/logos.', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.
|
||
|
||
Art direction (user, 2026-07-06): garments read CYBERPUNK/MODERN — near-future everyday civilian + corporate wear — NOT fantasy/medieval. The owned Fantasy pack is at most a topology donor (low-poly base shapes like pants/shirts are genre-neutral; genre lives in silhouette details, textures, trims, and accessories) — no medieval trim/textures may survive into shipped garments. Weight the authoring routes accordingly: texture identity matters as much as mesh. Canon hook: the wiki already ships a garment brand — thrds (wiki/star-systems/GJ-475/index.md, Braemar fiber cooperative, corridor fashion markets) — so branded clothing connects to Phase-1 lore, not only generated_brands.toml. This emphasis also feeds the Quaternius-pivot evaluation: commercial alternatives skew sci-fi/urban while Quaternius clothing is fantasy-only.
|
||
|
||
Nuance (user, 2026-07-06): the cyberpunk/modern direction is the DEFAULT, not a prohibition — fashion in the Reach is cyclical, so fantasy/medieval-flavored garments may appear here and there as deliberate fashion statements (subculture pieces, luxury/revival trims, statement outerwear). Supersedes the previous note''s hard ''no medieval trim may survive'' line. Practical consequence: a small number of Fantasy-pack pieces may ship near-as-is where they read as intentional fashion; the basic set itself stays modern.
|
||
|
||
Art direction CONSOLIDATED (user, 2026-07-06 — supersedes the two notes above): the Reach has no single clothing style — ALL styles coexist, with modern/cyberpunk probably the most prevalent. Style is a prevalence DISTRIBUTION, not a genre rule, and may eventually vary by culture/settlement (fits the simulation DNA; fashion-as-cultural-data is a later phase concern, not this ticket). Consequences now: (1) the engine is style-agnostic by construction (slots/tints/logos carry no genre); (2) the basic set targets the prevalent center — modern casual + corporate — because it dresses the most NPCs and the shopping experience; (3) garments get a lightweight style tag in the manifest (e.g. style: modern|formal|fantasy|utility) as the cheap seam so per-culture distributions can be authored later without retrofitting; (4) Fantasy-pack pieces are legitimate catalogue members under their own tag, prevalence-weighted low.
|
||
|
||
Scope pin (user, 2026-07-06, final word on style): for simplicity, THIS ticket ships ONE style only — cyberpunk/modern. The pluralistic distribution model above remains the long-term truth (keep the manifest style tag as the seam), but the v1 basic set is single-style; other styles are catalogue growth, not scope.
|
||
|
||
Route challenge (user, 2026-07-06): not sold on staying Quaternius-primary — ''Quaternius is limited and will move the wall at too slow a pace; I''d rather pick something that has what we need now.'' Fresh store verification (2026-07-06): Sidekick packs are one-time USD199.99, perpetual, engine-agnostic license (Godot legal, unsupported); NO raw FBX — extraction from unitypackage (community-proven: unitypackage_godot, third-party Sidekick Creator Godot plugin incl. body blend shapes); ''Sold out'' labels are a broken-theme artifact per Shopify JSON (needs one browser cart check); SyntyPass rejected (assets stop being developable after cancel). Relevant packs: Starter (FREE, 57+91 parts), Modern Civilians (165 parts = v1 basic set territory), Sci-Fi Civilians (103 parts, cyberpunk accents), Modern Police (uniforms/officials). DECISION NOW GATED ON THE FREE SPIKE: user downloads free Starter Pack -> Bridge-C spike (extract garment -> Robust Weight Transfer onto our rig -> 11-body batch -> animation QA in T-1088 sandbox). Pass -> buy Modern Civilians, Synty = primary garment supply (+UAL1/UAL2 Source ~USD30 for clips — no Synty substitute exists for Godot animations; Fantasy Outfits Source drops to low priority under the single-style pin). Fail -> hand-author route stands. Stay-vs-pivot governance record HELD until spike evidence lands.
|
||
|
||
Scope guard (user concern, 2026-07-06): Synty intake must NOT displace the create-stuff-yourself pipeline — the user''s goal includes in-house garment creation capability, not just swapping vendor catalogs. Resolution: three-route portfolio sharing one engine — (a) Synty intake = variety bootstrap only; (b) derivation scripting (cuts/merges/retexture, agent-automatable) = create-yourself lite, turns any donor topology into original designs; (c) TRUE AUTHORING on owned UBC Source body .blends = the pipeline proper. GUARANTEE: the colorable uniform and black suit (no donor exists in any pack) are built via route (c) as the authoring pipeline''s end-to-end proof — non-negotiable deliverable of this ticket, so the pipeline exists even if Synty covers everything else. Spike status: extraction done inline by lead (158 FBX, sci-fi civilian theme confirmed); DECISIVE finding — Sidekick rig is UE-Mannequin-named, 52/65 bone-name overlap with our rig, sample garment binds to 12 vgroups of which 11 match ours exactly (only head->Head case rename) => transplant likely rename-and-rebind, far cheaper than the weight-transfer the pivot eval assumed; body blend shapes travel in the FBX. Transplant phase parked pending API recovery / token-window reset.
|
||
|
||
ROUTE DECISION (user, 2026-07-06, final): Synty intake REJECTED despite the spike''s technical PASS — (1) USD199.99/pack is too expensive; (2) Sidekick modularity is baked body-segment swap (clothes fused to body chunks), incompatible with our layered clothing-over-body system (11 bodies, skin tones, slot swapping); (3) user dislikes the Synty style. The spike still paid: transplant/batch scripts are source-agnostic and become the G1-family production pipeline; T-1090 (5 bodies broken bare) discovered; the Synty question is closed with evidence, not parked. OPERATIVE ROUTE: (b) derive from owned Fantasy parts + (c) hand-author — with a new preferred authoring technique: OFFSET-SHELL FROM OUR OWN BODY MESHES (extract body segment surface, offset outward into garment shell, cut neckline/hem/sleeves; weights inherited by construction, style fully ours, USD0). Suit + uniform remain the full hand-author proof. Purchases still open (separate concerns): UAL1/UAL2 Source ~USD30 for animation clips; Fantasy Outfits Source USD20 low-priority convenience.
|
||
|
||
Chromakey garment-QA harness DELIVERED (2026-07-06, commits eaca6c8c4/74fa16260/b09a50efb): two-pass depth-proximity clip detection — pass A keys covered body segments magenta, pass B re-renders garment-only with a depth-only 3cm epsilon bias toward camera; analyzer splits key pixels into exposed_skin (informational — sleeveless arms, collars) vs clip_through (gating — skin within 3cm in front of cloth). Run: tooling/garment-qa/run-garment-qa <config>. Verified on the peasant set (avg_m/f x Walk/Sprint/Crouch_Fwd x 3 frames x 4 yaws): 0/18 front-view false positives; genuine findings = sleeveless armhole seam (avg_f, sides), deep-crouch waist gap (worst 150px, back), collar nape. First real fit observations already on record for the peasant set. Sensitivity: clip_epsilon_m + --min-pixels, to calibrate against the first modern garments. This is the acceptance gate for every garment the wardrobe pipeline produces; pair with the T-1088 sandbox for in-world walk QA.
|
||
|
||
ENGINE DELIVERED (2026-07-06, commits e22ea0fa4 + 278e8b7c2; earlier eaca6c8c4/74fa16260/b09a50efb chromakey, b54b8189d bodies): G1 skinned batch-fit (blender_batch_fit_skinned.py), offset-shell authoring (blender_author_offset_shell.py — route c create-yourself, weights by construction, procedural RGBA masks, UV2 chest channel), toon_garment.gdshader (channel-blended 4-region tint + logo after-tint/before-toon), compositor plumb (multi_region coverage flag -> garment shader; descriptor clothing_logos: per-character brand choice), thrds logo stub, manifest style tag + logo_capable. PROOF: tshirt_modern on 6 healthy bodies, 18-assertion suite green, 216-capture chromakey QA. ROUTE GUIDANCE from QA evidence (Q-060): single-reference SD-fit of offset-shells degrades with girth divergence (muscular_m worst 859px clip at 24mm standoff; reference body clean) — offset-shell garments should be authored PER BODY (needs per-body masks + runtime <body>_mask.png loading, small change); SD-fit remains right for derived/hand-authored garments sharing one mask (suit, uniform, Fantasy cuts). REMAINING for this ticket: refit tshirt to the 5 repaired forks (T-1090 done — add to --only and rerun), per-body shell mode, then the basic set: hoodie, button-down, shorts, jeans, formal pants, jacket + the suit/uniform hand-author proof; creation-screen try-on UI for tints/logos.
|
||
|
||
Basic-set EXPANSION (user, 2026-07-06 bedtime directive: ''full set of the basics across the board''): wave 2 after the in-flight wave 1 — FOOTWEAR: sneakers_modern (trainers, everyday default), shoes_formal (suit pairing), boots_modern (ankle height); SPORT: tank_top (sleeveless, logo-capable), joggers_modern (cuffed, track-stripe tint region), track_jacket (with joggers = the training suit, logo-capable); SWIM: swim_trunks (bright), swimsuit_onepiece (color-block regions). Foot garments follow the peasant_shoes both-feet convention; sole geometry as an offset-shell param extension. Total modern catalogue after wave 2: 17 garments across tops/bottoms/feet/full-body x casual/formal/sport/swim. DEFERRED deliberately: hats/accessories — accessory slot path is unexercised and T-721 flags a filter bug; needs daylight, not a 3am debug. Overnight sequence: wave 1 -> wave 2 -> full garment x 11-body fitting matrix (the ''T-1090 fittings'' check, fork bodies especially) -> commits -> gated pushes -> morning report.', NULL, '2026-07-06 21:19:48', '2026-07-06 21:19:48.840', '2026-07-06 21:19:48.840', NULL, '2e5f043ccaad01475ce7fd7972613565', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKCPBF41RWK9PW9M22Q7961C', 'description', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.
|
||
|
||
Art direction (user, 2026-07-06): garments read CYBERPUNK/MODERN — near-future everyday civilian + corporate wear — NOT fantasy/medieval. The owned Fantasy pack is at most a topology donor (low-poly base shapes like pants/shirts are genre-neutral; genre lives in silhouette details, textures, trims, and accessories) — no medieval trim/textures may survive into shipped garments. Weight the authoring routes accordingly: texture identity matters as much as mesh. Canon hook: the wiki already ships a garment brand — thrds (wiki/star-systems/GJ-475/index.md, Braemar fiber cooperative, corridor fashion markets) — so branded clothing connects to Phase-1 lore, not only generated_brands.toml. This emphasis also feeds the Quaternius-pivot evaluation: commercial alternatives skew sci-fi/urban while Quaternius clothing is fantasy-only.
|
||
|
||
Nuance (user, 2026-07-06): the cyberpunk/modern direction is the DEFAULT, not a prohibition — fashion in the Reach is cyclical, so fantasy/medieval-flavored garments may appear here and there as deliberate fashion statements (subculture pieces, luxury/revival trims, statement outerwear). Supersedes the previous note''s hard ''no medieval trim may survive'' line. Practical consequence: a small number of Fantasy-pack pieces may ship near-as-is where they read as intentional fashion; the basic set itself stays modern.
|
||
|
||
Art direction CONSOLIDATED (user, 2026-07-06 — supersedes the two notes above): the Reach has no single clothing style — ALL styles coexist, with modern/cyberpunk probably the most prevalent. Style is a prevalence DISTRIBUTION, not a genre rule, and may eventually vary by culture/settlement (fits the simulation DNA; fashion-as-cultural-data is a later phase concern, not this ticket). Consequences now: (1) the engine is style-agnostic by construction (slots/tints/logos carry no genre); (2) the basic set targets the prevalent center — modern casual + corporate — because it dresses the most NPCs and the shopping experience; (3) garments get a lightweight style tag in the manifest (e.g. style: modern|formal|fantasy|utility) as the cheap seam so per-culture distributions can be authored later without retrofitting; (4) Fantasy-pack pieces are legitimate catalogue members under their own tag, prevalence-weighted low.
|
||
|
||
Scope pin (user, 2026-07-06, final word on style): for simplicity, THIS ticket ships ONE style only — cyberpunk/modern. The pluralistic distribution model above remains the long-term truth (keep the manifest style tag as the seam), but the v1 basic set is single-style; other styles are catalogue growth, not scope.
|
||
|
||
Route challenge (user, 2026-07-06): not sold on staying Quaternius-primary — ''Quaternius is limited and will move the wall at too slow a pace; I''d rather pick something that has what we need now.'' Fresh store verification (2026-07-06): Sidekick packs are one-time USD199.99, perpetual, engine-agnostic license (Godot legal, unsupported); NO raw FBX — extraction from unitypackage (community-proven: unitypackage_godot, third-party Sidekick Creator Godot plugin incl. body blend shapes); ''Sold out'' labels are a broken-theme artifact per Shopify JSON (needs one browser cart check); SyntyPass rejected (assets stop being developable after cancel). Relevant packs: Starter (FREE, 57+91 parts), Modern Civilians (165 parts = v1 basic set territory), Sci-Fi Civilians (103 parts, cyberpunk accents), Modern Police (uniforms/officials). DECISION NOW GATED ON THE FREE SPIKE: user downloads free Starter Pack -> Bridge-C spike (extract garment -> Robust Weight Transfer onto our rig -> 11-body batch -> animation QA in T-1088 sandbox). Pass -> buy Modern Civilians, Synty = primary garment supply (+UAL1/UAL2 Source ~USD30 for clips — no Synty substitute exists for Godot animations; Fantasy Outfits Source drops to low priority under the single-style pin). Fail -> hand-author route stands. Stay-vs-pivot governance record HELD until spike evidence lands.
|
||
|
||
Scope guard (user concern, 2026-07-06): Synty intake must NOT displace the create-stuff-yourself pipeline — the user''s goal includes in-house garment creation capability, not just swapping vendor catalogs. Resolution: three-route portfolio sharing one engine — (a) Synty intake = variety bootstrap only; (b) derivation scripting (cuts/merges/retexture, agent-automatable) = create-yourself lite, turns any donor topology into original designs; (c) TRUE AUTHORING on owned UBC Source body .blends = the pipeline proper. GUARANTEE: the colorable uniform and black suit (no donor exists in any pack) are built via route (c) as the authoring pipeline''s end-to-end proof — non-negotiable deliverable of this ticket, so the pipeline exists even if Synty covers everything else. Spike status: extraction done inline by lead (158 FBX, sci-fi civilian theme confirmed); DECISIVE finding — Sidekick rig is UE-Mannequin-named, 52/65 bone-name overlap with our rig, sample garment binds to 12 vgroups of which 11 match ours exactly (only head->Head case rename) => transplant likely rename-and-rebind, far cheaper than the weight-transfer the pivot eval assumed; body blend shapes travel in the FBX. Transplant phase parked pending API recovery / token-window reset.
|
||
|
||
ROUTE DECISION (user, 2026-07-06, final): Synty intake REJECTED despite the spike''s technical PASS — (1) USD199.99/pack is too expensive; (2) Sidekick modularity is baked body-segment swap (clothes fused to body chunks), incompatible with our layered clothing-over-body system (11 bodies, skin tones, slot swapping); (3) user dislikes the Synty style. The spike still paid: transplant/batch scripts are source-agnostic and become the G1-family production pipeline; T-1090 (5 bodies broken bare) discovered; the Synty question is closed with evidence, not parked. OPERATIVE ROUTE: (b) derive from owned Fantasy parts + (c) hand-author — with a new preferred authoring technique: OFFSET-SHELL FROM OUR OWN BODY MESHES (extract body segment surface, offset outward into garment shell, cut neckline/hem/sleeves; weights inherited by construction, style fully ours, USD0). Suit + uniform remain the full hand-author proof. Purchases still open (separate concerns): UAL1/UAL2 Source ~USD30 for animation clips; Fantasy Outfits Source USD20 low-priority convenience.
|
||
|
||
Chromakey garment-QA harness DELIVERED (2026-07-06, commits eaca6c8c4/74fa16260/b09a50efb): two-pass depth-proximity clip detection — pass A keys covered body segments magenta, pass B re-renders garment-only with a depth-only 3cm epsilon bias toward camera; analyzer splits key pixels into exposed_skin (informational — sleeveless arms, collars) vs clip_through (gating — skin within 3cm in front of cloth). Run: tooling/garment-qa/run-garment-qa <config>. Verified on the peasant set (avg_m/f x Walk/Sprint/Crouch_Fwd x 3 frames x 4 yaws): 0/18 front-view false positives; genuine findings = sleeveless armhole seam (avg_f, sides), deep-crouch waist gap (worst 150px, back), collar nape. First real fit observations already on record for the peasant set. Sensitivity: clip_epsilon_m + --min-pixels, to calibrate against the first modern garments. This is the acceptance gate for every garment the wardrobe pipeline produces; pair with the T-1088 sandbox for in-world walk QA.
|
||
|
||
ENGINE DELIVERED (2026-07-06, commits e22ea0fa4 + 278e8b7c2; earlier eaca6c8c4/74fa16260/b09a50efb chromakey, b54b8189d bodies): G1 skinned batch-fit (blender_batch_fit_skinned.py), offset-shell authoring (blender_author_offset_shell.py — route c create-yourself, weights by construction, procedural RGBA masks, UV2 chest channel), toon_garment.gdshader (channel-blended 4-region tint + logo after-tint/before-toon), compositor plumb (multi_region coverage flag -> garment shader; descriptor clothing_logos: per-character brand choice), thrds logo stub, manifest style tag + logo_capable. PROOF: tshirt_modern on 6 healthy bodies, 18-assertion suite green, 216-capture chromakey QA. ROUTE GUIDANCE from QA evidence (Q-060): single-reference SD-fit of offset-shells degrades with girth divergence (muscular_m worst 859px clip at 24mm standoff; reference body clean) — offset-shell garments should be authored PER BODY (needs per-body masks + runtime <body>_mask.png loading, small change); SD-fit remains right for derived/hand-authored garments sharing one mask (suit, uniform, Fantasy cuts). REMAINING for this ticket: refit tshirt to the 5 repaired forks (T-1090 done — add to --only and rerun), per-body shell mode, then the basic set: hoodie, button-down, shorts, jeans, formal pants, jacket + the suit/uniform hand-author proof; creation-screen try-on UI for tints/logos.
|
||
|
||
Basic-set EXPANSION (user, 2026-07-06 bedtime directive: ''full set of the basics across the board''): wave 2 after the in-flight wave 1 — FOOTWEAR: sneakers_modern (trainers, everyday default), shoes_formal (suit pairing), boots_modern (ankle height); SPORT: tank_top (sleeveless, logo-capable), joggers_modern (cuffed, track-stripe tint region), track_jacket (with joggers = the training suit, logo-capable); SWIM: swim_trunks (bright), swimsuit_onepiece (color-block regions). Foot garments follow the peasant_shoes both-feet convention; sole geometry as an offset-shell param extension. Total modern catalogue after wave 2: 17 garments across tops/bottoms/feet/full-body x casual/formal/sport/swim. DEFERRED deliberately: hats/accessories — accessory slot path is unexercised and T-721 flags a filter bug; needs daylight, not a 3am debug. Overnight sequence: wave 1 -> wave 2 -> full garment x 11-body fitting matrix (the ''T-1090 fittings'' check, fork bodies especially) -> commits -> gated pushes -> morning report.', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.
|
||
|
||
Art direction (user, 2026-07-06): garments read CYBERPUNK/MODERN — near-future everyday civilian + corporate wear — NOT fantasy/medieval. The owned Fantasy pack is at most a topology donor (low-poly base shapes like pants/shirts are genre-neutral; genre lives in silhouette details, textures, trims, and accessories) — no medieval trim/textures may survive into shipped garments. Weight the authoring routes accordingly: texture identity matters as much as mesh. Canon hook: the wiki already ships a garment brand — thrds (wiki/star-systems/GJ-475/index.md, Braemar fiber cooperative, corridor fashion markets) — so branded clothing connects to Phase-1 lore, not only generated_brands.toml. This emphasis also feeds the Quaternius-pivot evaluation: commercial alternatives skew sci-fi/urban while Quaternius clothing is fantasy-only.
|
||
|
||
Nuance (user, 2026-07-06): the cyberpunk/modern direction is the DEFAULT, not a prohibition — fashion in the Reach is cyclical, so fantasy/medieval-flavored garments may appear here and there as deliberate fashion statements (subculture pieces, luxury/revival trims, statement outerwear). Supersedes the previous note''s hard ''no medieval trim may survive'' line. Practical consequence: a small number of Fantasy-pack pieces may ship near-as-is where they read as intentional fashion; the basic set itself stays modern.
|
||
|
||
Art direction CONSOLIDATED (user, 2026-07-06 — supersedes the two notes above): the Reach has no single clothing style — ALL styles coexist, with modern/cyberpunk probably the most prevalent. Style is a prevalence DISTRIBUTION, not a genre rule, and may eventually vary by culture/settlement (fits the simulation DNA; fashion-as-cultural-data is a later phase concern, not this ticket). Consequences now: (1) the engine is style-agnostic by construction (slots/tints/logos carry no genre); (2) the basic set targets the prevalent center — modern casual + corporate — because it dresses the most NPCs and the shopping experience; (3) garments get a lightweight style tag in the manifest (e.g. style: modern|formal|fantasy|utility) as the cheap seam so per-culture distributions can be authored later without retrofitting; (4) Fantasy-pack pieces are legitimate catalogue members under their own tag, prevalence-weighted low.
|
||
|
||
Scope pin (user, 2026-07-06, final word on style): for simplicity, THIS ticket ships ONE style only — cyberpunk/modern. The pluralistic distribution model above remains the long-term truth (keep the manifest style tag as the seam), but the v1 basic set is single-style; other styles are catalogue growth, not scope.
|
||
|
||
Route challenge (user, 2026-07-06): not sold on staying Quaternius-primary — ''Quaternius is limited and will move the wall at too slow a pace; I''d rather pick something that has what we need now.'' Fresh store verification (2026-07-06): Sidekick packs are one-time USD199.99, perpetual, engine-agnostic license (Godot legal, unsupported); NO raw FBX — extraction from unitypackage (community-proven: unitypackage_godot, third-party Sidekick Creator Godot plugin incl. body blend shapes); ''Sold out'' labels are a broken-theme artifact per Shopify JSON (needs one browser cart check); SyntyPass rejected (assets stop being developable after cancel). Relevant packs: Starter (FREE, 57+91 parts), Modern Civilians (165 parts = v1 basic set territory), Sci-Fi Civilians (103 parts, cyberpunk accents), Modern Police (uniforms/officials). DECISION NOW GATED ON THE FREE SPIKE: user downloads free Starter Pack -> Bridge-C spike (extract garment -> Robust Weight Transfer onto our rig -> 11-body batch -> animation QA in T-1088 sandbox). Pass -> buy Modern Civilians, Synty = primary garment supply (+UAL1/UAL2 Source ~USD30 for clips — no Synty substitute exists for Godot animations; Fantasy Outfits Source drops to low priority under the single-style pin). Fail -> hand-author route stands. Stay-vs-pivot governance record HELD until spike evidence lands.
|
||
|
||
Scope guard (user concern, 2026-07-06): Synty intake must NOT displace the create-stuff-yourself pipeline — the user''s goal includes in-house garment creation capability, not just swapping vendor catalogs. Resolution: three-route portfolio sharing one engine — (a) Synty intake = variety bootstrap only; (b) derivation scripting (cuts/merges/retexture, agent-automatable) = create-yourself lite, turns any donor topology into original designs; (c) TRUE AUTHORING on owned UBC Source body .blends = the pipeline proper. GUARANTEE: the colorable uniform and black suit (no donor exists in any pack) are built via route (c) as the authoring pipeline''s end-to-end proof — non-negotiable deliverable of this ticket, so the pipeline exists even if Synty covers everything else. Spike status: extraction done inline by lead (158 FBX, sci-fi civilian theme confirmed); DECISIVE finding — Sidekick rig is UE-Mannequin-named, 52/65 bone-name overlap with our rig, sample garment binds to 12 vgroups of which 11 match ours exactly (only head->Head case rename) => transplant likely rename-and-rebind, far cheaper than the weight-transfer the pivot eval assumed; body blend shapes travel in the FBX. Transplant phase parked pending API recovery / token-window reset.
|
||
|
||
ROUTE DECISION (user, 2026-07-06, final): Synty intake REJECTED despite the spike''s technical PASS — (1) USD199.99/pack is too expensive; (2) Sidekick modularity is baked body-segment swap (clothes fused to body chunks), incompatible with our layered clothing-over-body system (11 bodies, skin tones, slot swapping); (3) user dislikes the Synty style. The spike still paid: transplant/batch scripts are source-agnostic and become the G1-family production pipeline; T-1090 (5 bodies broken bare) discovered; the Synty question is closed with evidence, not parked. OPERATIVE ROUTE: (b) derive from owned Fantasy parts + (c) hand-author — with a new preferred authoring technique: OFFSET-SHELL FROM OUR OWN BODY MESHES (extract body segment surface, offset outward into garment shell, cut neckline/hem/sleeves; weights inherited by construction, style fully ours, USD0). Suit + uniform remain the full hand-author proof. Purchases still open (separate concerns): UAL1/UAL2 Source ~USD30 for animation clips; Fantasy Outfits Source USD20 low-priority convenience.
|
||
|
||
Chromakey garment-QA harness DELIVERED (2026-07-06, commits eaca6c8c4/74fa16260/b09a50efb): two-pass depth-proximity clip detection — pass A keys covered body segments magenta, pass B re-renders garment-only with a depth-only 3cm epsilon bias toward camera; analyzer splits key pixels into exposed_skin (informational — sleeveless arms, collars) vs clip_through (gating — skin within 3cm in front of cloth). Run: tooling/garment-qa/run-garment-qa <config>. Verified on the peasant set (avg_m/f x Walk/Sprint/Crouch_Fwd x 3 frames x 4 yaws): 0/18 front-view false positives; genuine findings = sleeveless armhole seam (avg_f, sides), deep-crouch waist gap (worst 150px, back), collar nape. First real fit observations already on record for the peasant set. Sensitivity: clip_epsilon_m + --min-pixels, to calibrate against the first modern garments. This is the acceptance gate for every garment the wardrobe pipeline produces; pair with the T-1088 sandbox for in-world walk QA.
|
||
|
||
ENGINE DELIVERED (2026-07-06, commits e22ea0fa4 + 278e8b7c2; earlier eaca6c8c4/74fa16260/b09a50efb chromakey, b54b8189d bodies): G1 skinned batch-fit (blender_batch_fit_skinned.py), offset-shell authoring (blender_author_offset_shell.py — route c create-yourself, weights by construction, procedural RGBA masks, UV2 chest channel), toon_garment.gdshader (channel-blended 4-region tint + logo after-tint/before-toon), compositor plumb (multi_region coverage flag -> garment shader; descriptor clothing_logos: per-character brand choice), thrds logo stub, manifest style tag + logo_capable. PROOF: tshirt_modern on 6 healthy bodies, 18-assertion suite green, 216-capture chromakey QA. ROUTE GUIDANCE from QA evidence (Q-060): single-reference SD-fit of offset-shells degrades with girth divergence (muscular_m worst 859px clip at 24mm standoff; reference body clean) — offset-shell garments should be authored PER BODY (needs per-body masks + runtime <body>_mask.png loading, small change); SD-fit remains right for derived/hand-authored garments sharing one mask (suit, uniform, Fantasy cuts). REMAINING for this ticket: refit tshirt to the 5 repaired forks (T-1090 done — add to --only and rerun), per-body shell mode, then the basic set: hoodie, button-down, shorts, jeans, formal pants, jacket + the suit/uniform hand-author proof; creation-screen try-on UI for tints/logos.
|
||
|
||
Basic-set EXPANSION (user, 2026-07-06 bedtime directive: ''full set of the basics across the board''): wave 2 after the in-flight wave 1 — FOOTWEAR: sneakers_modern (trainers, everyday default), shoes_formal (suit pairing), boots_modern (ankle height); SPORT: tank_top (sleeveless, logo-capable), joggers_modern (cuffed, track-stripe tint region), track_jacket (with joggers = the training suit, logo-capable); SWIM: swim_trunks (bright), swimsuit_onepiece (color-block regions). Foot garments follow the peasant_shoes both-feet convention; sole geometry as an offset-shell param extension. Total modern catalogue after wave 2: 17 garments across tops/bottoms/feet/full-body x casual/formal/sport/swim. DEFERRED deliberately: hats/accessories — accessory slot path is unexercised and T-721 flags a filter bug; needs daylight, not a 3am debug. Overnight sequence: wave 1 -> wave 2 -> full garment x 11-body fitting matrix (the ''T-1090 fittings'' check, fork bodies especially) -> commits -> gated pushes -> morning report.
|
||
|
||
Fill-in-the-blanks addendum (user bedtime directive 2 + lead judgment): wave 2 grows to 12 — adds sweater_modern (crew pullover), cargo_pants (utility/cyberpunk staple), parka_thrds (cold-weather was absent entirely; ships as the FIRST CANON-BRANDED garment — thrds is Braemar''s cold-weather fiber brand per wiki; hip-length to avoid the parked skirt-rigging tier), slides (swim footwear, near-free). PLUS outfit presets: data file of named complete looks (casual/business/sport/beach/worker/sleep as tint-palette presets over garments) authored by the lead at integration — makes the catalogue usable for NPC dressing and the shop as OUTFITS, not just items. Post-wave-2 catalogue: 21 modern pieces (tops 8 / bottoms 6 / feet 4 / full-body 2 / swim 3). Hats/accessories remain the deliberate daylight deferral (T-721).', NULL, '2026-07-06 21:20:30', '2026-07-06 21:20:30.325', '2026-07-06 21:20:30.325', NULL, '844a61fd59dbff78bb63a90f4399d5c9', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKCPBF41RWK9PW9M22Q7961C', 'status', 'backlog', 'review', NULL, '2026-07-07 09:23:38', '2026-07-07 09:23:38.268', '2026-07-07 09:23:38.268', NULL, 'dbfc4dd044d0fd988d9b5ff5e2514d7e', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKCPBF41RWK9PW9M22Q7961C', 'description', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.
|
||
|
||
Art direction (user, 2026-07-06): garments read CYBERPUNK/MODERN — near-future everyday civilian + corporate wear — NOT fantasy/medieval. The owned Fantasy pack is at most a topology donor (low-poly base shapes like pants/shirts are genre-neutral; genre lives in silhouette details, textures, trims, and accessories) — no medieval trim/textures may survive into shipped garments. Weight the authoring routes accordingly: texture identity matters as much as mesh. Canon hook: the wiki already ships a garment brand — thrds (wiki/star-systems/GJ-475/index.md, Braemar fiber cooperative, corridor fashion markets) — so branded clothing connects to Phase-1 lore, not only generated_brands.toml. This emphasis also feeds the Quaternius-pivot evaluation: commercial alternatives skew sci-fi/urban while Quaternius clothing is fantasy-only.
|
||
|
||
Nuance (user, 2026-07-06): the cyberpunk/modern direction is the DEFAULT, not a prohibition — fashion in the Reach is cyclical, so fantasy/medieval-flavored garments may appear here and there as deliberate fashion statements (subculture pieces, luxury/revival trims, statement outerwear). Supersedes the previous note''s hard ''no medieval trim may survive'' line. Practical consequence: a small number of Fantasy-pack pieces may ship near-as-is where they read as intentional fashion; the basic set itself stays modern.
|
||
|
||
Art direction CONSOLIDATED (user, 2026-07-06 — supersedes the two notes above): the Reach has no single clothing style — ALL styles coexist, with modern/cyberpunk probably the most prevalent. Style is a prevalence DISTRIBUTION, not a genre rule, and may eventually vary by culture/settlement (fits the simulation DNA; fashion-as-cultural-data is a later phase concern, not this ticket). Consequences now: (1) the engine is style-agnostic by construction (slots/tints/logos carry no genre); (2) the basic set targets the prevalent center — modern casual + corporate — because it dresses the most NPCs and the shopping experience; (3) garments get a lightweight style tag in the manifest (e.g. style: modern|formal|fantasy|utility) as the cheap seam so per-culture distributions can be authored later without retrofitting; (4) Fantasy-pack pieces are legitimate catalogue members under their own tag, prevalence-weighted low.
|
||
|
||
Scope pin (user, 2026-07-06, final word on style): for simplicity, THIS ticket ships ONE style only — cyberpunk/modern. The pluralistic distribution model above remains the long-term truth (keep the manifest style tag as the seam), but the v1 basic set is single-style; other styles are catalogue growth, not scope.
|
||
|
||
Route challenge (user, 2026-07-06): not sold on staying Quaternius-primary — ''Quaternius is limited and will move the wall at too slow a pace; I''d rather pick something that has what we need now.'' Fresh store verification (2026-07-06): Sidekick packs are one-time USD199.99, perpetual, engine-agnostic license (Godot legal, unsupported); NO raw FBX — extraction from unitypackage (community-proven: unitypackage_godot, third-party Sidekick Creator Godot plugin incl. body blend shapes); ''Sold out'' labels are a broken-theme artifact per Shopify JSON (needs one browser cart check); SyntyPass rejected (assets stop being developable after cancel). Relevant packs: Starter (FREE, 57+91 parts), Modern Civilians (165 parts = v1 basic set territory), Sci-Fi Civilians (103 parts, cyberpunk accents), Modern Police (uniforms/officials). DECISION NOW GATED ON THE FREE SPIKE: user downloads free Starter Pack -> Bridge-C spike (extract garment -> Robust Weight Transfer onto our rig -> 11-body batch -> animation QA in T-1088 sandbox). Pass -> buy Modern Civilians, Synty = primary garment supply (+UAL1/UAL2 Source ~USD30 for clips — no Synty substitute exists for Godot animations; Fantasy Outfits Source drops to low priority under the single-style pin). Fail -> hand-author route stands. Stay-vs-pivot governance record HELD until spike evidence lands.
|
||
|
||
Scope guard (user concern, 2026-07-06): Synty intake must NOT displace the create-stuff-yourself pipeline — the user''s goal includes in-house garment creation capability, not just swapping vendor catalogs. Resolution: three-route portfolio sharing one engine — (a) Synty intake = variety bootstrap only; (b) derivation scripting (cuts/merges/retexture, agent-automatable) = create-yourself lite, turns any donor topology into original designs; (c) TRUE AUTHORING on owned UBC Source body .blends = the pipeline proper. GUARANTEE: the colorable uniform and black suit (no donor exists in any pack) are built via route (c) as the authoring pipeline''s end-to-end proof — non-negotiable deliverable of this ticket, so the pipeline exists even if Synty covers everything else. Spike status: extraction done inline by lead (158 FBX, sci-fi civilian theme confirmed); DECISIVE finding — Sidekick rig is UE-Mannequin-named, 52/65 bone-name overlap with our rig, sample garment binds to 12 vgroups of which 11 match ours exactly (only head->Head case rename) => transplant likely rename-and-rebind, far cheaper than the weight-transfer the pivot eval assumed; body blend shapes travel in the FBX. Transplant phase parked pending API recovery / token-window reset.
|
||
|
||
ROUTE DECISION (user, 2026-07-06, final): Synty intake REJECTED despite the spike''s technical PASS — (1) USD199.99/pack is too expensive; (2) Sidekick modularity is baked body-segment swap (clothes fused to body chunks), incompatible with our layered clothing-over-body system (11 bodies, skin tones, slot swapping); (3) user dislikes the Synty style. The spike still paid: transplant/batch scripts are source-agnostic and become the G1-family production pipeline; T-1090 (5 bodies broken bare) discovered; the Synty question is closed with evidence, not parked. OPERATIVE ROUTE: (b) derive from owned Fantasy parts + (c) hand-author — with a new preferred authoring technique: OFFSET-SHELL FROM OUR OWN BODY MESHES (extract body segment surface, offset outward into garment shell, cut neckline/hem/sleeves; weights inherited by construction, style fully ours, USD0). Suit + uniform remain the full hand-author proof. Purchases still open (separate concerns): UAL1/UAL2 Source ~USD30 for animation clips; Fantasy Outfits Source USD20 low-priority convenience.
|
||
|
||
Chromakey garment-QA harness DELIVERED (2026-07-06, commits eaca6c8c4/74fa16260/b09a50efb): two-pass depth-proximity clip detection — pass A keys covered body segments magenta, pass B re-renders garment-only with a depth-only 3cm epsilon bias toward camera; analyzer splits key pixels into exposed_skin (informational — sleeveless arms, collars) vs clip_through (gating — skin within 3cm in front of cloth). Run: tooling/garment-qa/run-garment-qa <config>. Verified on the peasant set (avg_m/f x Walk/Sprint/Crouch_Fwd x 3 frames x 4 yaws): 0/18 front-view false positives; genuine findings = sleeveless armhole seam (avg_f, sides), deep-crouch waist gap (worst 150px, back), collar nape. First real fit observations already on record for the peasant set. Sensitivity: clip_epsilon_m + --min-pixels, to calibrate against the first modern garments. This is the acceptance gate for every garment the wardrobe pipeline produces; pair with the T-1088 sandbox for in-world walk QA.
|
||
|
||
ENGINE DELIVERED (2026-07-06, commits e22ea0fa4 + 278e8b7c2; earlier eaca6c8c4/74fa16260/b09a50efb chromakey, b54b8189d bodies): G1 skinned batch-fit (blender_batch_fit_skinned.py), offset-shell authoring (blender_author_offset_shell.py — route c create-yourself, weights by construction, procedural RGBA masks, UV2 chest channel), toon_garment.gdshader (channel-blended 4-region tint + logo after-tint/before-toon), compositor plumb (multi_region coverage flag -> garment shader; descriptor clothing_logos: per-character brand choice), thrds logo stub, manifest style tag + logo_capable. PROOF: tshirt_modern on 6 healthy bodies, 18-assertion suite green, 216-capture chromakey QA. ROUTE GUIDANCE from QA evidence (Q-060): single-reference SD-fit of offset-shells degrades with girth divergence (muscular_m worst 859px clip at 24mm standoff; reference body clean) — offset-shell garments should be authored PER BODY (needs per-body masks + runtime <body>_mask.png loading, small change); SD-fit remains right for derived/hand-authored garments sharing one mask (suit, uniform, Fantasy cuts). REMAINING for this ticket: refit tshirt to the 5 repaired forks (T-1090 done — add to --only and rerun), per-body shell mode, then the basic set: hoodie, button-down, shorts, jeans, formal pants, jacket + the suit/uniform hand-author proof; creation-screen try-on UI for tints/logos.
|
||
|
||
Basic-set EXPANSION (user, 2026-07-06 bedtime directive: ''full set of the basics across the board''): wave 2 after the in-flight wave 1 — FOOTWEAR: sneakers_modern (trainers, everyday default), shoes_formal (suit pairing), boots_modern (ankle height); SPORT: tank_top (sleeveless, logo-capable), joggers_modern (cuffed, track-stripe tint region), track_jacket (with joggers = the training suit, logo-capable); SWIM: swim_trunks (bright), swimsuit_onepiece (color-block regions). Foot garments follow the peasant_shoes both-feet convention; sole geometry as an offset-shell param extension. Total modern catalogue after wave 2: 17 garments across tops/bottoms/feet/full-body x casual/formal/sport/swim. DEFERRED deliberately: hats/accessories — accessory slot path is unexercised and T-721 flags a filter bug; needs daylight, not a 3am debug. Overnight sequence: wave 1 -> wave 2 -> full garment x 11-body fitting matrix (the ''T-1090 fittings'' check, fork bodies especially) -> commits -> gated pushes -> morning report.
|
||
|
||
Fill-in-the-blanks addendum (user bedtime directive 2 + lead judgment): wave 2 grows to 12 — adds sweater_modern (crew pullover), cargo_pants (utility/cyberpunk staple), parka_thrds (cold-weather was absent entirely; ships as the FIRST CANON-BRANDED garment — thrds is Braemar''s cold-weather fiber brand per wiki; hip-length to avoid the parked skirt-rigging tier), slides (swim footwear, near-free). PLUS outfit presets: data file of named complete looks (casual/business/sport/beach/worker/sleep as tint-palette presets over garments) authored by the lead at integration — makes the catalogue usable for NPC dressing and the shop as OUTFITS, not just items. Post-wave-2 catalogue: 21 modern pieces (tops 8 / bottoms 6 / feet 4 / full-body 2 / swim 3). Hats/accessories remain the deliberate daylight deferral (T-721).', 'Fable-5-window sidequest workstream 2 (user directive 2026-07-06, extends T-1088 scope family): build the clothing ENGINE and a basic set now, park variety for later. Target bar: RimWorld''s original apparel breadth — varied enough to not feel limiting. Goal experience: being able to pick and SHOP for clothes — colorize + slap logos on casualwear. Basic set: t-shirt (logo-capable), hoodie (logo-capable), button-down shirt, shorts, jeans, formal pants, jacket, colorable uniform, black suit (moved up so officials are includable). Skipped by explicit call: capes, dresses/skirts (parked — difficulty tier). Engine deliverables: (1) multi-region tint masks — requires Quaternius Source tier files (USD5 Patreon month, one-time download, CC0 retained — user purchase action); (2) logo decal region on garment chest UV — flat 2D artwork per D-244, diegetic hook into economy generated brands (wiki/economics/corporations/generated_brands.toml) for brand-logo shirts; (3) manifest + CharacterVisualDescriptor category coverage (slots/tints already generic); (4) batch-fit each authored garment to all 11 body types via the validated Sprint-28 Blender Surface Deform pipeline (tooling/blender_*.py). Authoring routes per garment TBD by feasibility pass: derive from owned Fantasy pack meshes (62 parts, e.g. tunic->tshirt sleeve cut, pants->shorts hem cut) vs hand-author low-poly on the 65-bone rig (Garment Tool). Related: T-1088 locomotion sandbox doubles as the garment-under-animation QA rig (cycle outfits through Walk/Sprint/Crouch_Fwd).
|
||
|
||
Correction (2026-07-06): Source tier is PARTIALLY owned already — docs/assets/downloads/ (gitignored vendor archives, present in both checkouts) holds Universal Base Characters[Source] (630MB: full .blend files for all 6 base bodies incl. FullBody + OnlyHead variants, hairstyle .blends origin-at-0 + rigged-to-head-bone, texture masters, Godot engine project) plus UBC[Standard], UAL 1+2[Standard], Modular Character Outfits Fantasy[Standard]. NOT owned: Fantasy Outfits[Source] — the garment recolor masks + named vertex groups. Consequence: authoring NEW garments is fully unblocked (author against source body .blends, create our own tint masks/vertex groups — no purchase needed); only pack-DERIVED garments'' clean masks would want one more USD5 Patreon month, decision deferred until the feasibility route table says how much derivation we actually use.
|
||
|
||
Art direction (user, 2026-07-06): garments read CYBERPUNK/MODERN — near-future everyday civilian + corporate wear — NOT fantasy/medieval. The owned Fantasy pack is at most a topology donor (low-poly base shapes like pants/shirts are genre-neutral; genre lives in silhouette details, textures, trims, and accessories) — no medieval trim/textures may survive into shipped garments. Weight the authoring routes accordingly: texture identity matters as much as mesh. Canon hook: the wiki already ships a garment brand — thrds (wiki/star-systems/GJ-475/index.md, Braemar fiber cooperative, corridor fashion markets) — so branded clothing connects to Phase-1 lore, not only generated_brands.toml. This emphasis also feeds the Quaternius-pivot evaluation: commercial alternatives skew sci-fi/urban while Quaternius clothing is fantasy-only.
|
||
|
||
Nuance (user, 2026-07-06): the cyberpunk/modern direction is the DEFAULT, not a prohibition — fashion in the Reach is cyclical, so fantasy/medieval-flavored garments may appear here and there as deliberate fashion statements (subculture pieces, luxury/revival trims, statement outerwear). Supersedes the previous note''s hard ''no medieval trim may survive'' line. Practical consequence: a small number of Fantasy-pack pieces may ship near-as-is where they read as intentional fashion; the basic set itself stays modern.
|
||
|
||
Art direction CONSOLIDATED (user, 2026-07-06 — supersedes the two notes above): the Reach has no single clothing style — ALL styles coexist, with modern/cyberpunk probably the most prevalent. Style is a prevalence DISTRIBUTION, not a genre rule, and may eventually vary by culture/settlement (fits the simulation DNA; fashion-as-cultural-data is a later phase concern, not this ticket). Consequences now: (1) the engine is style-agnostic by construction (slots/tints/logos carry no genre); (2) the basic set targets the prevalent center — modern casual + corporate — because it dresses the most NPCs and the shopping experience; (3) garments get a lightweight style tag in the manifest (e.g. style: modern|formal|fantasy|utility) as the cheap seam so per-culture distributions can be authored later without retrofitting; (4) Fantasy-pack pieces are legitimate catalogue members under their own tag, prevalence-weighted low.
|
||
|
||
Scope pin (user, 2026-07-06, final word on style): for simplicity, THIS ticket ships ONE style only — cyberpunk/modern. The pluralistic distribution model above remains the long-term truth (keep the manifest style tag as the seam), but the v1 basic set is single-style; other styles are catalogue growth, not scope.
|
||
|
||
Route challenge (user, 2026-07-06): not sold on staying Quaternius-primary — ''Quaternius is limited and will move the wall at too slow a pace; I''d rather pick something that has what we need now.'' Fresh store verification (2026-07-06): Sidekick packs are one-time USD199.99, perpetual, engine-agnostic license (Godot legal, unsupported); NO raw FBX — extraction from unitypackage (community-proven: unitypackage_godot, third-party Sidekick Creator Godot plugin incl. body blend shapes); ''Sold out'' labels are a broken-theme artifact per Shopify JSON (needs one browser cart check); SyntyPass rejected (assets stop being developable after cancel). Relevant packs: Starter (FREE, 57+91 parts), Modern Civilians (165 parts = v1 basic set territory), Sci-Fi Civilians (103 parts, cyberpunk accents), Modern Police (uniforms/officials). DECISION NOW GATED ON THE FREE SPIKE: user downloads free Starter Pack -> Bridge-C spike (extract garment -> Robust Weight Transfer onto our rig -> 11-body batch -> animation QA in T-1088 sandbox). Pass -> buy Modern Civilians, Synty = primary garment supply (+UAL1/UAL2 Source ~USD30 for clips — no Synty substitute exists for Godot animations; Fantasy Outfits Source drops to low priority under the single-style pin). Fail -> hand-author route stands. Stay-vs-pivot governance record HELD until spike evidence lands.
|
||
|
||
Scope guard (user concern, 2026-07-06): Synty intake must NOT displace the create-stuff-yourself pipeline — the user''s goal includes in-house garment creation capability, not just swapping vendor catalogs. Resolution: three-route portfolio sharing one engine — (a) Synty intake = variety bootstrap only; (b) derivation scripting (cuts/merges/retexture, agent-automatable) = create-yourself lite, turns any donor topology into original designs; (c) TRUE AUTHORING on owned UBC Source body .blends = the pipeline proper. GUARANTEE: the colorable uniform and black suit (no donor exists in any pack) are built via route (c) as the authoring pipeline''s end-to-end proof — non-negotiable deliverable of this ticket, so the pipeline exists even if Synty covers everything else. Spike status: extraction done inline by lead (158 FBX, sci-fi civilian theme confirmed); DECISIVE finding — Sidekick rig is UE-Mannequin-named, 52/65 bone-name overlap with our rig, sample garment binds to 12 vgroups of which 11 match ours exactly (only head->Head case rename) => transplant likely rename-and-rebind, far cheaper than the weight-transfer the pivot eval assumed; body blend shapes travel in the FBX. Transplant phase parked pending API recovery / token-window reset.
|
||
|
||
ROUTE DECISION (user, 2026-07-06, final): Synty intake REJECTED despite the spike''s technical PASS — (1) USD199.99/pack is too expensive; (2) Sidekick modularity is baked body-segment swap (clothes fused to body chunks), incompatible with our layered clothing-over-body system (11 bodies, skin tones, slot swapping); (3) user dislikes the Synty style. The spike still paid: transplant/batch scripts are source-agnostic and become the G1-family production pipeline; T-1090 (5 bodies broken bare) discovered; the Synty question is closed with evidence, not parked. OPERATIVE ROUTE: (b) derive from owned Fantasy parts + (c) hand-author — with a new preferred authoring technique: OFFSET-SHELL FROM OUR OWN BODY MESHES (extract body segment surface, offset outward into garment shell, cut neckline/hem/sleeves; weights inherited by construction, style fully ours, USD0). Suit + uniform remain the full hand-author proof. Purchases still open (separate concerns): UAL1/UAL2 Source ~USD30 for animation clips; Fantasy Outfits Source USD20 low-priority convenience.
|
||
|
||
Chromakey garment-QA harness DELIVERED (2026-07-06, commits eaca6c8c4/74fa16260/b09a50efb): two-pass depth-proximity clip detection — pass A keys covered body segments magenta, pass B re-renders garment-only with a depth-only 3cm epsilon bias toward camera; analyzer splits key pixels into exposed_skin (informational — sleeveless arms, collars) vs clip_through (gating — skin within 3cm in front of cloth). Run: tooling/garment-qa/run-garment-qa <config>. Verified on the peasant set (avg_m/f x Walk/Sprint/Crouch_Fwd x 3 frames x 4 yaws): 0/18 front-view false positives; genuine findings = sleeveless armhole seam (avg_f, sides), deep-crouch waist gap (worst 150px, back), collar nape. First real fit observations already on record for the peasant set. Sensitivity: clip_epsilon_m + --min-pixels, to calibrate against the first modern garments. This is the acceptance gate for every garment the wardrobe pipeline produces; pair with the T-1088 sandbox for in-world walk QA.
|
||
|
||
ENGINE DELIVERED (2026-07-06, commits e22ea0fa4 + 278e8b7c2; earlier eaca6c8c4/74fa16260/b09a50efb chromakey, b54b8189d bodies): G1 skinned batch-fit (blender_batch_fit_skinned.py), offset-shell authoring (blender_author_offset_shell.py — route c create-yourself, weights by construction, procedural RGBA masks, UV2 chest channel), toon_garment.gdshader (channel-blended 4-region tint + logo after-tint/before-toon), compositor plumb (multi_region coverage flag -> garment shader; descriptor clothing_logos: per-character brand choice), thrds logo stub, manifest style tag + logo_capable. PROOF: tshirt_modern on 6 healthy bodies, 18-assertion suite green, 216-capture chromakey QA. ROUTE GUIDANCE from QA evidence (Q-060): single-reference SD-fit of offset-shells degrades with girth divergence (muscular_m worst 859px clip at 24mm standoff; reference body clean) — offset-shell garments should be authored PER BODY (needs per-body masks + runtime <body>_mask.png loading, small change); SD-fit remains right for derived/hand-authored garments sharing one mask (suit, uniform, Fantasy cuts). REMAINING for this ticket: refit tshirt to the 5 repaired forks (T-1090 done — add to --only and rerun), per-body shell mode, then the basic set: hoodie, button-down, shorts, jeans, formal pants, jacket + the suit/uniform hand-author proof; creation-screen try-on UI for tints/logos.
|
||
|
||
Basic-set EXPANSION (user, 2026-07-06 bedtime directive: ''full set of the basics across the board''): wave 2 after the in-flight wave 1 — FOOTWEAR: sneakers_modern (trainers, everyday default), shoes_formal (suit pairing), boots_modern (ankle height); SPORT: tank_top (sleeveless, logo-capable), joggers_modern (cuffed, track-stripe tint region), track_jacket (with joggers = the training suit, logo-capable); SWIM: swim_trunks (bright), swimsuit_onepiece (color-block regions). Foot garments follow the peasant_shoes both-feet convention; sole geometry as an offset-shell param extension. Total modern catalogue after wave 2: 17 garments across tops/bottoms/feet/full-body x casual/formal/sport/swim. DEFERRED deliberately: hats/accessories — accessory slot path is unexercised and T-721 flags a filter bug; needs daylight, not a 3am debug. Overnight sequence: wave 1 -> wave 2 -> full garment x 11-body fitting matrix (the ''T-1090 fittings'' check, fork bodies especially) -> commits -> gated pushes -> morning report.
|
||
|
||
Fill-in-the-blanks addendum (user bedtime directive 2 + lead judgment): wave 2 grows to 12 — adds sweater_modern (crew pullover), cargo_pants (utility/cyberpunk staple), parka_thrds (cold-weather was absent entirely; ships as the FIRST CANON-BRANDED garment — thrds is Braemar''s cold-weather fiber brand per wiki; hip-length to avoid the parked skirt-rigging tier), slides (swim footwear, near-free). PLUS outfit presets: data file of named complete looks (casual/business/sport/beach/worker/sleep as tint-palette presets over garments) authored by the lead at integration — makes the catalogue usable for NPC dressing and the shop as OUTFITS, not just items. Post-wave-2 catalogue: 21 modern pieces (tops 8 / bottoms 6 / feet 4 / full-body 2 / swim 3). Hats/accessories remain the deliberate daylight deferral (T-721).
|
||
|
||
ACCEPTED for first release (user review, 2026-07-07): full catalogue + lookbook approved; toe-box fix reviewed — ''I still see some toes, but this will do''. Residual toe hints on closed footwear accepted as first-release quality; further toe-box smoothing is polish backlog, not scope. Closing.', NULL, '2026-07-07 12:04:38', '2026-07-07 12:04:38.700', '2026-07-07 12:04:38.700', NULL, '8fd724c63e771a5cef9dd2120aa022ec', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKCPBF41RWK9PW9M22Q7961C', 'status', 'review', 'done', NULL, '2026-07-07 12:04:49', '2026-07-07 12:04:49.833', '2026-07-07 12:04:49.833', NULL, '69ad0ce426a5cf65efe7df5dc06161ef', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKR283RTWYXD2M005K65S52M', 'status', 'backlog', 'done', NULL, '2026-07-07 12:08:15', '2026-07-07 12:08:15.679', '2026-07-07 12:08:15.679', NULL, 'abf3b8af8fd454d6a75ca095b6d57908', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKCER95EK266H8RWPW8XT1F0', 'description', 'Fable-5-window sidequest (sanctioned cascade exception, 2026-07-05): the presentation layer that turns discrete server tile steps into a believable walking 3D character. Scope: 3D sandbox dev scene (SR_LIVE=1, greybox tiles derived from server snapshots, no hand-authored map), CharacterVisual instantiated in-world, locomotion rig (tile-step + facing-octant interpolation, stance-aware speeds), UAL animation state machine (idle/walk/sprint/careful/crouch), D-148 camera rig (30deg low-angle follow, 45deg rotation). Server-authoritative from day one — no client-local movement model. Builds on D-148/D-149/D-244/D-066 and the T-417 stance system. If the Fable 5 window closes mid-flight, work parks here.
|
||
|
||
Visual reference (user, 2026-07-06): Xenonauts 2 nails the target tiles/occlusion/character perspective — readable tile grid, low-angle tactical camera with angle options (matches D-148 30deg low-angle + 45deg rotation steps and the spikes/3dpipeline angle presets), and crucially its wall/roof occlusion treatment: camera-facing walls cut down/ghosted so interiors stay readable, floors peel per z-level. One deliberate difference: our camera locks to the player character (D-015/T-116) — no free map panning. Implication for the locomotion sandbox: greybox walls should prototype camera-facing cutaway occlusion early, since wall readability interacts with the locked low-angle camera.
|
||
|
||
Scoping call (user + lead agreement, 2026-07-06): wall cutaway is CLIENT-SIDE presentation, decoupled from fog-of-perception. Rationale: two occlusion systems with different subjects — perception/fog governs what the CHARACTER knows (server-enforced info boundary; client only receives observer-filtered geometry), cutaway governs what the PLAYER''S CAMERA sees (pure render mode on wall data the client already holds). They compose: cutaway cuts render height; fog overlay still gates what is visible behind. Walls remain first-class client data objects (future destruction/explosion interactions), cutaway is a render mode on them like tint/LOD. Nuance parked for Phase 5 proper: destroyed-while-unobserved walls should render in remembered state (fog-memory applied to geometry). If this holds through implementation, mint a D-record (perception domain) when the sidequest lands.
|
||
|
||
Animation supply resolved (2026-07-06): user purchased UAL1[Source+Pro] (120 clips, identical lists) + UAL2[Source] (134 clips), unzipped in docs/assets/downloads/. Gains: Turn90_L/R + Turn180_L/R (turn-in-place), Sprint_Enter/Exit + Crouch_Enter/Exit (stance transitions), full 8-direction Walk/Jog/Crouch sets incl. diagonals, Counter_Idle + talking/phone/sitting idles (life-sim verbs), plus _RM root-motion variants (unused — in-place is correct for server-authoritative interpolation). Still absent everywhere: walk start/stop + stairs — the only remaining custom clips. Integration is NOT a drop-in swap: upstream renamed clips (Walk_Loop -> Walk_Fwd_Loop etc.), so wire via the design''s recorded plan — explicit library names + lib/Clip addressing + gait-table update. NOTE for facing design: the 8-dir walk sets unlock Q-084''s parked walk-vs-aim split (direction-matched clips relative to facing) — revisit during the S9 tuning session.
|
||
|
||
Live-session feedback (user, 2026-07-06): (1) Corridor cutaway verdict — two minds: ''extremely trippy, could be the game''s own look'' vs ''player cannot see what is in the room unless close''. Resolution: cutaway MODES, toggled live in the sandbox (corridor / bottom-walls-low / both) — bottom-wall rule is data-driven (wall drops to stub when a KNOWN floor tile sits on its camera-far side; camera-facing directions derived from WorldRoot basis at runtime, not hand-derived). Default picked by feel during the session; the trippy corridor stays available as a signature-look option. (2) NEW: mouse-over move-here marker on the hovered tile + optimal path line — client-side A* over the never-evict KNOWN tile store (info-boundary-honest: the character plans only through known tiles; fog is unpathable), 8-dir with diagonal step cost 1 (time-optimal per the no-sqrt2 wire), terrain-cost provider seam (uniform today, Phase-4 terrain later), click executes by streaming ordinary Move* step commands through the existing throttle (zero protocol change, server validates every step), cancelled by WASD override / path invalidation / arrival. Settles more of Q-084 (click-to-move half).
|
||
|
||
RMB gesture vocabulary (user, live session 2026-07-06, added to the path-preview feature): single right-click = walk there (current stance); DOUBLE right-click = sprint there (ladder ToggleStanceUp burst to Sprint via the ordinary command queue, pre-sprint stance RESTORED on arrival; a double upgrades the already-started follow in place); LONG-PRESS right-click (~0.4s, commit on release) = ''take cover at location'', prototyped as go-there-then-Crouch-on-arrival (no restore — crouching was the point). Real cover mechanics (wall adjacency, directional protection) are future combat design; the gesture is the input-vocabulary prototype. WASD always cancels any follow without stance restore (player override is deliberate).
|
||
|
||
Follow-facing refinement (user, live session 2026-07-06): during an RMB path-follow the BODY commits to the leg/movement direction (mouse no longer swings body yaw); the mouse instead drives a LAYERED LOOK-AT — Head bone (~70deg limit) plus torso twist via a spine bone (~30deg) for looking far lateral/behind; beyond their sum the character physically cannot look further without turning (correct). Pure client presentation on the D-249 model; SetFacing continues to ride the wire during follows, so the SERVER vision cone still follows the mouse (diegetic: the character looks where the player points while walking a committed path). Implementation: Godot LookAtModifier3D pair under the CharacterVisual skeleton, influence-faded in/out on follow start/end; rig gains a commit_body_to_motion flag (yaw from leg velocity while set).', 'Fable-5-window sidequest (sanctioned cascade exception, 2026-07-05): the presentation layer that turns discrete server tile steps into a believable walking 3D character. Scope: 3D sandbox dev scene (SR_LIVE=1, greybox tiles derived from server snapshots, no hand-authored map), CharacterVisual instantiated in-world, locomotion rig (tile-step + facing-octant interpolation, stance-aware speeds), UAL animation state machine (idle/walk/sprint/careful/crouch), D-148 camera rig (30deg low-angle follow, 45deg rotation). Server-authoritative from day one — no client-local movement model. Builds on D-148/D-149/D-244/D-066 and the T-417 stance system. If the Fable 5 window closes mid-flight, work parks here.
|
||
|
||
Visual reference (user, 2026-07-06): Xenonauts 2 nails the target tiles/occlusion/character perspective — readable tile grid, low-angle tactical camera with angle options (matches D-148 30deg low-angle + 45deg rotation steps and the spikes/3dpipeline angle presets), and crucially its wall/roof occlusion treatment: camera-facing walls cut down/ghosted so interiors stay readable, floors peel per z-level. One deliberate difference: our camera locks to the player character (D-015/T-116) — no free map panning. Implication for the locomotion sandbox: greybox walls should prototype camera-facing cutaway occlusion early, since wall readability interacts with the locked low-angle camera.
|
||
|
||
Scoping call (user + lead agreement, 2026-07-06): wall cutaway is CLIENT-SIDE presentation, decoupled from fog-of-perception. Rationale: two occlusion systems with different subjects — perception/fog governs what the CHARACTER knows (server-enforced info boundary; client only receives observer-filtered geometry), cutaway governs what the PLAYER''S CAMERA sees (pure render mode on wall data the client already holds). They compose: cutaway cuts render height; fog overlay still gates what is visible behind. Walls remain first-class client data objects (future destruction/explosion interactions), cutaway is a render mode on them like tint/LOD. Nuance parked for Phase 5 proper: destroyed-while-unobserved walls should render in remembered state (fog-memory applied to geometry). If this holds through implementation, mint a D-record (perception domain) when the sidequest lands.
|
||
|
||
Animation supply resolved (2026-07-06): user purchased UAL1[Source+Pro] (120 clips, identical lists) + UAL2[Source] (134 clips), unzipped in docs/assets/downloads/. Gains: Turn90_L/R + Turn180_L/R (turn-in-place), Sprint_Enter/Exit + Crouch_Enter/Exit (stance transitions), full 8-direction Walk/Jog/Crouch sets incl. diagonals, Counter_Idle + talking/phone/sitting idles (life-sim verbs), plus _RM root-motion variants (unused — in-place is correct for server-authoritative interpolation). Still absent everywhere: walk start/stop + stairs — the only remaining custom clips. Integration is NOT a drop-in swap: upstream renamed clips (Walk_Loop -> Walk_Fwd_Loop etc.), so wire via the design''s recorded plan — explicit library names + lib/Clip addressing + gait-table update. NOTE for facing design: the 8-dir walk sets unlock Q-084''s parked walk-vs-aim split (direction-matched clips relative to facing) — revisit during the S9 tuning session.
|
||
|
||
Live-session feedback (user, 2026-07-06): (1) Corridor cutaway verdict — two minds: ''extremely trippy, could be the game''s own look'' vs ''player cannot see what is in the room unless close''. Resolution: cutaway MODES, toggled live in the sandbox (corridor / bottom-walls-low / both) — bottom-wall rule is data-driven (wall drops to stub when a KNOWN floor tile sits on its camera-far side; camera-facing directions derived from WorldRoot basis at runtime, not hand-derived). Default picked by feel during the session; the trippy corridor stays available as a signature-look option. (2) NEW: mouse-over move-here marker on the hovered tile + optimal path line — client-side A* over the never-evict KNOWN tile store (info-boundary-honest: the character plans only through known tiles; fog is unpathable), 8-dir with diagonal step cost 1 (time-optimal per the no-sqrt2 wire), terrain-cost provider seam (uniform today, Phase-4 terrain later), click executes by streaming ordinary Move* step commands through the existing throttle (zero protocol change, server validates every step), cancelled by WASD override / path invalidation / arrival. Settles more of Q-084 (click-to-move half).
|
||
|
||
RMB gesture vocabulary (user, live session 2026-07-06, added to the path-preview feature): single right-click = walk there (current stance); DOUBLE right-click = sprint there (ladder ToggleStanceUp burst to Sprint via the ordinary command queue, pre-sprint stance RESTORED on arrival; a double upgrades the already-started follow in place); LONG-PRESS right-click (~0.4s, commit on release) = ''take cover at location'', prototyped as go-there-then-Crouch-on-arrival (no restore — crouching was the point). Real cover mechanics (wall adjacency, directional protection) are future combat design; the gesture is the input-vocabulary prototype. WASD always cancels any follow without stance restore (player override is deliberate).
|
||
|
||
Follow-facing refinement (user, live session 2026-07-06): during an RMB path-follow the BODY commits to the leg/movement direction (mouse no longer swings body yaw); the mouse instead drives a LAYERED LOOK-AT — Head bone (~70deg limit) plus torso twist via a spine bone (~30deg) for looking far lateral/behind; beyond their sum the character physically cannot look further without turning (correct). Pure client presentation on the D-249 model; SetFacing continues to ride the wire during follows, so the SERVER vision cone still follows the mouse (diegetic: the character looks where the player points while walking a committed path). Implementation: Godot LookAtModifier3D pair under the CharacterVisual skeleton, influence-faded in/out on follow start/end; rig gains a commit_body_to_motion flag (yaw from leg velocity while set).
|
||
|
||
SIDEQUEST CLOSE-OUT (2026-07-07): all scope delivered and pushed — sandbox (scene, greybox store, rig, gait machine, camera, cutaway modes w/ user-verdict mode-2 default recorded as D-250 amendment), RMB navigation vocabulary, layered head/torso look-at, D-252 view/movement protocol split (server+client), purchased UAL tiers wired (turn-in-place, stance enter/exits), design doc committed to docs/design/t1088-locomotion-sandbox-design.md (the ''design §'' references in sandbox code resolve in-repo now). Design-delta close-out notes: no new Gauntlet room was needed (constraint 12 never triggered, server untouched except D-252); ~40 lines of main.gd boot boilerplate duplicated with Pattern: markers for the T-962 extraction; seek-during-blend + remove_immutable_tracks caveats did not manifest in practice; ual_extended wiring superseded by the purchased-tier ual1/ual2 libraries; 2D select_yaw_target moving-branch is dead code post-D-252 (cleanup rides Phase 5). Remaining feel work parked as T-1096 (S9 live tuning — needs the user). Closing.', NULL, '2026-07-07 12:10:20', '2026-07-07 12:10:20.956', '2026-07-07 12:10:20.956', NULL, '846e89916f601a4622a03b275f200bc6', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FKCER95EK266H8RWPW8XT1F0', 'status', 'backlog', 'done', NULL, '2026-07-07 12:10:20', '2026-07-07 12:10:20.986', '2026-07-07 12:10:20.986', NULL, '3016244358c491462e72331ef063ed35', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRX65YFYFR5RNCM9MCG', 'description', 'Methodology doc analogous to the D-223 naming one: stage-1 register selection from wiki prose, stage-2 structured output {tag, allow, block, weight, trauma_decay_rate}. Defines the Gemma prompt + review at GTTR/wiki authoring.
|
||
|
||
Round 3 reframe: Gemma is a BOUNDED corpus-distillation pass (one read of all wiki -> propose catalog templates -> human-gated), NOT per-body open-vocab generation. Plus core catalog hand-authoring (Miri = cultural meaning + eligibility; Araminta = matching visual_bundle).
|
||
|
||
Round-3 refinement (2026-05-26): reframed as a FOLLOW-ON extension, not a blocker of the core catalog (1005). Runs AFTER the core hand-authored set exists, to propose additional templates (corpus-distillation, human-gated) toward the 40-45 target. Needs an architecture-flavor Gemma methodology doc (analogous to the naming one) defining the extraction prompt + structured output schema + human-review gate.', 'Methodology doc analogous to the D-223 naming one: stage-1 register selection from wiki prose, stage-2 structured output {tag, allow, block, weight, trauma_decay_rate}. Defines the Gemma prompt + review at GTTR/wiki authoring.
|
||
|
||
Round 3 reframe: Gemma is a BOUNDED corpus-distillation pass (one read of all wiki -> propose catalog templates -> human-gated), NOT per-body open-vocab generation. Plus core catalog hand-authoring (Miri = cultural meaning + eligibility; Araminta = matching visual_bundle).
|
||
|
||
Round-3 refinement (2026-05-26): reframed as a FOLLOW-ON extension, not a blocker of the core catalog (1005). Runs AFTER the core hand-authored set exists, to propose additional templates (corpus-distillation, human-gated) toward the 40-45 target. Needs an architecture-flavor Gemma methodology doc (analogous to the naming one) defining the extraction prompt + structured output schema + human-review gate.
|
||
|
||
---
|
||
Refinement (/whats-next 2026-07-07): The stage-2 schema in the description is stale round-2 text — there is no trauma_decay_rate anywhere in schema or code; D-232 round 3 (trait-template model) is authoritative. RESOLVED (user): Gemma proposes TEXT FIELDS ONLY — tag, label, cultural_description, candidate allow_tags/block_tags. Humans set all numeric/eligibility fields with whole-pool knowledge (Miri: gates, base_weight, weight_mods, zone_affinity, corridor_pool/geographic_sector; Araminta: visual_bundle) — the catalog-wide CI guardrails (V-TT-01 pool>=5, V-TT-02 weight<=60%) cannot be satisfied by a per-template extraction pass, so Gemma never sets numbers. Doc target: docs/gemma-architecture-flavor-methodology.md (analogous to docs/gemma-naming-methodology.md). Stage-1 register selection reads the current wiki tree (wiki/star-systems/*/index.md); state that assumption explicitly in the doc — location may move if Q-107 resolves. Q-106 is dissolved: no era-band logic in the doc.', NULL, '2026-07-07 16:57:22', '2026-07-07 16:57:22.053', '2026-07-07 16:57:22.053', NULL, '09163b19207472ac445d6e8fc496c104', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWYHR72SC80F5T0TBW', 'description', 'Apply the flavor profile as a filter over the D-142 zone-type ObjectTag baseline pool: block removed, allow weighted up by weight; dominant wins categorical, weighted-avg continuous. Three-layer: body x district x era-band (depth Q-106).
|
||
|
||
Round 3: this becomes the THREE-PHASE DRAW (body K-draw [K=5/3/1/0 by complexity_tier, SeedChain, coverage-aware] -> district-dominant by zone_affinity -> within-template seed picks) + CI guardrails, per D-232 — not a flat per-body allow/block filter.', 'Apply the flavor profile as a filter over the D-142 zone-type ObjectTag baseline pool: block removed, allow weighted up by weight; dominant wins categorical, weighted-avg continuous. Three-layer: body x district x era-band (depth Q-106).
|
||
|
||
Round 3: this becomes the THREE-PHASE DRAW (body K-draw [K=5/3/1/0 by complexity_tier, SeedChain, coverage-aware] -> district-dominant by zone_affinity -> within-template seed picks) + CI guardrails, per D-232 — not a flat per-body allow/block filter.
|
||
|
||
---
|
||
Refinement (/whats-next 2026-07-07): Paragraph 1 of the description is superseded round-1/2 prose — the "D-142 zone-type ObjectTag baseline pool" is a miscite (D-142 = NPC-behavior zone taxonomy; no such pool exists anywhere) and era-bands were dissolved with Q-106. The round-3 three-phase draw is the whole scope. RESOLVED (user decisions):
|
||
1. "District-dominant" = the TRUE D-243 2048m District tier (4 quarters), NOT the 512m Quarter. The District tier has no code representation in the cascade yet — building the District aggregation (grouping quarters, assigning one dominant template per 2048m District) is IN SCOPE for this ticket. The D-222/D-243 district redefinition was never captured into D-232 — amend D-232 with a dated note pinning "district" = the D-243 2048m tier as part of this work.
|
||
2. The dominant-template pick runs at GenerateSkeleton (NOT "FillChunk head" — FillChunk is pure/cache-free by design per T-987); store the resolved template on skeleton/block tags.
|
||
3. Coverage: thread a body-level district-type-mix aggregate into CityGenerationContext (from settlement placement / the L3-L4 dispatch) so draw_body_vocabulary() is coverage-aware up front (>=1 eligible template per present district type).
|
||
4. Seed the body K-draw from SeedChain::for_body(world_seed, body_id) — NOT the per-dispatch chain — so every city/quarter on a body draws the identical closed vocabulary (D-232 invariant).
|
||
5. Files: server/src/atlas/skeleton_gen.rs is the primary site — replace the shipped flat assign_block_tags/zone_type_hash flavor_index pick (round-1/2 model) with the three-phase draw. The CI guardrails already exist and pass (V-TT-01/V-TT-02 in tooling/economy-db/economy_import/traits.py) — no importer work needed.
|
||
6. geographic_sector remains a SOFT weight, two-part pool join (PR #148 note stands).', NULL, '2026-07-07 16:57:22', '2026-07-07 16:57:22.461', '2026-07-07 16:57:22.461', NULL, 'fedcae768907dabfea9d33e22a2face0', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZCG08B0P6PRNQV8KG', 'description', 'Author the ObjectTag + exterior-material vocabulary the allow/block lists and D-235 grammar reference. Carried over from the retired generator-arch D-READY-9 requirement. Content task, Miri + Araminta.', 'Author the ObjectTag + exterior-material vocabulary the allow/block lists and D-235 grammar reference. Carried over from the retired generator-arch D-READY-9 requirement. Content task, Miri + Araminta.
|
||
|
||
---
|
||
Refinement (/whats-next 2026-07-07): RESOLVED (user): the shipped 28-tag material palette in wiki/economics/architecture_trait_catalog.toml (T-1005) is RATIFIED as canonical. D-235''s example WallMaterial/RoofForm/FacadeRhythm/StreetSurface token lists must be amended to match shipped reality as part of this ticket. Deliverable = formalize-and-validate: (a) a machine-readable tag registry (proposal: wiki/economics/object_tag_vocabulary.toml, imported by economy_import/traits.py) covering every tag used in allow_tags/block_tags/visual_bundle; (b) importer validation that all catalog tags resolve against the registry; (c) fallback-graph validation absorbed from T-1004 (parked to Phase 5): every specific token declares a generic parent (generic_wall/roof/facade/street) and resolution is acyclic — build-time check. Cite Q-049 (ObjectTag ownership/co-maintenance, still open — Miri: cultural meaning, Araminta: visual) — this ticket''s registry + review flow is the practical answer; close or update Q-049 with it. Q-107: the registry is generator-facing and Q-107-invariant like the catalog table; note the location assumption in the file header.', NULL, '2026-07-07 16:57:23', '2026-07-07 16:57:23.405', '2026-07-07 16:57:23.405', NULL, '4286256417fad064caadc02f0defc6fd', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWGDT3AJJE5QD0E3FR', 'description', 'Closed vocabulary by default; a rare per-building wildcard draws a COHERENT whole foreign template (cultural-only — function still passes economic hard gates; never an axis-scramble). Two OPPOSED active drivers: foreign-import (another corridor) scaled UP by cosmopolitanism/centrality/transit/Epicenter tier; heritage-callback (the body''s own corridor heritage sub-pool) scaled UP by remoteness/isolation/conservatism. Passive past-vogue holdover from age (D-217 wear). Sparsity escape-hatch = the SAME mechanism triggered by necessity when the closed vocabulary cannot serve a district. Per D-232.', 'Closed vocabulary by default; a rare per-building wildcard draws a COHERENT whole foreign template (cultural-only — function still passes economic hard gates; never an axis-scramble). Two OPPOSED active drivers: foreign-import (another corridor) scaled UP by cosmopolitanism/centrality/transit/Epicenter tier; heritage-callback (the body''s own corridor heritage sub-pool) scaled UP by remoteness/isolation/conservatism. Passive past-vogue holdover from age (D-217 wear). Sparsity escape-hatch = the SAME mechanism triggered by necessity when the closed vocabulary cannot serve a district. Per D-232.
|
||
|
||
---
|
||
Refinement (/whats-next 2026-07-07): Blocked by T-994 (edge added) — the swerve overrides the three-phase draw; implement after it lands, within this batch. RESOLVED (user): resolve driver mappings now. Proposed mappings to REAL fields (integer bps mods, constants in one tunable block):
|
||
- foreign-import scale-ups: WorldTier::Epicenter / WorldTier::Passage (transit), dominant_faction == mixed (cosmopolitanism), road/rail-graph hub degree where available in context (centrality; else world_tier proxy).
|
||
- heritage-callback scale-ups: remoteness/isolation from star_systems dist_ly / earth_proximity percentile plus absence of Passage tier; conservatism from founding_age_years (older = stronger callback; T-1000 backfilled the field).
|
||
- Placeholder wildcard rate: base 100 bps (1%) per building, driver mods multiplicative, hard cap 300 bps; all constants integer bps per D-010 determinism.
|
||
- Passive past-vogue holdover rides D-217 wear/era; no new fields.
|
||
Data-model prerequisite: extend ArchitectureFlavorRef (server/src/simulation/generator.rs:826, currently a u8 index into trait_selection) to represent an out-of-vocabulary template (e.g. InVocabulary(u8) | Swerve(template_tag)) — the wildcard draws outside the closed K-set by definition.
|
||
Sparsity escape-hatch: the SAME mechanism, necessity-triggered at District-dominant assignment time (2048m tier per T-994 refinement) when zero eligible templates serve the district type post-hard-gate.', NULL, '2026-07-07 16:57:23', '2026-07-07 16:57:23.876', '2026-07-07 16:57:23.876', NULL, '8a1882447dbd25441a6c9d0a6c3ba4eb', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZNNMZPXSEZ7HN778R', 'description', 'Every specific texture/material token declares a generic parent it degrades to: temple_wall_wood -> generic wood_wall placeholder until the specific asset ships, then it upgrades IN PLACE. The logical token a building uses is fixed + deterministic at generation (frozen world); only render fidelity is incremental. This is where patched-in themes/textures live -> NO catalog versioning needed for art (versioning only re-enters if a NEW logical template is added post-launch). Per D-232 + D-235. Cross-refs ticket 988 (exterior visual grammar).', 'Every specific texture/material token declares a generic parent it degrades to: temple_wall_wood -> generic wood_wall placeholder until the specific asset ships, then it upgrades IN PLACE. The logical token a building uses is fixed + deterministic at generation (frozen world); only render fidelity is incremental. This is where patched-in themes/textures live -> NO catalog versioning needed for art (versioning only re-enters if a NEW logical template is added post-launch). Per D-232 + D-235. Cross-refs ticket 988 (exterior visual grammar).
|
||
|
||
---
|
||
Refinement (/whats-next 2026-07-07): PARKED TO PHASE 5 (user decision) — reparented under the Phase 5 epic. D-235 itself marks the patch-upgrade render mechanism Phase 5+/post-launch; the fallback DATA already shipped (T-1005 catalog visual_bundle.fallback maps + the four generic placeholders generic_wall/roof/facade/street). The Phase-4-needed slice (build-time fallback-graph validation: every specific token resolves to a generic, no cycles) moved to T-995. When picked up in Phase 5: the mechanism is client/asset-pipeline resolution (which assets have shipped -> in-place upgrade); coordinate with T-988 (BuildingExteriorTag grammar), T-1050 (production-status catalog, held) and open Q-119 (generic-parent asset set enumeration).', NULL, '2026-07-07 16:57:24', '2026-07-07 16:57:24.538', '2026-07-07 16:57:24.538', NULL, '2f7bc164f3f5c8ec52c75a1352d94520', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZNNMZPXSEZ7HN778R', 'parent_id', 'T-977', 'T-749', NULL, '2026-07-07 16:57:31', '2026-07-07 16:57:31.903', '2026-07-07 16:57:31.903', NULL, '30d225e7be67fc2d91ac18e180a19ffc', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRX65YFYFR5RNCM9MCG', 'status', 'backlog', 'in_progress', NULL, '2026-07-07 17:18:47', '2026-07-07 17:18:47.873', '2026-07-07 17:18:47.873', NULL, '33c494db88791e3acea11b8e08d9a49b', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWYHR72SC80F5T0TBW', 'status', 'backlog', 'in_progress', NULL, '2026-07-07 17:18:47', '2026-07-07 17:18:47.875', '2026-07-07 17:18:47.875', NULL, '022f4ff2df5ad20c9269eea9952ded10', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWGDT3AJJE5QD0E3FR', 'status', 'backlog', 'in_progress', NULL, '2026-07-07 17:18:47', '2026-07-07 17:18:47.876', '2026-07-07 17:18:47.876', NULL, '413acc4af15800667d8dbcae00f00ce2', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZCG08B0P6PRNQV8KG', 'status', 'backlog', 'in_progress', NULL, '2026-07-07 17:18:47', '2026-07-07 17:18:47.876', '2026-07-07 17:18:47.876', NULL, '91996bb1360bb2954c97a01e536ba8b7', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRX65YFYFR5RNCM9MCG', 'status', 'in_progress', 'review', NULL, '2026-07-08 08:01:20', '2026-07-08 08:01:20.004', '2026-07-08 08:01:20.004', NULL, '36e998ca7f413e15bf89aa3147cc627a', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZCG08B0P6PRNQV8KG', 'status', 'in_progress', 'review', NULL, '2026-07-08 08:01:20', '2026-07-08 08:01:20.008', '2026-07-08 08:01:20.008', NULL, '133e5644895f233a0c61a112d54405a5', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWYHR72SC80F5T0TBW', 'status', 'in_progress', 'review', NULL, '2026-07-08 08:01:20', '2026-07-08 08:01:20.008', '2026-07-08 08:01:20.008', NULL, '60ebe4e3cf5bcf3b62aa723e2987d86a', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWGDT3AJJE5QD0E3FR', 'status', 'in_progress', 'review', NULL, '2026-07-08 08:01:20', '2026-07-08 08:01:20.010', '2026-07-08 08:01:20.010', NULL, '4407b55d5c6ca0c5f9244b9db442bfd2', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRX65YFYFR5RNCM9MCG', 'status', 'review', 'done', NULL, '2026-07-08 13:57:21', '2026-07-08 13:57:21.371', '2026-07-08 13:57:21.371', NULL, '111bf664d7dc8ac7e9e64568d45b3f5a', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZCG08B0P6PRNQV8KG', 'status', 'review', 'done', NULL, '2026-07-08 13:57:21', '2026-07-08 13:57:21.375', '2026-07-08 13:57:21.375', NULL, '9080dd67e697dc8c741913212a38b92d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWGDT3AJJE5QD0E3FR', 'status', 'review', 'done', NULL, '2026-07-08 13:57:21', '2026-07-08 13:57:21.375', '2026-07-08 13:57:21.375', NULL, 'c14519c10e49aa58b51649dcc270b207', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWYHR72SC80F5T0TBW', 'status', 'review', 'done', NULL, '2026-07-08 13:57:21', '2026-07-08 13:57:21.375', '2026-07-08 13:57:21.375', NULL, 'c2f0106efbb248444ee8829633830021', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWMZBFV1V6F79VW8S4', 'status', 'backlog', 'done', NULL, '2026-07-08 13:57:27', '2026-07-08 13:57:27.196', '2026-07-08 13:57:27.196', NULL, '8315da7993ab8e37f2e85b04aefc6d78', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZKXHAYMT7Q6WW3XDC', 'description', 'THE primary gap (generator.rs is stubbed). Generate walkable tiles from the block/chunk skeleton: floors, walls, doors, placed objects, using tile-condition thresholds 0.63/0.43/0.23 (D-217). Output is the walkable world data.
|
||
|
||
Refinement (round 2, 2026-05-25): Layer-5 fill is the D-230 on-demand derive phase (<5ms shell derivation Void/Wall/FloorSlab/Roof from the cached tags) plus the BuildingExteriorTag visual grammar and material vocabulary (D-235: WallMaterial/RoofForm/FacadeRhythm/StreetSurface, template-filtered (era = maintenance/wear, not a material gate)) plus interstitial and operations-surface fill driven by BulkClass coverage (D-233). Blocked by 957, 976, 977.
|
||
|
||
Refinement (2026-05-26): READY behind 1006/957/976/977/1005. shell_derive = rectangle-containment + z-range over cached tags (~0.5ms/chunk). FillChunk pre-condition: only after SkeletonGenerated; re-enqueue High if block_tags absent. Wire chunk_streaming.rs to enqueue FillChunk on load-radius entry (no GenerationQueue interaction today). Interstitial token derived from setback_tier (D-235) x position; bulk operations-surface tagged built-infra, not open space. Child 988 = exterior grammar, now 3-step template-filtered (era is wear, not a material gate). Files: gen_queue.rs FillChunk arm, workers/stubs.rs, plugin.rs SkeletonGenerated handler.', 'THE primary gap (generator.rs is stubbed). Generate walkable tiles from the block/chunk skeleton: floors, walls, doors, placed objects, using tile-condition thresholds 0.63/0.43/0.23 (D-217). Output is the walkable world data.
|
||
|
||
Refinement (round 2, 2026-05-25): Layer-5 fill is the D-230 on-demand derive phase (<5ms shell derivation Void/Wall/FloorSlab/Roof from the cached tags) plus the BuildingExteriorTag visual grammar and material vocabulary (D-235: WallMaterial/RoofForm/FacadeRhythm/StreetSurface, template-filtered (era = maintenance/wear, not a material gate)) plus interstitial and operations-surface fill driven by BulkClass coverage (D-233). Blocked by 957, 976, 977.
|
||
|
||
Refinement (2026-05-26): READY behind 1006/957/976/977/1005. shell_derive = rectangle-containment + z-range over cached tags (~0.5ms/chunk). FillChunk pre-condition: only after SkeletonGenerated; re-enqueue High if block_tags absent. Wire chunk_streaming.rs to enqueue FillChunk on load-radius entry (no GenerationQueue interaction today). Interstitial token derived from setback_tier (D-235) x position; bulk operations-surface tagged built-infra, not open space. Child 988 = exterior grammar, now 3-step template-filtered (era is wear, not a material gate). Files: gen_queue.rs FillChunk arm, workers/stubs.rs, plugin.rs SkeletonGenerated handler.
|
||
|
||
---
|
||
Refinement (/whats-next 2026-07-08): SCOPE PINNED post-PR #173. T-987 (shell derivation) shipped; remaining T-959 scope = floors/walls/materials + interstitial fill. RESOLVED (user): "placed objects" DESCOPED — no D-record, vocabulary, or code path exists; exterior props arrive with the asset pipeline and interiors are Phase 6 (cascade). Title updated accordingly. Doors stay deferred to T-979/T-998 (BuildingPropertyTag.doors = empty, commented "#979"). Confirmed non-gaps (Si sweep): D-217 thresholds 0.63/0.43/0.23 unchanged, initial_condition frozen at plan time and consumed by T-999 (not here); Atlas tile-layer visualization is T-960''s scope — T-959''s deliverable is DATA only; chunk_streaming.rs FillChunk enqueue wiring is a deliberate Phase-5 deferral gated by T-962 (per T-987 close-out), not this ticket. D-233 operations-surface fill split to a new child task (BulkClass-driven, distinct from T-988''s density/setback-driven interstitial type).', NULL, '2026-07-08 15:52:56', '2026-07-08 15:52:56.968', '2026-07-08 15:52:56.968', NULL, 'd04423c0091daedf7a1f1340cb558718', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZWSSHC2S5KPKAZ5QR', 'description', '(architecture_flavor x zone_type x era x density) -> BuildingExteriorTag{wall_material, roof_form, setback_tier, facade_rhythm, color_range}. Vocabulary: WallMaterial/RoofForm/FacadeRhythm/StreetSurface (extends D-228 FloorMaterial). 4-step derivation: flavor filter -> zone bias -> era restrict -> density setback -> interstitial type. Color flavor-bounded/era-adjusted/seed-selected.', '(architecture_flavor x zone_type x era x density) -> BuildingExteriorTag{wall_material, roof_form, setback_tier, facade_rhythm, color_range}. Vocabulary: WallMaterial/RoofForm/FacadeRhythm/StreetSurface (extends D-228 FloorMaterial). 4-step derivation: flavor filter -> zone bias -> era restrict -> density setback -> interstitial type. Color flavor-bounded/era-adjusted/seed-selected.
|
||
|
||
---
|
||
Refinement (/whats-next 2026-07-08): AUTHORED-DEPTH v1 (user decision — "deliver what we want to deliver in the first run"; pull Miri + Araminta into the ticket for the content catalog). RESOLVED:
|
||
1. Derivation is 3-STEP, era-free (D-235 amendment / D-232 reframe): template visual_bundle filter -> zone_type bias -> density setback + interstitial type. Drop the stale "era restrict" step and "era-adjusted" color — era reads as wear via D-217 condition, never a material gate.
|
||
2. Phase timing (per the T-994 precedent, same rationale): BuildingExteriorTag is resolved at GenerateSkeleton dispatch/plan time — where context, catalog, and flavor_ref resolution are available — and stored FROZEN on BuildingPropertyTag; FillChunk only reads it (T-987 purity). Swerve(tag) refs resolve against the full catalog at the same point.
|
||
3. trait_catalog_reader must be extended to parse visual_bundle (+ the new fields below) — currently explicitly unparsed ("D-235 territory").
|
||
4. Vocabulary becomes append-only integer-discriminant Rust enums (WallMaterial/RoofForm/FacadeRhythm/StreetSurface), matching the SeedDomain/DistrictType convention; unknown registry strings parse to the axis generic with a tracing warning (patch tolerance). Registry TOML remains the authoring source (V-TT-03/04 validated).
|
||
5. Zone bias is a REAL authored table: per-template zone_type -> token weight overrides (integer bps), authored by Miri (cultural meaning) + Araminta (visual coherence) into the catalog TOML alongside visual_bundle; importer-validated (new V-TT check: referenced tokens exist in the template''s own visual_bundle axis). Uniform fallback where unauthored.
|
||
6. color_range is a NUMERIC model now: per-color_register authored integer ranges (e.g. HSV/OKLCH components as integer bps bands, D-010 — no floats), one table keyed by the 28 color_register values, Araminta-authored; per-building seed pick within the template''s register band, stored as integers on BuildingExteriorTag.
|
||
7. StreetSurface is IN SCOPE here: derived per street/interstitial run with the same template filter (D-235 "same filter as buildings"), stored alongside the interstitial type.
|
||
8. setback_tier: fixed 5-tier vocabulary (zero_lot | tight | standard | generous | campus) derived from BlockSkeleton.density_pct bands (the shipped axis; D-220 DensityClass has no code representation) — thresholds documented as calibration placeholders.
|
||
Content deliverables (Miri + Araminta): zone-bias table + color_register numeric bands for all 28 templates/registers. Code deliverables: reader extension, enums, derivation fn at skeleton time, importer validation, tests.', NULL, '2026-07-08 15:52:57', '2026-07-08 15:52:57.845', '2026-07-08 15:52:57.845', NULL, '84fc98e8708bedffdd91ad226b6e6a18', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXQGAX5GT4PTTBQYGJCV4', 'description', '(description follows in first append)', '(description follows in first append)
|
||
|
||
---
|
||
RECOVERED DESCRIPTION (lost to a same-second create+append LWW tie-break on changelog rebuild; recovered from .pql/changelog/ticket_history/2026-06.sql — pql bug filed upstream): "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)."
|
||
|
||
Refinement (/whats-next 2026-07-08): triage dispositions RESOLVED (user):
|
||
- Q-102: RESOLVED-IN-PRACTICE — close with a resolution note citing D-246 voxel_mosaic (noise basis/keying/determinism), T-1080 (meso gradients), T-1077 (ladder), and D-228''s categorical FloorMaterial override stack (authored features composite without bleed).
|
||
- Q-103: DEFER with dated note — its own text scopes to Phase 5+ save system; T-987 shipped Layer-5 shell fill without mutators (empirical non-blocker). Revisit at Phase-5 save-system kickoff.
|
||
- Q-109: DEFER with dated note — planetary path is the only live source; D-229''s 2026-06-05 amendment carved the station interim. Revisit before stations/mods/save-only bodies.
|
||
- Q-105: CLAIM THE D-RECORD NOW (user decision) — design the region transient mechanics as part of this ticket: seasonal phase stepping, tidal term, weather term, snow/ice depth rise/fall, crop-cycle cadence, recompute-on-phase-change; grounded in D-243 §3/§4 region-clock structure (T-1078) and the three shipped punts (freeze/snow model, region climate stack, water-body gen). Claim via pql decisions claim D architecture; resolve Q-105 against it.
|
||
Deliverables: governance notes for all four Q-records + the new Q-105 D-record. This ticket gates T-959''s start.', NULL, '2026-07-08 15:52:58', '2026-07-08 15:52:58.293', '2026-07-08 15:52:58.293', NULL, '919e715cde9bec58a6007ae86ed73710', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZKXHAYMT7Q6WW3XDC', 'title', 'Layer 5 — Chunk→Tile fill (floors, walls, doors, objects)', 'Layer 5 — Chunk→Tile fill (floors, walls, materials, interstitial)', NULL, '2026-07-08 15:53:07', '2026-07-08 15:53:07.204', '2026-07-08 15:53:07.204', NULL, '6a6d7aa508fe95084af2a868e13e0166', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZKXHAYMT7Q6WW3XDC', 'status', 'backlog', 'in_progress', NULL, '2026-07-08 20:44:50', '2026-07-08 20:44:50.729', '2026-07-08 20:44:50.729', NULL, '0feee4e1684c37612a36da511c19eb0d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZWSSHC2S5KPKAZ5QR', 'status', 'backlog', 'in_progress', NULL, '2026-07-08 20:44:50', '2026-07-08 20:44:50.734', '2026-07-08 20:44:50.734', NULL, '9beaa140649f2715563a6d9199690295', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FM4VQCXZ9JEXPCM4ZQD5WXNW', 'status', 'backlog', 'in_progress', NULL, '2026-07-08 20:44:50', '2026-07-08 20:44:50.734', '2026-07-08 20:44:50.734', NULL, '9d5208a2ef70d0077dc110cb832cd4f6', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXQGAX5GT4PTTBQYGJCV4', 'status', 'backlog', 'in_progress', NULL, '2026-07-08 20:44:50', '2026-07-08 20:44:50.735', '2026-07-08 20:44:50.735', NULL, '8e5e77b2ba2e990390fcc89fadddd2af', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZWSSHC2S5KPKAZ5QR', 'status', 'in_progress', 'review', NULL, '2026-07-11 08:34:23', '2026-07-11 08:34:23.127', '2026-07-11 08:34:23.127', NULL, '3f73ba07eb259af532e55efd90b94457', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZKXHAYMT7Q6WW3XDC', 'status', 'in_progress', 'review', NULL, '2026-07-11 08:34:23', '2026-07-11 08:34:23.130', '2026-07-11 08:34:23.130', NULL, '2bb7676b99d3663b810cddc0a345e2c4', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXQGAX5GT4PTTBQYGJCV4', 'status', 'in_progress', 'review', NULL, '2026-07-11 08:34:23', '2026-07-11 08:34:23.130', '2026-07-11 08:34:23.130', NULL, '38f22584bb357e186b0b816bc16e55d3', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FM4VQCXZ9JEXPCM4ZQD5WXNW', 'status', 'in_progress', 'review', NULL, '2026-07-11 08:34:23', '2026-07-11 08:34:23.130', '2026-07-11 08:34:23.130', NULL, '50bab55442eba405f747c5002ec8093d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FMZZ0184R5B8YMFJW5NWPNXW', 'parent_id', 'T-959', 'T-750', NULL, '2026-07-11 12:54:35', '2026-07-11 12:54:35.373', '2026-07-11 12:54:35.373', NULL, 'b09eacf8ed0d8a96f8e56e5a462dcf02', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZWSSHC2S5KPKAZ5QR', 'status', 'review', 'done', NULL, '2026-07-11 12:54:38', '2026-07-11 12:54:38.771', '2026-07-11 12:54:38.771', NULL, 'c8a1836a9b45795bfe1399605218a60d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FM4VQCXZ9JEXPCM4ZQD5WXNW', 'status', 'review', 'done', NULL, '2026-07-11 12:54:38', '2026-07-11 12:54:38.778', '2026-07-11 12:54:38.778', NULL, 'cc484b2a90166dec75547367ee9d8f59', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZKXHAYMT7Q6WW3XDC', 'status', 'review', 'done', NULL, '2026-07-11 12:54:38', '2026-07-11 12:54:38.779', '2026-07-11 12:54:38.779', NULL, 'e957e4e756f5d5c35c87c2c4c0152512', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXQGAX5GT4PTTBQYGJCV4', 'status', 'review', 'done', NULL, '2026-07-11 12:54:38', '2026-07-11 12:54:38.779', '2026-07-11 12:54:38.779', NULL, 'fe7d55a6b7e05931138edfd2ab6038eb', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FN2TWG2HF2YHQFJFTSGTYS48', 'status', 'backlog', 'review', NULL, '2026-07-13 15:17:49', '2026-07-13 15:17:49.943', '2026-07-13 15:17:49.943', NULL, '7d1b74a4ae29004994cc136983f67c67', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FN2TX5V43575PG96F14AH0N0', 'status', 'backlog', 'review', NULL, '2026-07-13 15:17:49', '2026-07-13 15:17:49.946', '2026-07-13 15:17:49.946', NULL, '5ba04a13dff93d3a25e6b9ec36e98982', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FN2TWSXH3XF64SYP4FS89P7G', 'status', 'backlog', 'review', NULL, '2026-07-13 15:17:49', '2026-07-13 15:17:49.946', '2026-07-13 15:17:49.946', NULL, '699460252071b141a89d5d9534546f41', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FN2VQEJ20NM1RS413DEXCN98', 'status', 'backlog', 'review', NULL, '2026-07-13 15:17:49', '2026-07-13 15:17:49.947', '2026-07-13 15:17:49.947', NULL, '00ad0e8407160a8b2762dacafd9c070a', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FN2TXSWVJGQWV6Q2RF5EF35W', 'status', 'backlog', 'review', NULL, '2026-07-13 15:17:49', '2026-07-13 15:17:49.947', '2026-07-13 15:17:49.947', NULL, '20be933fd4f11023d37e35c4cc182eba', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FN2TXFEDCYPSARF3DYRN9VAG', 'status', 'backlog', 'review', NULL, '2026-07-13 15:17:49', '2026-07-13 15:17:49.947', '2026-07-13 15:17:49.947', NULL, '44bc4642758bc97f87068ca14a0196ea', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FN2VTA380WZT33Q07TJES7Q8', 'status', 'backlog', 'review', NULL, '2026-07-13 15:17:49', '2026-07-13 15:17:49.947', '2026-07-13 15:17:49.947', NULL, '501e74946bff31355ddfa77ab43c7a0d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FN2VXFRB6K4TDBEPVH0P8XHG', 'status', 'backlog', 'review', NULL, '2026-07-13 15:17:49', '2026-07-13 15:17:49.948', '2026-07-13 15:17:49.948', NULL, '656b5fc7411bff5c8089c1d78508d47a', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FN2VQEJ20NM1RS413DEXCN98', 'status', 'review', 'done', NULL, '2026-07-13 20:52:24', '2026-07-13 20:52:24.184', '2026-07-13 20:52:24.184', NULL, 'b1798cf474b5fc21b6ae42d1ff15006c', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FN2VTA380WZT33Q07TJES7Q8', 'status', 'review', 'done', NULL, '2026-07-13 20:52:24', '2026-07-13 20:52:24.191', '2026-07-13 20:52:24.191', NULL, '3ef17f07a663a30d45f478232dcb01b2', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FN2TWSXH3XF64SYP4FS89P7G', 'status', 'review', 'done', NULL, '2026-07-13 20:52:24', '2026-07-13 20:52:24.192', '2026-07-13 20:52:24.192', NULL, '369c8e4d3178d2159b38bb042fe37efa', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FN2VXFRB6K4TDBEPVH0P8XHG', 'status', 'review', 'done', NULL, '2026-07-13 20:52:24', '2026-07-13 20:52:24.192', '2026-07-13 20:52:24.192', NULL, '75e41d00e9f9fdc2fe5514b3dde126a3', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FN2TWG2HF2YHQFJFTSGTYS48', 'status', 'review', 'done', NULL, '2026-07-13 20:52:24', '2026-07-13 20:52:24.192', '2026-07-13 20:52:24.192', NULL, 'a7f836f77d49a9634c845fb251184bf0', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FN2TXFEDCYPSARF3DYRN9VAG', 'status', 'review', 'done', NULL, '2026-07-13 20:52:24', '2026-07-13 20:52:24.193', '2026-07-13 20:52:24.193', NULL, '46ed8d900406448c20b620ea29e9ed05', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FN2TXSWVJGQWV6Q2RF5EF35W', 'status', 'review', 'done', NULL, '2026-07-13 20:52:24', '2026-07-13 20:52:24.193', '2026-07-13 20:52:24.193', NULL, 'a22fb2d151630b93cece5577c18bb13e', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FN2TX5V43575PG96F14AH0N0', 'status', 'review', 'done', NULL, '2026-07-13 20:52:24', '2026-07-13 20:52:24.193', '2026-07-13 20:52:24.193', NULL, 'b62d57f8d12b7a1748ecf05b506e60dd', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FN2TV9HWGK5P7MJ9REHFKVFC', 'status', 'backlog', 'done', NULL, '2026-07-13 20:52:30', '2026-07-13 20:52:30.115', '2026-07-13 20:52:30.115', NULL, 'f4a4c68f4063a550a6ca58cf7a0e660a', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ8BFVNWDH17CMH1YM', 'description', '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.', '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.
|
||
|
||
---
|
||
Refinement (2026-07-13, /whats-next Si audit + Jeroen rulings) — RESCOPE. The 2026-06-07 scope note is obsolete in both directions:
|
||
|
||
DONE ALREADY (record, don''t rebuild):
|
||
- L1 overlays (gen_l1_rivers/basins/attractors) + proxy wire + pending indicator: shipped.
|
||
- District-morphology overlay (gen_district "MRPH"): shipped under T-1046 via AtlasLayerResponse.district_grid — the wiring precedent for everything below.
|
||
- gen_l0_heightmap: DROPPED — relief already renders via the always-on terrain overlay (D-191 §7). D-226 amended (2026-07-13) accordingly.
|
||
|
||
IN SCOPE NOW (this ticket):
|
||
1. gen_l2_roads overlay — L2 road/rail graph (T-1038) is computed on every AnalyzeBody (gen_queue.rs runs up_to=RoadGraph) but never serialized: add RoadGraphLayer field to AtlasLayerResponse (layer_proxy.rs), protocol.gd decode, overlay rendering (edges colored by MaintenanceAuthority, junction markers).
|
||
2. gen_l3_settlements overlay — wire T-955''s computed CityPlacement positions through the proxy (new SettlementLayer field, exact T-1046 precedent) so cities render on generated bodies for the first time (Jeroen ruling: wire positions now; T-949 stays boundary-cleanup).
|
||
3. Left-side legend panel — D-226 item (3) deliverable, never built (shape/color key for attractor types + sub-biomes + the new overlays).
|
||
4. Doc-comment fix: layer_proxy.rs:31-34 claims cascade runs "through CascadeLayer::Settlement" — actually RoadGraph (gen_queue.rs:416); client''s up_to field is ignored by the server. One-line correction.
|
||
|
||
OUT OF SCOPE (explicitly, per 2026-07-13 rulings):
|
||
- L4 quarter footprints → design ticket T-1112 (needs coarse-shape design first).
|
||
- Region climate → prerequisite wiring ticket T-1113 (not in cascade at all yet).
|
||
- L5 chunk/tile fill → NEVER an Atlas map layer (D-191/D-226 amendments 2026-07-13; harness-verified, Phase-5 in-world).
|
||
- markers.json migration / Sol → T-949 / T-1073 (D-236: Sol excluded from deterministic runs, access capped at Oort gateway).
|
||
|
||
Overlay mechanism: follow the shipped always-toggleable pattern (D-226 as amended), NOT the old lock/notify spec.', NULL, '2026-07-13 21:53:23', '2026-07-13 21:53:23.042', '2026-07-13 21:53:23.042', NULL, '3ae0281c74dafba38b3d19b4787b0a84', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW2ZSPJ3D9NEZ6JBW8', 'description', '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.', '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.
|
||
|
||
---
|
||
Refinement (2026-07-13, /whats-next Si audit + Jeroen rulings):
|
||
|
||
SCOPE: the ~2,398 generated (non-Sol) bodies + star_map_data.json only.
|
||
- SOL EXCLUDED (Jeroen): Sol stays out of all deterministic runs; player access is lore-capped at the Oort-cloud gateway station — see D-236 as amended 2026-07-13. Sol''s client-side legacy markers.json read (atlas_viewer.gd::_load_markers) STAYS as the documented D-223/D-236 exception until T-1073 (gated on Q-107). Do not repeat T-1073''s implement→break→revert cycle.
|
||
- CITATION FIX: the description''s "perception-filtered queries (D-012)" should read D-010 (information boundaries). D-012 is chunk-based map architecture — unrelated.
|
||
|
||
CURRENT READ INVENTORY (verified 2026-07-13):
|
||
1. atlas_viewer.gd::_load_markers (~436-467) — markers.json via FileAccess. For non-Sol bodies this is names-only data (D-223); replace with a names request over the bridge (server already reads atlas_city_names via CityContextReader). Positions come from T-960''s SettlementLayer work (separate ticket, same branch).
|
||
2. system_index.gd::get_sorted_systems — star_map_data.json, consumed by atlas_app.gd:150 (Reach screen) + overview_screen.gd:114 (economics monitor selector; its only direct read). star_map_data.json is a build-time bake (tooling/generate-star-map-data.py); the server has NO existing reader — a thin proxy (server reads the same JSON, returns it) is acceptable per the ticket.
|
||
3. OUT OF SCOPE (deliberate, D-225): reliefmap.png / wiki globe image loads stay client-side.
|
||
|
||
PROTOCOL PATTERN: structural disambiguation on the existing IPC stream (Inbound enum: Inputs vs AtlasRequest). Reach-level star-map data is not per-body/cascade-shaped — add NEW request/response types (e.g. StarMapRequest → StarMapResponse), do not shoehorn into AtlasLayerResponse. Per-body names ride the atlas path.', NULL, '2026-07-13 21:53:24', '2026-07-13 21:53:24.830', '2026-07-13 21:53:24.830', NULL, 'ecef2b6cccdc0ad213d3ac4f86a7d0ad', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYEJ0G4F0SBHG379YR', 'description', 'D-226 layer 1 (substrate). Auto-pause the sim when the client enters a fullscreen implant app (the Atlas). Freeze the world-advancing tick phases (Movement/Simulation/Economy/Storyteller/Knowledge/TickAdvance) via run-conditions keyed to a pause command, but KEEP PreInput (gen-drain), Input (receive resume), Snapshot, PostSnapshot (bridge) alive so the UI keeps fetching data while frozen. Reuse the existing TickRate::Paused + the input.rs paused-allowlist seam; trigger from HudGroups::gameplay_occluded (D-170) -> a pause/resume command over the bridge. For static geography pause is a compute-saver; for dynamic state (economics, later) it is essential. Confirm exactly what TickRate::Paused currently gates (whole loop vs sim-advance) and gate at the phase level.', 'D-226 layer 1 (substrate). Auto-pause the sim when the client enters a fullscreen implant app (the Atlas). Freeze the world-advancing tick phases (Movement/Simulation/Economy/Storyteller/Knowledge/TickAdvance) via run-conditions keyed to a pause command, but KEEP PreInput (gen-drain), Input (receive resume), Snapshot, PostSnapshot (bridge) alive so the UI keeps fetching data while frozen. Reuse the existing TickRate::Paused + the input.rs paused-allowlist seam; trigger from HudGroups::gameplay_occluded (D-170) -> a pause/resume command over the bridge. For static geography pause is a compute-saver; for dynamic state (economics, later) it is essential. Confirm exactly what TickRate::Paused currently gates (whole loop vs sim-advance) and gate at the phase level.
|
||
|
||
---
|
||
Refinement (2026-07-13, /whats-next Si audit + lead ruling):
|
||
|
||
CONFIRMED (the ticket''s own open question): TickRate::Paused today gates ONLY the clock — advance_tick (simulation/time.rs:100-110, in TickPhase::TickAdvance) no-ops when Paused. There are ZERO run_if/run-conditions anywhere in the server schedule; tick_phases.rs::configure() only chains ordering. input.rs''s paused-allowlist (input.rs:128,134-155) is an in-system dispatch filter, not a phase gate. So "gate at the phase level" is new plumbing: add .run_if(not paused) to the SystemSet configs for Movement/Simulation/Storyteller/Knowledge/TickAdvance in tick_phases.rs::configure().
|
||
|
||
ECONOMY SPLIT (must not miss): serve_econ_state_query — which services the paused-ALLOWED EconStateQuery — is registered in the same TickPhase::Economy set, .after(tick_economy_simulation) (economy_plugin.rs:27-35). A blanket set-level gate on Economy would break that paused guarantee. Gate tick_economy_simulation individually; leave serve_econ_state_query unconditioned (.after() ordering holds when the upstream system is skipped). All other allowlist entries verified to land on keep-alive phases.
|
||
|
||
BRIDGE: no new protocol needed — PlayerAction::Pause/Unpause work end-to-end (D-088 manual pause; input_mapper.gd:137-139 → sim_bridge.gd action_enum_to_wire:528-531 → receive_bridge_inputs → process_player_input). The ONLY missing piece is client wiring: connect HudGroups.gameplay_occluded (hud_groups.gd:33,63-88) to sending Pause/Unpause via sim_bridge.gd''s outbound queue. Today only implant/map (Atlas, default_mode=fullscreen) triggers occlusion.
|
||
|
||
GEN-DRAIN: confirmed still correct post-T-1046 — GenerationPlugin registers drain_generation_completions + serve_atlas_requests in TickPhase::PreInput (atlas/plugin.rs:52-62); cascade compute is on an independent Rayon pool, so generation keeps flowing while paused. PreInput/Input/Snapshot/PostSnapshot stay alive per the ticket.
|
||
|
||
MANUAL-vs-AUTO PAUSE (the one gap — lead ruling: Option A): track WHETHER THE AUTO-PAUSE CAUSED the pause (a flag distinct from TickRate itself, e.g. auto_pause_active). Auto-resume on implant-close fires Unpause ONLY if auto-pause was the trigger — a prior manual pause (or D-088 Half rate) survives implant close untouched. No previous-rate stack (that''s Option C, deferred).', NULL, '2026-07-13 21:53:25', '2026-07-13 21:53:25.085', '2026-07-13 21:53:25.085', NULL, 'b9d4170174c71d85a36bd62c8be00c73', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBRCMEKT72S0Q6NE68JH7EXC', 'description', '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).', '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).
|
||
|
||
D-236 amended 2026-07-13: player access lore-capped at the Oort-cloud gateway station; Sol permanently excluded from deterministic runs. T-949 (2026-07-13 scoping) explicitly excludes Sol and leaves the legacy markers read in place for this ticket to migrate once Q-107 resolves — Sol''s geometry needs a server-side AUTHORED home, never a cascade path.', NULL, '2026-07-13 21:53:26', '2026-07-13 21:53:26.940', '2026-07-13 21:53:26.940', NULL, '814a6aa15196b19ecc10be00c2b28c60', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ8BFVNWDH17CMH1YM', 'status', 'backlog', 'in_progress', NULL, '2026-07-13 21:54:06', '2026-07-13 21:54:06.361', '2026-07-13 21:54:06.361', NULL, 'ea84832dad04aa38fbbc6993eae1094d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYEJ0G4F0SBHG379YR', 'status', 'backlog', 'in_progress', NULL, '2026-07-13 21:54:06', '2026-07-13 21:54:06.378', '2026-07-13 21:54:06.378', NULL, '252b112df804eb3c43ad50177bc65e70', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW2ZSPJ3D9NEZ6JBW8', 'status', 'backlog', 'in_progress', NULL, '2026-07-13 21:54:06', '2026-07-13 21:54:06.379', '2026-07-13 21:54:06.379', NULL, 'e2cb8bfa8c9865802fa2fa35b135f35b', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ8BFVNWDH17CMH1YM', 'status', 'in_progress', 'review', NULL, '2026-07-14 14:36:24', '2026-07-14 14:36:24.074', '2026-07-14 14:36:24.074', NULL, 'f610c47b468432be2311ffb750fda80a', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW2ZSPJ3D9NEZ6JBW8', 'status', 'in_progress', 'review', NULL, '2026-07-14 14:36:24', '2026-07-14 14:36:24.077', '2026-07-14 14:36:24.077', NULL, '38a216c974f2c48757c2c2d08a9d4d1d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYEJ0G4F0SBHG379YR', 'status', 'in_progress', 'review', NULL, '2026-07-14 14:36:24', '2026-07-14 14:36:24.077', '2026-07-14 14:36:24.077', NULL, 'bdbd4faf5158ae520a7b6e02aa0f0871', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ8BFVNWDH17CMH1YM', 'status', 'review', 'done', NULL, '2026-07-14 16:03:22', '2026-07-14 16:03:22.069', '2026-07-14 16:03:22.069', NULL, 'b754b491146d3be5d46c4bd83eccb4dd', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRYEJ0G4F0SBHG379YR', 'status', 'review', 'done', NULL, '2026-07-14 16:03:22', '2026-07-14 16:03:22.074', '2026-07-14 16:03:22.074', NULL, '08a20f24aa5ecd449aabaca49017d2af', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRW2ZSPJ3D9NEZ6JBW8', 'status', 'review', 'done', NULL, '2026-07-14 16:03:22', '2026-07-14 16:03:22.075', '2026-07-14 16:03:22.075', NULL, '28e7a1cd73d82111ebd5d537666e03a2', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDG73NW7SNCA5Y8JN905QMR', 'description', '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.', '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.
|
||
|
||
---
|
||
Refinement (2026-07-16, /whats-next Si review + gap resolution):
|
||
|
||
1. Specialization key-space (gap): corporations.specialization is unconstrained free text — 20/165 rows hand-seeded prose via the ORPHANED tooling/populate-corporations.sh (raw sqlite3 INSERTs, single commit e05444f70, not in the Makefile or generator_sources.py; nothing in import_economics writes the column). supply_chain_role is 100% NULL, never wired. RESOLUTION: author a corp_specialization controlled vocabulary + source-canonical TOML (mirror the D-237 wiki/economics/specialization_vocabulary.toml pattern), backfill all 165 corps, and key the {CityTenant, Standalone} placement map on it — all in this ticket. Retire/supersede the orphaned populate-corporations.sh as part of the cleanup (hand-seeded DB values violate the source-canonical rule).
|
||
|
||
2. headquarters_body resolution (gap): RESOLUTION — explicitly reuse the most-populated-body-in-system heuristic from populate_atlas_city_names_corps (tooling/economy-db/economy_import/atlas.py:229-233) at import/bake time to backfill headquarters_body for Standalone HQs. Deterministic, install-baked.
|
||
|
||
Si verification notes: all 30 duplicate-name groups in atlas_city_names are 100% reserved=1 rows (zero duplicates among reserved=0) — removal is cleanly scoped. corp_type confirmed degenerate (158 corporation / 7 combine). Consumption side has zero corp/Standalone/Tenant scaffolding: the merge point is greenfield, natural seam is read_body_settlements (server/src/atlas/city_context_reader.rs:268) feeding match_cities (server/src/atlas/attractor_matching.rs).', NULL, '2026-07-16 07:03:52', '2026-07-16 07:03:52.010', '2026-07-16 07:03:52.010', NULL, '706219100a3778e1bb684e56f261852b', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDG73S4ET8KKTK62Z5KFEQM', 'description', '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.', '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.
|
||
|
||
---
|
||
Refinement (2026-07-16, /whats-next Si review + gap resolution):
|
||
|
||
1. Population source (gap): RESOLUTION — pure importer derivation. import_economics computes the per-city population spread from the authored bodies.population on every regen-db run via a documented rank-size (Zipf-style) curve; no per-city population source file. Keep the curve constants named + documented in the importer — tuning is a code change by design. Only POSITION stays seed-derived (D-211). Amend D-242''s "carried down into the city/settlement source data" wording while implementing, to record the derivation rule (derivation-at-import, not hand-authoring).
|
||
|
||
2. settlement_class assignment (gap): RESOLUTION — default every pooled city to PopulationBudget; the D-196 thresholds (>=50k active / <5k ghost) decide state from the baked population. An authored NameLocked override list (small new source TOML) pins hero cities. EconomicTriggered and OrganicGrowth are simulation-time classes per D-196 — out of bake scope.
|
||
|
||
Si verification notes: 463 atlas_city_names rows, all population=0 / settlement_class NULL — claim exact. match_cities (server/src/atlas/attractor_matching.rs) only READS these fields for tiering; nothing assigns them. D-242/D-223/D-211/D-196 chain is consistent; no conflicting open Q-records. Importer entry point: populate_atlas_city_names (tooling/economy-db/economy_import/atlas.py:61-141).', NULL, '2026-07-16 07:03:59', '2026-07-16 07:03:59.490', '2026-07-16 07:03:59.490', NULL, 'c16f372b083f55eb7320bd4e69176176', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDG73NW7SNCA5Y8JN905QMR', 'status', 'backlog', 'in_progress', NULL, '2026-07-16 07:04:05', '2026-07-16 07:04:05.817', '2026-07-16 07:04:05.817', NULL, '35123526cb22e5bb041d10a5101cc9c0', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDG73S4ET8KKTK62Z5KFEQM', 'status', 'backlog', 'in_progress', NULL, '2026-07-16 07:04:05', '2026-07-16 07:04:05.825', '2026-07-16 07:04:05.825', NULL, 'f63fd497fc86304e59dba4e30630f1de', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDG73NW7SNCA5Y8JN905QMR', 'assigned_to', NULL, 'dudley', NULL, '2026-07-16 07:33:41', '2026-07-16 07:33:41.104', '2026-07-16 07:33:41.104', NULL, 'bb6115fa7673749962a397c742061468', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDG73S4ET8KKTK62Z5KFEQM', 'assigned_to', NULL, 'dudley', NULL, '2026-07-16 07:33:41', '2026-07-16 07:33:41.107', '2026-07-16 07:33:41.107', NULL, '03dde46fff5a35876bdb227f008f3d7f', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDG73NW7SNCA5Y8JN905QMR', 'status', 'in_progress', 'review', NULL, '2026-07-16 09:49:28', '2026-07-16 09:49:28.596', '2026-07-16 09:49:28.596', NULL, '7977bc9541bfce61e29855667c0fcdcb', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDG73S4ET8KKTK62Z5KFEQM', 'status', 'in_progress', 'review', NULL, '2026-07-16 09:49:28', '2026-07-16 09:49:28.604', '2026-07-16 09:49:28.604', NULL, '7be819d7fe6d3c5613640599658348d4', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDG73NW7SNCA5Y8JN905QMR', 'status', 'review', 'done', NULL, '2026-07-16 11:08:50', '2026-07-16 11:08:50.978', '2026-07-16 11:08:50.978', NULL, 'd29af2ba9bc5ff62a5d55990eea82614', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDG73S4ET8KKTK62Z5KFEQM', 'status', 'review', 'done', NULL, '2026-07-16 11:08:50', '2026-07-16 11:08:50.980', '2026-07-16 11:08:50.980', NULL, '2b775e39c956ac93cd4a6bacbbc8cedc', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDG73V9R6N024QSFDEJ4R68', 'description', '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.', '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.
|
||
|
||
---
|
||
Refinement (2026-07-16, /whats-next Si review + gap resolution with Jeroen):
|
||
|
||
SCOPE ITEM 0 (added — placement-map correction, precedes hub work): corp_hq_placement.toml over-generalized D-242''s Standalone boundary (bulk_class != NonPhysical -> Standalone gave 95 Standalone / 60 CityTenant, incl. distilleries/wineries/leatherworks as standalone belt settlements). Jeroen''s ruling, faithful to D-242''s own examples: Standalone ONLY where the HQ is itself an industrial complex / company town — extraction/mining/quarrying, heavy vehicle + shipyard manufacturing, heavy energy (refinery/extraction complexes), gate/orbital infrastructure. Everything else CityTenant, explicitly including craft/consumer manufacturing (distilleries, breweries, wineries, ceramics, textiles, furniture), agriculture (estate offices sit in market towns), and high-tech fabs. Re-author per-value (judge each of the 31 value descriptions against this boundary), regen, and amend D-242 to state the boundary explicitly so it cannot be re-coarsened; record Jeroen''s "edge of settlement / clusters" color as CityTenant rendering detail for later phases, not a third placement class.
|
||
|
||
1. Hub selection (gap: no cap formula, no HQ-row identity): RESOLUTION — thread an is_standalone_hq flag through read_body_settlements/CityRecord (join corporations.headquarters_body + proper_name where hq_placement=''Standalone''; the city_context_reader.rs:1165-1170 test comment predicted exactly this threading). Hubs = top-cap by population among NON-HQ cities; cap scales with body size via a documented inline constant (existing workshop-tunable pattern in road_graph.rs), sanity-checked on 2-3 bodies of different sizes.
|
||
|
||
2. Co-location collapse (gap: zero live cases, no rule): RESOLUTION — ship trivial defensive: exact (body_id, name) match collapses to one node keeping lowest id, loud log warning when it ever fires.
|
||
|
||
3. Hybrid minor-settlement attach (gap: no snap threshold, no edge-split machinery): RESOLUTION — engineer''s judgment: design the edge-split representation + pick the snap threshold as a documented inline constant; extend the RoadEdge/RoadNode invariants and the ten existing unit tests accordingly.
|
||
|
||
4. RailHeadFacing (well-specified per Si): add the FoundingOrientation variant (consumers use if-let, no exhaustive-match break), assign via existing RoadGraph::high_connectivity_junctions (degree >= 3, matches D-213''s paula-round3 source), amend D-213, and make the skeleton_gen rotation call inline (Si''s suggested default: face the junction''s dominant incident-edge bearing).
|
||
|
||
Deferred (no preference given): standalone-HQ Zipf population shares stay as-is (e.g. Gate Corporation 909M on GJ251c); the item-0 re-tune shrinks standalone rows to genuine company-towns where a real share is defensible. Revisit if Atlas numbers read wrong.
|
||
|
||
Si verification notes: road_graph.rs has NO hub concept and NO edge-split machinery today (T-1038 treats every placement as a uniform MST node); RoadGraph::high_connectivity_junctions() exists (JUNCTION_DEGREE=3); FoundingOrientation consumers are founding_orientation() and coastal_edge() (if-let, safe); skeleton_gen has zero rail-facing rotation logic (new work, scoped); PR #177 data preconditions verified (population>0 + settlement_class on all rows; standalone HQs present as ordinary rows).', NULL, '2026-07-16 13:34:35', '2026-07-16 13:34:35.724', '2026-07-16 13:34:35.724', NULL, 'be7de02b5348e09ea077e14d1e7be350', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDG73V9R6N024QSFDEJ4R68', 'status', 'backlog', 'in_progress', NULL, '2026-07-16 13:34:42', '2026-07-16 13:34:42.070', '2026-07-16 13:34:42.070', NULL, '59512cd5b886bad98a03e3bbb106b07d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDG73V9R6N024QSFDEJ4R68', 'assigned_to', NULL, 'dudley', NULL, '2026-07-16 13:34:49', '2026-07-16 13:34:49.724', '2026-07-16 13:34:49.724', NULL, '974c9ac15c87788ce7b7bc1af07548d5', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDG73V9R6N024QSFDEJ4R68', 'status', 'in_progress', 'review', NULL, '2026-07-16 14:25:25', '2026-07-16 14:25:25.191', '2026-07-16 14:25:25.191', NULL, '4db8483f0395e003366d0313acca2bbb', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDG73V9R6N024QSFDEJ4R68', 'status', 'review', 'done', NULL, '2026-07-16 15:15:16', '2026-07-16 15:15:16.465', '2026-07-16 15:15:16.465', NULL, '45ac7e300870b581b76c0a195c32ff67', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FNTXF0JB8E6PDQRASQ18E9ER', 'description', 'Si audit of T-960 (2026-07-13): region_profile.rs (T-1078 — RegionProfile, derive_regions_for_body, region_baseline_at_district) is implemented and unit-tested but never called from cascade.rs: no CascadeLayer::Region variant, nothing on BodyWorldState, nothing in the layer proxy. Prerequisite for any climate Atlas overlay (explicitly out of T-960 scope per 2026-07-13 ruling): add the cascade layer, populate BodyWorldState, expose via AtlasLayerResponse following the T-1046 district-grid precedent. The climate OVERLAY itself is a small follow-up once this serves data.', 'Si audit of T-960 (2026-07-13): region_profile.rs (T-1078 — RegionProfile, derive_regions_for_body, region_baseline_at_district) is implemented and unit-tested but never called from cascade.rs: no CascadeLayer::Region variant, nothing on BodyWorldState, nothing in the layer proxy. Prerequisite for any climate Atlas overlay (explicitly out of T-960 scope per 2026-07-13 ruling): add the cascade layer, populate BodyWorldState, expose via AtlasLayerResponse following the T-1046 district-grid precedent. The climate OVERLAY itself is a small follow-up once this serves data.
|
||
|
||
---
|
||
Refinement (2026-07-16, /whats-next Si review): READY, no gaps.
|
||
|
||
Key implementation facts (Si-verified against post-PR#178 main):
|
||
- region_profile.rs (T-1078) exposes exactly what''s needed: RegionProfile{pos, clock: RegionClock{season, weather, mean_temp_c}, latitude_deg, moisture_q}, derive_regions_for_body(...) -> BTreeMap<RegionPos, RegionProfile>, region_baseline_at_district(...). Deterministic, unit-tested.
|
||
- CRITICAL: district_profile.rs::derive_all_districts (~1434-1509) ALREADY builds the region cache internally (incl. neighbours for edge-fuzz) and discards it — this ticket is retention, not new derivation. Chosen shape: option (a) — independent CascadeLayer::Region step in run_cascade_from_heightmap (one-layer-one-concern, mirrors existing layers; accept the cheap double-derive).
|
||
- CascadeLayer Ord today: Heightmap < Topography < Settlement < DistrictProfile < RoadGraph. Region slots as its own step.
|
||
- BodyWorldState: add pub regions: BTreeMap<RegionPos, RegionProfile> per the districts precedent (same determinism rationale, same empty-until-run convention). Footprint trivial (~195×98 max).
|
||
- layer_proxy.rs doc comment (76-79) already earmarks T-1113 as one of the two final layer fields. Mirror build_district_grid: RegionGridLayer + build_region_grid(state) -> Option<...>, called from handle_atlas_request cache-hit branch. Encoding: dense row-major grid per the T-1046 precedent (implementer''s low-stakes call on exact fields/quantization).
|
||
- Client wire-decode IS in scope (one line): protocol.gd::atlas_response_from_raw raw.get("region_grid") passthrough, matching district_grid. The VISUAL overlay (atlas_viewer/marker_overlay/legend) is explicitly OUT of scope — small follow-up per D-226 amendment (a) incremental-overlay pattern.
|
||
- Edge-fuzz (D-243 §4) is consumer-side sampling behavior already implemented in region_baseline_at_district — not this ticket''s concern.
|
||
- Q-105 resolved into D-243; RegionClock tick-phase callbacks stay deferred — only the mean-state fields are served.', NULL, '2026-07-16 16:28:52', '2026-07-16 16:28:52.948', '2026-07-16 16:28:52.948', NULL, '28022a866ff419d9ac72dca1c7f5e0fe', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FNTXEM9NM5M5SX9WQAAA40SC', 'description', 'Si audit of T-960 (2026-07-13): L4 quarter/block skeletons (T-957/T-976) auto-generate server-side into BodyWorldState.quarters, but carry full per-block zoning/street/tag detail — too fine for a planetary map, and unlike the district grid there is no existing coarse shape to reuse. DESIGN ticket (Araminta encoding + Tyre data shape) before any wiring: define a QuarterFootprintLayer (city outline + aggregate stats?) for AtlasLayerResponse and its overlay encoding per the D-226 amended (2026-07-13) overlay pattern. Wiring is a follow-up once the design is recorded.', 'Si audit of T-960 (2026-07-13): L4 quarter/block skeletons (T-957/T-976) auto-generate server-side into BodyWorldState.quarters, but carry full per-block zoning/street/tag detail — too fine for a planetary map, and unlike the district grid there is no existing coarse shape to reuse. DESIGN ticket (Araminta encoding + Tyre data shape) before any wiring: define a QuarterFootprintLayer (city outline + aggregate stats?) for AtlasLayerResponse and its overlay encoding per the D-226 amended (2026-07-13) overlay pattern. Wiring is a follow-up once the design is recorded.
|
||
|
||
---
|
||
Refinement (2026-07-16, /whats-next Si review): READY, one scoping note made explicit.
|
||
|
||
- DELIVERABLE FORMAT (was unpinned): record the design as a **D-226 amendment** — the established mechanism (the 2026-07-13 overlay pattern itself was recorded that way); no docs/design Atlas-overlay doc precedent exists (T-1046 shipped design-in-ticket+code-comments). The design pass ends at the recorded amendment; the wiring follow-up ticket is filed by the lead afterwards, not by the design pass.
|
||
- BINDING CONSTRAINT: D-226 amendment (d) is a hard ceiling — planetary Atlas tops out at settlement/quarter-skeleton granularity with AT MOST aggregate stats. No per-block zoning/street/tag detail at planetary scale. City outline + aggregate stats only.
|
||
- DATA SOURCE: BodyWorldState.quarters stores QuarterWorldState{skeleton: QuarterSkeleton, block_tags: BTreeMap<(u8,u8), Vec<BuildingPropertyTag>>}; QuarterSkeleton carries [[BlockSkeleton;4];4] with zoning/district_type/density_pct/landmark + reservations/corridors. All aggregatable (density avg, dominant zoning/district-type mix, landmark count, corridor count) without inventing new simulation truth — same derivation class as build_district_grid/build_settlement_layer.
|
||
- PRECEDENT TO IMITATE (five touch points, each with a working example): server AtlasLayerResponse field + build_quarter_footprint_layer() mirroring build_district_grid (keyed off non-empty state.quarters); client OVERLAY_DEFS gen_* id (atlas_viewer.gd), _draw_gen_* fn (atlas_marker_overlay.gd, imitate _draw_gen_district ~185-188), GENERATION_LEGEND entry (atlas_legend_panel.gd). These are named in the amendment for the wiring follow-up — not implemented in this ticket.
|
||
- PARTICIPANT SPLIT: Tyre owns the aggregate-stats data shape (fields, structure, D-010 integer discipline); Araminta owns the overlay encoding (outline vs filled block, color axis per the shape-vs-color convention in atlas_legend_panel.gd) — the same division D-226 originally used. Two coordinated agents, not a workshop round.
|
||
- pql metadata quirk noted: the ticket''s decision_ref D-226 resolves to a wrong title in show-summary; `pql decisions read D-226` returns the correct record.', NULL, '2026-07-16 16:29:00', '2026-07-16 16:29:00.676', '2026-07-16 16:29:00.676', NULL, '175b39a57958906d4f3d80816499a617', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FNTXEM9NM5M5SX9WQAAA40SC', 'status', 'backlog', 'in_progress', NULL, '2026-07-16 16:29:07', '2026-07-16 16:29:07.857', '2026-07-16 16:29:07.857', NULL, '672f4ada58be5b83ccd4eb0db737843c', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FNTXF0JB8E6PDQRASQ18E9ER', 'status', 'backlog', 'in_progress', NULL, '2026-07-16 16:29:07', '2026-07-16 16:29:07.859', '2026-07-16 16:29:07.859', NULL, '0982ecc37d460add179eae8491ce496d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FNTXF0JB8E6PDQRASQ18E9ER', 'assigned_to', NULL, 'dudley', NULL, '2026-07-16 16:29:14', '2026-07-16 16:29:14.525', '2026-07-16 16:29:14.525', NULL, 'eda3d1391d0ea48a59277fd6486cdbe5', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FNTXEM9NM5M5SX9WQAAA40SC', 'assigned_to', NULL, 'tyre', NULL, '2026-07-16 16:29:22', '2026-07-16 16:29:22.162', '2026-07-16 16:29:22.162', NULL, 'c9cfbbab6a28aa1e01b21c60f30624f5', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FNTXEM9NM5M5SX9WQAAA40SC', 'status', 'in_progress', 'review', NULL, '2026-07-16 17:08:34', '2026-07-16 17:08:34.002', '2026-07-16 17:08:34.002', NULL, '164946c94d6d95e2e7d6b1403d70d68a', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FNTXF0JB8E6PDQRASQ18E9ER', 'status', 'in_progress', 'review', NULL, '2026-07-16 17:08:34', '2026-07-16 17:08:34.005', '2026-07-16 17:08:34.005', NULL, 'bc87116dbb3c7aa92437d29d457a2b51', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FNTXEM9NM5M5SX9WQAAA40SC', 'status', 'review', 'done', NULL, '2026-07-16 17:24:54', '2026-07-16 17:24:54.844', '2026-07-16 17:24:54.844', NULL, '8a99c8b7ea756572523471e9dc89ccf2', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FNTXF0JB8E6PDQRASQ18E9ER', 'status', 'review', 'done', NULL, '2026-07-16 17:24:54', '2026-07-16 17:24:54.846', '2026-07-16 17:24:54.846', NULL, '71b133f7f788c56ae887746d097290e9', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPQXK8D6YVWVC2TB2ZR25K6G', 'status', 'backlog', 'in_progress', NULL, '2026-07-16 17:30:59', '2026-07-16 17:30:59.851', '2026-07-16 17:30:59.851', NULL, '724b47769f20cc8e6035e910bdd088fb', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPQXK8D6YVWVC2TB2ZR25K6G', 'assigned_to', NULL, 'stig', NULL, '2026-07-16 17:31:07', '2026-07-16 17:31:07.367', '2026-07-16 17:31:07.367', NULL, '35ca5550701796deddc807d8768da485', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPQXK8D6YVWVC2TB2ZR25K6G', 'status', 'in_progress', 'review', NULL, '2026-07-16 18:36:30', '2026-07-16 18:36:30.146', '2026-07-16 18:36:30.146', NULL, '49e8cbce555de010d3c9dc571f34aacf', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPQXK8D6YVWVC2TB2ZR25K6G', 'status', 'review', 'done', NULL, '2026-07-16 19:43:56', '2026-07-16 19:43:56.313', '2026-07-16 19:43:56.313', NULL, 'fe698fe8c23007f9007197b370476c38', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPRZX1PJ55V7462N56ME2QZ0', 'status', 'backlog', 'in_progress', NULL, '2026-07-16 19:55:54', '2026-07-16 19:55:54.663', '2026-07-16 19:55:54.663', NULL, '326347510db12702d6ec7bea396a3df5', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPRZX1PJ55V7462N56ME2QZ0', 'assigned_to', NULL, 'dudley', NULL, '2026-07-16 19:56:02', '2026-07-16 19:56:02.144', '2026-07-16 19:56:02.144', NULL, 'e1f4abe4a51a17463c14dbe68e85f24f', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPRZX1PJ55V7462N56ME2QZ0', 'status', 'in_progress', 'review', NULL, '2026-07-16 20:31:20', '2026-07-16 20:31:20.627', '2026-07-16 20:31:20.627', NULL, '6d6a4755a90f4c6e87cd1f33d03ce397', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPRZX1PJ55V7462N56ME2QZ0', 'status', 'review', 'done', NULL, '2026-07-16 20:36:46', '2026-07-16 20:36:46.488', '2026-07-16 20:36:46.488', NULL, 'e3c840b23066917cd35f62ef3e0e1492', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPS6QD5FG9TC2WXTDVA44FPW', 'description', 'T-1123 zoom-ladder finding (2026-07-16, first-ever look at district-resolution maps; images in .cache/screenshots/district-windows, evidence /tmp/district-windows). At w256 (524km) the district layer reads as coherent geography (coastal band sequences, legible coasts — but bilinear-smooth: rounded corners of ~156km heightmap pixels visible, no invented bays). At w64 (131km) it degenerates to razor-straight gradient stripes; at w16 (33km) a single flat color. MECHANISM (code-grounded by Dudley): derive_district classifies morphology from ocean_fraction_q = RAW BILINEAR of the ocean mask (district_profile.rs:1318 — no domain warp, no scatter), and the D-227 detail-scatter amplitude is slaved to local_slope of the coarse heightmap (1301-1303) — near zero on low-relief coastal plains, so invention collapses exactly where coastlines live. The scatter itself works (visible as cloudy texture in w256 elev panels) but barely feeds classification and never feeds the coastline. NEEDED: the D-227 invention (interpolation + domain warp + detail-scatter) must carry geographic content into district classification — warped coastline sampling, slope-independent scatter floor, invented drainage/relief between heightmap pixels. This is the heart of the Phase-4 deliverable (deterministic walkable-world data that reads as geography) and blocks T-1124''s regional map view being worth looking at below ~500km. Determinism verified byte-identical cross-process — the substrate is sound; it is the content of the invention that is missing. Reproduce: cargo run --bin aliveness_probe -- --body GJ380c --seed 42 --render /tmp/out --window 64.', 'T-1123 zoom-ladder finding (2026-07-16, first-ever look at district-resolution maps; images in .cache/screenshots/district-windows, evidence /tmp/district-windows). At w256 (524km) the district layer reads as coherent geography (coastal band sequences, legible coasts — but bilinear-smooth: rounded corners of ~156km heightmap pixels visible, no invented bays). At w64 (131km) it degenerates to razor-straight gradient stripes; at w16 (33km) a single flat color. MECHANISM (code-grounded by Dudley): derive_district classifies morphology from ocean_fraction_q = RAW BILINEAR of the ocean mask (district_profile.rs:1318 — no domain warp, no scatter), and the D-227 detail-scatter amplitude is slaved to local_slope of the coarse heightmap (1301-1303) — near zero on low-relief coastal plains, so invention collapses exactly where coastlines live. The scatter itself works (visible as cloudy texture in w256 elev panels) but barely feeds classification and never feeds the coastline. NEEDED: the D-227 invention (interpolation + domain warp + detail-scatter) must carry geographic content into district classification — warped coastline sampling, slope-independent scatter floor, invented drainage/relief between heightmap pixels. This is the heart of the Phase-4 deliverable (deterministic walkable-world data that reads as geography) and blocks T-1124''s regional map view being worth looking at below ~500km. Determinism verified byte-identical cross-process — the substrate is sound; it is the content of the invention that is missing. Reproduce: cargo run --bin aliveness_probe -- --body GJ380c --seed 42 --render /tmp/out --window 64.
|
||
|
||
Jeroen''s design ruling (2026-07-17, pre-refinement): CRINKLE SHOULD VARY. The invented coastline/terrain detail must not be a single global roughness constant or uniform scatter floor — its amplitude and character vary from place to place. Candidate drivers to pin during refinement/implementation (lead''s interpretation, Si to ground in what derive_district already carries): geological context (tectonic_class, glaciation_grade — fjord coasts jagged, deltas smooth, cliff coasts sharp, alluvial plains gentle), climate signals, and seeded spatial heterogeneity so stretches of the same coast differ. The variation itself must be deterministic (seed+position), per D-227/D-010.', NULL, '2026-07-17 05:29:10', '2026-07-17 05:29:10.686', '2026-07-17 05:29:10.686', NULL, '2e918d8dc5ef41b56a3e35aedce12ec8', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPS6QD5FG9TC2WXTDVA44FPW', 'description', 'T-1123 zoom-ladder finding (2026-07-16, first-ever look at district-resolution maps; images in .cache/screenshots/district-windows, evidence /tmp/district-windows). At w256 (524km) the district layer reads as coherent geography (coastal band sequences, legible coasts — but bilinear-smooth: rounded corners of ~156km heightmap pixels visible, no invented bays). At w64 (131km) it degenerates to razor-straight gradient stripes; at w16 (33km) a single flat color. MECHANISM (code-grounded by Dudley): derive_district classifies morphology from ocean_fraction_q = RAW BILINEAR of the ocean mask (district_profile.rs:1318 — no domain warp, no scatter), and the D-227 detail-scatter amplitude is slaved to local_slope of the coarse heightmap (1301-1303) — near zero on low-relief coastal plains, so invention collapses exactly where coastlines live. The scatter itself works (visible as cloudy texture in w256 elev panels) but barely feeds classification and never feeds the coastline. NEEDED: the D-227 invention (interpolation + domain warp + detail-scatter) must carry geographic content into district classification — warped coastline sampling, slope-independent scatter floor, invented drainage/relief between heightmap pixels. This is the heart of the Phase-4 deliverable (deterministic walkable-world data that reads as geography) and blocks T-1124''s regional map view being worth looking at below ~500km. Determinism verified byte-identical cross-process — the substrate is sound; it is the content of the invention that is missing. Reproduce: cargo run --bin aliveness_probe -- --body GJ380c --seed 42 --render /tmp/out --window 64.
|
||
|
||
Jeroen''s design ruling (2026-07-17, pre-refinement): CRINKLE SHOULD VARY. The invented coastline/terrain detail must not be a single global roughness constant or uniform scatter floor — its amplitude and character vary from place to place. Candidate drivers to pin during refinement/implementation (lead''s interpretation, Si to ground in what derive_district already carries): geological context (tectonic_class, glaciation_grade — fjord coasts jagged, deltas smooth, cliff coasts sharp, alluvial plains gentle), climate signals, and seeded spatial heterogeneity so stretches of the same coast differ. The variation itself must be deterministic (seed+position), per D-227/D-010.', 'T-1123 zoom-ladder finding (2026-07-16, first-ever look at district-resolution maps; images in .cache/screenshots/district-windows, evidence /tmp/district-windows). At w256 (524km) the district layer reads as coherent geography (coastal band sequences, legible coasts — but bilinear-smooth: rounded corners of ~156km heightmap pixels visible, no invented bays). At w64 (131km) it degenerates to razor-straight gradient stripes; at w16 (33km) a single flat color. MECHANISM (code-grounded by Dudley): derive_district classifies morphology from ocean_fraction_q = RAW BILINEAR of the ocean mask (district_profile.rs:1318 — no domain warp, no scatter), and the D-227 detail-scatter amplitude is slaved to local_slope of the coarse heightmap (1301-1303) — near zero on low-relief coastal plains, so invention collapses exactly where coastlines live. The scatter itself works (visible as cloudy texture in w256 elev panels) but barely feeds classification and never feeds the coastline. NEEDED: the D-227 invention (interpolation + domain warp + detail-scatter) must carry geographic content into district classification — warped coastline sampling, slope-independent scatter floor, invented drainage/relief between heightmap pixels. This is the heart of the Phase-4 deliverable (deterministic walkable-world data that reads as geography) and blocks T-1124''s regional map view being worth looking at below ~500km. Determinism verified byte-identical cross-process — the substrate is sound; it is the content of the invention that is missing. Reproduce: cargo run --bin aliveness_probe -- --body GJ380c --seed 42 --render /tmp/out --window 64.
|
||
|
||
Jeroen''s design ruling (2026-07-17, pre-refinement): CRINKLE SHOULD VARY. The invented coastline/terrain detail must not be a single global roughness constant or uniform scatter floor — its amplitude and character vary from place to place. Candidate drivers to pin during refinement/implementation (lead''s interpretation, Si to ground in what derive_district already carries): geological context (tectonic_class, glaciation_grade — fjord coasts jagged, deltas smooth, cliff coasts sharp, alluvial plains gentle), climate signals, and seeded spatial heterogeneity so stretches of the same coast differ. The variation itself must be deterministic (seed+position), per D-227/D-010.
|
||
|
||
Jeroen''s ruling, elaborated (2026-07-17): derive coastline variation from EXISTING body settings + lat/long — do not author new knobs. Some places fjordy, some smooth; some planets have tectonics, some are prone to higher erosion. Two driver tiers: (1) BODY-level — the variation already in body parameters (planet_class, atmosphere, hydrosphere, axial tilt, radius, and whatever tectonic/erosion signals exist or are derivable from them) sets each body''s coastline character envelope; (2) POSITION-level — latitude/longitude and the derived district context (glaciation_grade, tectonic_class, climate bands) modulate within it: high-latitude glaciated coasts go fjordy, humid climates erode smooth, arid/tectonic coasts stay sharp. The point: two planets should have recognisably different coastline personalities, and one planet''s coasts should vary by where you are — all deterministic from seed+body+position, zero new authored data.', NULL, '2026-07-17 05:30:58', '2026-07-17 05:30:58.591', '2026-07-17 05:30:58.591', NULL, '960ed4bdf97d679bf3f1d6cd05eaba8e', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPS6QD5FG9TC2WXTDVA44FPW', 'description', 'T-1123 zoom-ladder finding (2026-07-16, first-ever look at district-resolution maps; images in .cache/screenshots/district-windows, evidence /tmp/district-windows). At w256 (524km) the district layer reads as coherent geography (coastal band sequences, legible coasts — but bilinear-smooth: rounded corners of ~156km heightmap pixels visible, no invented bays). At w64 (131km) it degenerates to razor-straight gradient stripes; at w16 (33km) a single flat color. MECHANISM (code-grounded by Dudley): derive_district classifies morphology from ocean_fraction_q = RAW BILINEAR of the ocean mask (district_profile.rs:1318 — no domain warp, no scatter), and the D-227 detail-scatter amplitude is slaved to local_slope of the coarse heightmap (1301-1303) — near zero on low-relief coastal plains, so invention collapses exactly where coastlines live. The scatter itself works (visible as cloudy texture in w256 elev panels) but barely feeds classification and never feeds the coastline. NEEDED: the D-227 invention (interpolation + domain warp + detail-scatter) must carry geographic content into district classification — warped coastline sampling, slope-independent scatter floor, invented drainage/relief between heightmap pixels. This is the heart of the Phase-4 deliverable (deterministic walkable-world data that reads as geography) and blocks T-1124''s regional map view being worth looking at below ~500km. Determinism verified byte-identical cross-process — the substrate is sound; it is the content of the invention that is missing. Reproduce: cargo run --bin aliveness_probe -- --body GJ380c --seed 42 --render /tmp/out --window 64.
|
||
|
||
Jeroen''s design ruling (2026-07-17, pre-refinement): CRINKLE SHOULD VARY. The invented coastline/terrain detail must not be a single global roughness constant or uniform scatter floor — its amplitude and character vary from place to place. Candidate drivers to pin during refinement/implementation (lead''s interpretation, Si to ground in what derive_district already carries): geological context (tectonic_class, glaciation_grade — fjord coasts jagged, deltas smooth, cliff coasts sharp, alluvial plains gentle), climate signals, and seeded spatial heterogeneity so stretches of the same coast differ. The variation itself must be deterministic (seed+position), per D-227/D-010.
|
||
|
||
Jeroen''s ruling, elaborated (2026-07-17): derive coastline variation from EXISTING body settings + lat/long — do not author new knobs. Some places fjordy, some smooth; some planets have tectonics, some are prone to higher erosion. Two driver tiers: (1) BODY-level — the variation already in body parameters (planet_class, atmosphere, hydrosphere, axial tilt, radius, and whatever tectonic/erosion signals exist or are derivable from them) sets each body''s coastline character envelope; (2) POSITION-level — latitude/longitude and the derived district context (glaciation_grade, tectonic_class, climate bands) modulate within it: high-latitude glaciated coasts go fjordy, humid climates erode smooth, arid/tectonic coasts stay sharp. The point: two planets should have recognisably different coastline personalities, and one planet''s coasts should vary by where you are — all deterministic from seed+body+position, zero new authored data.', 'T-1123 zoom-ladder finding (2026-07-16, first-ever look at district-resolution maps; images in .cache/screenshots/district-windows, evidence /tmp/district-windows). At w256 (524km) the district layer reads as coherent geography (coastal band sequences, legible coasts — but bilinear-smooth: rounded corners of ~156km heightmap pixels visible, no invented bays). At w64 (131km) it degenerates to razor-straight gradient stripes; at w16 (33km) a single flat color. MECHANISM (code-grounded by Dudley): derive_district classifies morphology from ocean_fraction_q = RAW BILINEAR of the ocean mask (district_profile.rs:1318 — no domain warp, no scatter), and the D-227 detail-scatter amplitude is slaved to local_slope of the coarse heightmap (1301-1303) — near zero on low-relief coastal plains, so invention collapses exactly where coastlines live. The scatter itself works (visible as cloudy texture in w256 elev panels) but barely feeds classification and never feeds the coastline. NEEDED: the D-227 invention (interpolation + domain warp + detail-scatter) must carry geographic content into district classification — warped coastline sampling, slope-independent scatter floor, invented drainage/relief between heightmap pixels. This is the heart of the Phase-4 deliverable (deterministic walkable-world data that reads as geography) and blocks T-1124''s regional map view being worth looking at below ~500km. Determinism verified byte-identical cross-process — the substrate is sound; it is the content of the invention that is missing. Reproduce: cargo run --bin aliveness_probe -- --body GJ380c --seed 42 --render /tmp/out --window 64.
|
||
|
||
Jeroen''s design ruling (2026-07-17, pre-refinement): CRINKLE SHOULD VARY. The invented coastline/terrain detail must not be a single global roughness constant or uniform scatter floor — its amplitude and character vary from place to place. Candidate drivers to pin during refinement/implementation (lead''s interpretation, Si to ground in what derive_district already carries): geological context (tectonic_class, glaciation_grade — fjord coasts jagged, deltas smooth, cliff coasts sharp, alluvial plains gentle), climate signals, and seeded spatial heterogeneity so stretches of the same coast differ. The variation itself must be deterministic (seed+position), per D-227/D-010.
|
||
|
||
Jeroen''s ruling, elaborated (2026-07-17): derive coastline variation from EXISTING body settings + lat/long — do not author new knobs. Some places fjordy, some smooth; some planets have tectonics, some are prone to higher erosion. Two driver tiers: (1) BODY-level — the variation already in body parameters (planet_class, atmosphere, hydrosphere, axial tilt, radius, and whatever tectonic/erosion signals exist or are derivable from them) sets each body''s coastline character envelope; (2) POSITION-level — latitude/longitude and the derived district context (glaciation_grade, tectonic_class, climate bands) modulate within it: high-latitude glaciated coasts go fjordy, humid climates erode smooth, arid/tectonic coasts stay sharp. The point: two planets should have recognisably different coastline personalities, and one planet''s coasts should vary by where you are — all deterministic from seed+body+position, zero new authored data.
|
||
|
||
Jeroen, further (2026-07-17): ''more ocean is more wet and rainy, for instance'' — hydrosphere/ocean coverage as a tier-1 driver chain: large hydrosphere -> wetter, rainier climate -> HIGHER EROSION -> smoother, more mature coastlines (and more dendritic/eroded relief); small hydrosphere / thin atmosphere -> dry -> sharp, young, uneroded coasts. Erosion-proneness therefore need not be a new authored field — it is derivable from hydrosphere + atmosphere + precipitation, compounding with the tectonic/glaciation drivers. Note for implementation: hydrosphere already feeds moisture derivation (T-1034 fixed the vocab fall-through), so part of this chain exists — the new link is wet/rainy feeding COASTLINE/relief character, not just biome wetness.', NULL, '2026-07-17 05:32:00', '2026-07-17 05:32:00.843', '2026-07-17 05:32:00.843', NULL, 'aff24c00645457ce4122e705900a685c', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPS6QD5FG9TC2WXTDVA44FPW', 'description', 'T-1123 zoom-ladder finding (2026-07-16, first-ever look at district-resolution maps; images in .cache/screenshots/district-windows, evidence /tmp/district-windows). At w256 (524km) the district layer reads as coherent geography (coastal band sequences, legible coasts — but bilinear-smooth: rounded corners of ~156km heightmap pixels visible, no invented bays). At w64 (131km) it degenerates to razor-straight gradient stripes; at w16 (33km) a single flat color. MECHANISM (code-grounded by Dudley): derive_district classifies morphology from ocean_fraction_q = RAW BILINEAR of the ocean mask (district_profile.rs:1318 — no domain warp, no scatter), and the D-227 detail-scatter amplitude is slaved to local_slope of the coarse heightmap (1301-1303) — near zero on low-relief coastal plains, so invention collapses exactly where coastlines live. The scatter itself works (visible as cloudy texture in w256 elev panels) but barely feeds classification and never feeds the coastline. NEEDED: the D-227 invention (interpolation + domain warp + detail-scatter) must carry geographic content into district classification — warped coastline sampling, slope-independent scatter floor, invented drainage/relief between heightmap pixels. This is the heart of the Phase-4 deliverable (deterministic walkable-world data that reads as geography) and blocks T-1124''s regional map view being worth looking at below ~500km. Determinism verified byte-identical cross-process — the substrate is sound; it is the content of the invention that is missing. Reproduce: cargo run --bin aliveness_probe -- --body GJ380c --seed 42 --render /tmp/out --window 64.
|
||
|
||
Jeroen''s design ruling (2026-07-17, pre-refinement): CRINKLE SHOULD VARY. The invented coastline/terrain detail must not be a single global roughness constant or uniform scatter floor — its amplitude and character vary from place to place. Candidate drivers to pin during refinement/implementation (lead''s interpretation, Si to ground in what derive_district already carries): geological context (tectonic_class, glaciation_grade — fjord coasts jagged, deltas smooth, cliff coasts sharp, alluvial plains gentle), climate signals, and seeded spatial heterogeneity so stretches of the same coast differ. The variation itself must be deterministic (seed+position), per D-227/D-010.
|
||
|
||
Jeroen''s ruling, elaborated (2026-07-17): derive coastline variation from EXISTING body settings + lat/long — do not author new knobs. Some places fjordy, some smooth; some planets have tectonics, some are prone to higher erosion. Two driver tiers: (1) BODY-level — the variation already in body parameters (planet_class, atmosphere, hydrosphere, axial tilt, radius, and whatever tectonic/erosion signals exist or are derivable from them) sets each body''s coastline character envelope; (2) POSITION-level — latitude/longitude and the derived district context (glaciation_grade, tectonic_class, climate bands) modulate within it: high-latitude glaciated coasts go fjordy, humid climates erode smooth, arid/tectonic coasts stay sharp. The point: two planets should have recognisably different coastline personalities, and one planet''s coasts should vary by where you are — all deterministic from seed+body+position, zero new authored data.
|
||
|
||
Jeroen, further (2026-07-17): ''more ocean is more wet and rainy, for instance'' — hydrosphere/ocean coverage as a tier-1 driver chain: large hydrosphere -> wetter, rainier climate -> HIGHER EROSION -> smoother, more mature coastlines (and more dendritic/eroded relief); small hydrosphere / thin atmosphere -> dry -> sharp, young, uneroded coasts. Erosion-proneness therefore need not be a new authored field — it is derivable from hydrosphere + atmosphere + precipitation, compounding with the tectonic/glaciation drivers. Note for implementation: hydrosphere already feeds moisture derivation (T-1034 fixed the vocab fall-through), so part of this chain exists — the new link is wet/rainy feeding COASTLINE/relief character, not just biome wetness.', 'T-1123 zoom-ladder finding (2026-07-16, first-ever look at district-resolution maps; images in .cache/screenshots/district-windows, evidence /tmp/district-windows). At w256 (524km) the district layer reads as coherent geography (coastal band sequences, legible coasts — but bilinear-smooth: rounded corners of ~156km heightmap pixels visible, no invented bays). At w64 (131km) it degenerates to razor-straight gradient stripes; at w16 (33km) a single flat color. MECHANISM (code-grounded by Dudley): derive_district classifies morphology from ocean_fraction_q = RAW BILINEAR of the ocean mask (district_profile.rs:1318 — no domain warp, no scatter), and the D-227 detail-scatter amplitude is slaved to local_slope of the coarse heightmap (1301-1303) — near zero on low-relief coastal plains, so invention collapses exactly where coastlines live. The scatter itself works (visible as cloudy texture in w256 elev panels) but barely feeds classification and never feeds the coastline. NEEDED: the D-227 invention (interpolation + domain warp + detail-scatter) must carry geographic content into district classification — warped coastline sampling, slope-independent scatter floor, invented drainage/relief between heightmap pixels. This is the heart of the Phase-4 deliverable (deterministic walkable-world data that reads as geography) and blocks T-1124''s regional map view being worth looking at below ~500km. Determinism verified byte-identical cross-process — the substrate is sound; it is the content of the invention that is missing. Reproduce: cargo run --bin aliveness_probe -- --body GJ380c --seed 42 --render /tmp/out --window 64.
|
||
|
||
Jeroen''s design ruling (2026-07-17, pre-refinement): CRINKLE SHOULD VARY. The invented coastline/terrain detail must not be a single global roughness constant or uniform scatter floor — its amplitude and character vary from place to place. Candidate drivers to pin during refinement/implementation (lead''s interpretation, Si to ground in what derive_district already carries): geological context (tectonic_class, glaciation_grade — fjord coasts jagged, deltas smooth, cliff coasts sharp, alluvial plains gentle), climate signals, and seeded spatial heterogeneity so stretches of the same coast differ. The variation itself must be deterministic (seed+position), per D-227/D-010.
|
||
|
||
Jeroen''s ruling, elaborated (2026-07-17): derive coastline variation from EXISTING body settings + lat/long — do not author new knobs. Some places fjordy, some smooth; some planets have tectonics, some are prone to higher erosion. Two driver tiers: (1) BODY-level — the variation already in body parameters (planet_class, atmosphere, hydrosphere, axial tilt, radius, and whatever tectonic/erosion signals exist or are derivable from them) sets each body''s coastline character envelope; (2) POSITION-level — latitude/longitude and the derived district context (glaciation_grade, tectonic_class, climate bands) modulate within it: high-latitude glaciated coasts go fjordy, humid climates erode smooth, arid/tectonic coasts stay sharp. The point: two planets should have recognisably different coastline personalities, and one planet''s coasts should vary by where you are — all deterministic from seed+body+position, zero new authored data.
|
||
|
||
Jeroen, further (2026-07-17): ''more ocean is more wet and rainy, for instance'' — hydrosphere/ocean coverage as a tier-1 driver chain: large hydrosphere -> wetter, rainier climate -> HIGHER EROSION -> smoother, more mature coastlines (and more dendritic/eroded relief); small hydrosphere / thin atmosphere -> dry -> sharp, young, uneroded coasts. Erosion-proneness therefore need not be a new authored field — it is derivable from hydrosphere + atmosphere + precipitation, compounding with the tectonic/glaciation drivers. Note for implementation: hydrosphere already feeds moisture derivation (T-1034 fixed the vocab fall-through), so part of this chain exists — the new link is wet/rainy feeding COASTLINE/relief character, not just biome wetness.
|
||
|
||
---
|
||
Gap resolution (2026-07-17, Si review + Jeroen''s rulings):
|
||
|
||
1. TILT/D-240: DROPPED — no axial tilt input; D-240 stays intact. latitude_deg alone carries the position-tier polar effects (glaciation_grade is already latitude/temperature-derived). Tier-1 envelope CONFIRMED as what exists: planet_class + hydrosphere + atmosphere + body_radius_km (BodyParams, body_params_reader.rs:14-20). No tectonic-activity or erosion field exists — tectonic_class derives from planet_class (derive_tectonic_class always falls to its planet_class branch in production); erosion-proneness is DERIVED from hydrosphere + atmosphere + precipitation per Jeroen''s chain. Do not hunt for richer body signals; they are not there.
|
||
|
||
2. CIRCULARITY: ACCEPT STALE INPUT — glaciation_grade reads the UNWARPED raw-bilinear ocean_fraction_q (one-step-stale, deterministic, coarse ~156km-pixel value anyway). Document on the call site. tectonic_class is cheap to hoist to the top of derive_district (needs only BodyParams).
|
||
|
||
3. SCOPE: BOTH PATHS — the invention must feed derive_district (on-demand: probe + future T-1124 view) AND the production derive_district_profile (district_profile.rs:1062-1134, the batch path BodyWorldState stores — currently has NO scatter at all; the paths silently diverged). Implementer may unify the shared classification core if cleaner than duplicating — his call, reviewers verify. Believability goldens (server/tests/golden/believability.json) WILL regenerate — expected and acknowledged via UPDATE_GOLDEN=1; report the metric deltas (contrast/coherence blocks) in the PR as evidence of improvement, not just churn.
|
||
|
||
Si verification facts for the implementer:
|
||
- Direct reusable precedents: climate_edge_warp (region_profile.rs:477-513) — warp-the-sampling with a distinct hash path, exactly the pattern for ocean_fraction_q; domain_warp.rs (T-1026, stateless (seed,body,pos)->offset); detail_scatter.rs voxel_mosaic (T-1084) proves slope-INDEPENDENT position-keyed scatter is established. Longitude variation comes free via position-keyed noise on world-metre coords — no explicit longitude plumbing needed.
|
||
- Fix shape (from the ticket + rulings): warp the ocean-mask sampling position (invented bays/capes), slope-independent scatter floor whose AMPLITUDE/CHARACTER varies by the two driver tiers (body envelope: planet_class/hydrosphere/atmosphere/radius -> personality incl. erosion-smoothness; position: latitude, glaciation_grade, tectonic_class, climate bands -> fjordy vs smooth vs sharp), plus seeded heterogeneity so same-coast stretches differ. All deterministic seed+body+position (D-227/D-010); continuous across district/region boundaries (D-243 edge-fuzz discipline — character never steps on a line).
|
||
- Acceptance: (a) before/after zoom ladders (aliveness_probe --render, same bodies/windows as T-1123: GJ380c/GJ820Bc/GJ244Ad at w256/w64/w16) reviewed by Jeroen — the primary artifact; (b) believability metrics moved not regressed; new coastline-legibility criterion work belongs to open Q-123, not this ticket. (c) determinism byte-compare as in T-1123.
|
||
- Performance: no per-district budget record exists; do the D-246-style check — verify derive_district cost stays same order (~8us was the T-1123 measurement) and the believability/derivation harness budgets stay green.', NULL, '2026-07-17 05:37:57', '2026-07-17 05:37:57.401', '2026-07-17 05:37:57.401', NULL, 'a029e889e078aa3d6a2e8ec4a13471b9', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPS6RRBF9HHAED5QKTKQCY1G', 'description', 'T-1123 zoom-ladder finding: derive_vegetation(temp, moisture, elev, near_water) has no ocean/water-mask input — GJ380c w256 renders solid Forest across ~250km of OpenOcean districts (see .cache/screenshots/district-windows gj380c_w256_veg.png vs _morphology.png). Voxel-level water generators mask this in-world, but any district-resolution Atlas view (T-1124) will show forested oceans. Fix: vegetation classification should return a None/Marine class when the district''s morphology/ocean_fraction says water (reuse ocean_fraction_q already computed in derive_district).', 'T-1123 zoom-ladder finding: derive_vegetation(temp, moisture, elev, near_water) has no ocean/water-mask input — GJ380c w256 renders solid Forest across ~250km of OpenOcean districts (see .cache/screenshots/district-windows gj380c_w256_veg.png vs _morphology.png). Voxel-level water generators mask this in-world, but any district-resolution Atlas view (T-1124) will show forested oceans. Fix: vegetation classification should return a None/Marine class when the district''s morphology/ocean_fraction says water (reuse ocean_fraction_q already computed in derive_district).
|
||
|
||
Gap resolution (2026-07-17, Si review + Jeroen): (1) GATE: morphology-derived — pass the already-computed morphology water verdict (OpenOcean/Lake) into the vegetation call; vegetation and morphology can NEVER disagree by construction; no fourth threshold is born. (2) VARIANT: Marine, appended at discriminant 6 (after RiparianThicket=5); update the load-bearing vegetation_class_discriminants_pinned test; document that Ord position is non-semantic (the density-ladder doc does not extend to Marine). (3) SEQUENCING: blocked by T-1125 (edge added) — classify against the warped/invented coastline, not the smooth one. Si facts: the ticket phrase near_water is a TRAP — derive_vegetation''s 4th param is near_perennial_water (riparian/river proximity), unrelated to ocean; do not reuse it. voxel.rs consumers are wildcard-safe (ocean districts route to the WaterBody generator upstream per D-239/T-1082) — no changes needed there. aliveness_probe.rs vegetation_rgb is an EXHAUSTIVE match and will fail to compile until it gets a Marine color — extend the palette deliberately (ocean blue distinct from morphology water tones). D-239 gets an implementation-addendum note recording the Marine variant (its §8 climate-vegetation law predates a water class).', NULL, '2026-07-17 05:38:10', '2026-07-17 05:38:10.917', '2026-07-17 05:38:10.917', NULL, 'b29435e54ddc6a109cd87e2f3af36ea9', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPS6TF9XDZPKZY8DHG1T0E2R', 'description', 'T-1123 zoom-ladder finding: GJ244Ad (frozen planet_class, temp panel pegged at the -60C clamp floor, vegetation solid Barren) still renders temperate-green morphology — the 17-zone MorphologyZone vocabulary (T-1027, FROZEN per its own contract) has no ice/glacial zone, and glaciation_grade is a separate DistrictProfile field nothing renders. Do NOT reopen the frozen vocab by default: the likely fix is rendering glaciation_grade as a modifier/overlay on the morphology color (ice-tinting affected zones) in both the T-1123 probe renderer and the future T-1124 view — or, if the team decides an ice zone belongs in the vocabulary after all, that is a deliberate amendment to the freeze decision, not a drive-by. Images: .cache/screenshots/district-windows gj244ad_w256_morphology.png vs _temp.png.', 'T-1123 zoom-ladder finding: GJ244Ad (frozen planet_class, temp panel pegged at the -60C clamp floor, vegetation solid Barren) still renders temperate-green morphology — the 17-zone MorphologyZone vocabulary (T-1027, FROZEN per its own contract) has no ice/glacial zone, and glaciation_grade is a separate DistrictProfile field nothing renders. Do NOT reopen the frozen vocab by default: the likely fix is rendering glaciation_grade as a modifier/overlay on the morphology color (ice-tinting affected zones) in both the T-1123 probe renderer and the future T-1124 view — or, if the team decides an ice zone belongs in the vocabulary after all, that is a deliberate amendment to the freeze decision, not a drive-by. Images: .cache/screenshots/district-windows gj244ad_w256_morphology.png vs _temp.png.
|
||
|
||
Refinement (2026-07-17, Si review): READY. Upstream verified HEALTHY — glaciation derivation (derive_glaciation_grade_from_climate, district_profile.rs:339-366) is correctly wired and even gates the Fjord family; GJ244Ad moisture clears the gate floor. This is purely a rendering gap: aliveness_probe render_window_panels computes the full DistrictProfile and discards .glaciation_grade (line ~458 reads only morphology_zone). SCOPE RULING (lead): probe-only THIS ticket — per-pixel ice tint blended on the morphology panel keyed on glaciation_grade (+ optionally a 6th dedicated glaciation panel; PANEL_NAMES/bufs are array-driven, cheap). The wire+client half (glaciation: Vec<u8> parallel array inside DistrictGridLayer + build_district_grid + protocol.gd + _draw_gen_district — governance-UNCONSTRAINED per the D-226 growth-ceiling reading: the cap governs new top-level Option layers, not per-cell fields inside a shipped layer; elev_q precedent) is DEFERRED to T-1124''s design pass, which owns the which-fields-ship-at-district-resolution question. Freeze contract confirmed: D-239 SS6 — tint is classifier-tuning territory, no MorphologyZone vocab reopen; an ice zone would need its own explicit D-amendment (not pursued).', NULL, '2026-07-17 05:38:24', '2026-07-17 05:38:24.161', '2026-07-17 05:38:24.161', NULL, '6a9d21bf30820e1d9058b4b8a8fa64df', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPS6QD5FG9TC2WXTDVA44FPW', 'status', 'backlog', 'in_progress', NULL, '2026-07-17 05:38:38', '2026-07-17 05:38:38.565', '2026-07-17 05:38:38.565', NULL, '988ba7528d21a98ad9f40ddfab210d2c', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPS6RRBF9HHAED5QKTKQCY1G', 'status', 'backlog', 'in_progress', NULL, '2026-07-17 05:38:38', '2026-07-17 05:38:38.574', '2026-07-17 05:38:38.574', NULL, '4cb60e2febd859020fc2fbae4aff9e59', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPS6TF9XDZPKZY8DHG1T0E2R', 'status', 'backlog', 'in_progress', NULL, '2026-07-17 05:38:38', '2026-07-17 05:38:38.574', '2026-07-17 05:38:38.574', NULL, '83ccddb3c4ed268a95cbd00f4843b0cd', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPS6QD5FG9TC2WXTDVA44FPW', 'assigned_to', NULL, 'dudley', NULL, '2026-07-17 05:38:51', '2026-07-17 05:38:51.399', '2026-07-17 05:38:51.399', NULL, '1db15e907105ca1e1b2a51736a2fb5b4', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPS6TF9XDZPKZY8DHG1T0E2R', 'assigned_to', NULL, 'dudley', NULL, '2026-07-17 05:38:51', '2026-07-17 05:38:51.406', '2026-07-17 05:38:51.406', NULL, 'a61ffc1075244eda35e07b8037fc561a', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPS6RRBF9HHAED5QKTKQCY1G', 'assigned_to', NULL, 'dudley', NULL, '2026-07-17 05:38:51', '2026-07-17 05:38:51.406', '2026-07-17 05:38:51.406', NULL, 'de3fdd3e8ceac6cd698a2270b5997592', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPX7HZY1CK3VSTRXP1NP9VYW', 'status', 'backlog', 'in_progress', NULL, '2026-07-17 05:48:21', '2026-07-17 05:48:21.369', '2026-07-17 05:48:21.369', NULL, '117c6985291dd5894ce19995f11d8c00', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPXAWGRH9QK5QKV7584Q92Z8', 'description', 'D-254 SS1/SS3/SS5. client/scenes/atlas_standalone.tscn + atlas_standalone.gd (modeled on visual_capture.gd''s boot shape — NOT a flag on main.tscn, which is saturated with player-only paths): attach-mode = TCP connect SR_PORT-or-9876 with ~500ms timeout; ECONNREFUSED falls through to spawn-mode = own child server via the server_process.gd ownership pattern with --port 0 + LISTENING:{port} parse, REAL systems.db (no --test-mode); sends Reader-role StartupMessage; opens implant/map fullscreen (skips main menu/character creation); window title branding via DisplayServer.window_set_title; intercept atlas close-to-gameplay in atlas_standalone.gd (do not modify atlas_app.gd). Makefile: target = trivial build+launch (the scene owns the attach-or-spawn decision — no Makefile orchestration; and per Oscar''s flag this simplicity does NOT shrink the T-1130 server work). Exportable later as a Godot export preset, no architecture change. Blocked by T-1130 for real attach-mode testing (developable against spawn-mode before that). Blocks the browser-UI ticket (needs a shell to launch from).', 'D-254 SS1/SS3/SS5. client/scenes/atlas_standalone.tscn + atlas_standalone.gd (modeled on visual_capture.gd''s boot shape — NOT a flag on main.tscn, which is saturated with player-only paths): attach-mode = TCP connect SR_PORT-or-9876 with ~500ms timeout; ECONNREFUSED falls through to spawn-mode = own child server via the server_process.gd ownership pattern with --port 0 + LISTENING:{port} parse, REAL systems.db (no --test-mode); sends Reader-role StartupMessage; opens implant/map fullscreen (skips main menu/character creation); window title branding via DisplayServer.window_set_title; intercept atlas close-to-gameplay in atlas_standalone.gd (do not modify atlas_app.gd). Makefile: target = trivial build+launch (the scene owns the attach-or-spawn decision — no Makefile orchestration; and per Oscar''s flag this simplicity does NOT shrink the T-1130 server work). Exportable later as a Godot export preset, no architecture change. Blocked by T-1130 for real attach-mode testing (developable against spawn-mode before that). Blocks the browser-UI ticket (needs a shell to launch from).
|
||
|
||
Correction: the Makefile target name in the line above is ''atlas'' (make atlas) — shell backticks ate the word during filing.', NULL, '2026-07-17 06:03:20', '2026-07-17 06:03:20.063', '2026-07-17 06:03:20.063', NULL, 'e6cbeaa35dd5d2b3382cea2581d589f7', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPXAS26J3BS7ZJVRFT5JDXP8', 'status', 'backlog', 'in_progress', NULL, '2026-07-17 06:06:10', '2026-07-17 06:06:10.171', '2026-07-17 06:06:10.171', NULL, 'd87f3e71e88a7149569e18d3e0154fd6', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPXAWGRH9QK5QKV7584Q92Z8', 'status', 'backlog', 'in_progress', NULL, '2026-07-17 06:06:10', '2026-07-17 06:06:10.173', '2026-07-17 06:06:10.173', NULL, 'f5470118007d1ba4b21437d68c729612', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPXAS26J3BS7ZJVRFT5JDXP8', 'assigned_to', NULL, 'oscar', NULL, '2026-07-17 06:06:19', '2026-07-17 06:06:19.074', '2026-07-17 06:06:19.074', NULL, 'ab76fd6b922495bb9e834da5b46f2f36', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPXAWGRH9QK5QKV7584Q92Z8', 'assigned_to', NULL, 'stig', NULL, '2026-07-17 06:06:27', '2026-07-17 06:06:27.645', '2026-07-17 06:06:27.645', NULL, '9fb340e92bdc294380c5b4e4fdba4420', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPXAWGRH9QK5QKV7584Q92Z8', 'description', 'D-254 SS1/SS3/SS5. client/scenes/atlas_standalone.tscn + atlas_standalone.gd (modeled on visual_capture.gd''s boot shape — NOT a flag on main.tscn, which is saturated with player-only paths): attach-mode = TCP connect SR_PORT-or-9876 with ~500ms timeout; ECONNREFUSED falls through to spawn-mode = own child server via the server_process.gd ownership pattern with --port 0 + LISTENING:{port} parse, REAL systems.db (no --test-mode); sends Reader-role StartupMessage; opens implant/map fullscreen (skips main menu/character creation); window title branding via DisplayServer.window_set_title; intercept atlas close-to-gameplay in atlas_standalone.gd (do not modify atlas_app.gd). Makefile: target = trivial build+launch (the scene owns the attach-or-spawn decision — no Makefile orchestration; and per Oscar''s flag this simplicity does NOT shrink the T-1130 server work). Exportable later as a Godot export preset, no architecture change. Blocked by T-1130 for real attach-mode testing (developable against spawn-mode before that). Blocks the browser-UI ticket (needs a shell to launch from).
|
||
|
||
Correction: the Makefile target name in the line above is ''atlas'' (make atlas) — shell backticks ate the word during filing.', 'D-254 SS1/SS3/SS5. client/scenes/atlas_standalone.tscn + atlas_standalone.gd (modeled on visual_capture.gd''s boot shape — NOT a flag on main.tscn, which is saturated with player-only paths): attach-mode = TCP connect SR_PORT-or-9876 with ~500ms timeout; ECONNREFUSED falls through to spawn-mode = own child server via the server_process.gd ownership pattern with --port 0 + LISTENING:{port} parse, REAL systems.db (no --test-mode); sends Reader-role StartupMessage; opens implant/map fullscreen (skips main menu/character creation); window title branding via DisplayServer.window_set_title; intercept atlas close-to-gameplay in atlas_standalone.gd (do not modify atlas_app.gd). Makefile: target = trivial build+launch (the scene owns the attach-or-spawn decision — no Makefile orchestration; and per Oscar''s flag this simplicity does NOT shrink the T-1130 server work). Exportable later as a Godot export preset, no architecture change. Blocked by T-1130 for real attach-mode testing (developable against spawn-mode before that). Blocks the browser-UI ticket (needs a shell to launch from).
|
||
|
||
Correction: the Makefile target name in the line above is ''atlas'' (make atlas) — shell backticks ate the word during filing.
|
||
|
||
Jeroen''s requirement (2026-07-17, mid-implementation — now D-254 SS3): the standalone shell is a GENERIC IMPLANT HOST, not an Atlas launcher. Every ImplantRegistry app is automatically available in the companion; the manifest (app.tres) gains available_in_companion: bool = true (OPT-OUT — set false only for apps that need a playing character/gameplay context). Shell consults the flag at instantiate_all/app-open time and in any app-switching surface; the in-game implant ignores it. Both current apps (Atlas, Economics) stay true. Jeroen''s suggested name availableInAtlasApp recorded in D-254 with the available_in_companion rename rationale (GDScript snake_case + avoids colliding with apps/atlas).', NULL, '2026-07-17 06:10:24', '2026-07-17 06:10:24.124', '2026-07-17 06:10:24.124', NULL, 'f4a5329d45762576cfed8fca9e2a7c6d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPXB28V72K8ZPE5WSNJS1SP8', 'description', 'D-254 SS4 + Jeroen''s IA ruling (2026-07-17): a SEPARATE implant app (implant/browser), sibling to the Atlas — the six registry entities do not share the Atlas''s geographic drill-down. ONE ticket for all six per Jeroen (single review sees the whole surface). Scope: new client/ui/implant/apps/browser/ app.tres + app.gd + index/detail screen pairs for star systems, bodies, stations, corporations, commodities, trait templates — composed ENTIRELY from D-169 implant components (ImplantPanel/ImplantHeader/ImplantDataRow/ImplantTextBlock; no new UI primitives); wired to the six BrowseRequest endpoints; reachable from the standalone shell (and by design also from the in-game implant later — it is a normal implant app). Blocked by the browse-proxy ticket (data source) and the standalone-shell ticket (launch surface).', 'D-254 SS4 + Jeroen''s IA ruling (2026-07-17): a SEPARATE implant app (implant/browser), sibling to the Atlas — the six registry entities do not share the Atlas''s geographic drill-down. ONE ticket for all six per Jeroen (single review sees the whole surface). Scope: new client/ui/implant/apps/browser/ app.tres + app.gd + index/detail screen pairs for star systems, bodies, stations, corporations, commodities, trait templates — composed ENTIRELY from D-169 implant components (ImplantPanel/ImplantHeader/ImplantDataRow/ImplantTextBlock; no new UI primitives); wired to the six BrowseRequest endpoints; reachable from the standalone shell (and by design also from the in-game implant later — it is a normal implant app). Blocked by the browse-proxy ticket (data source) and the standalone-shell ticket (launch surface).
|
||
|
||
Note (D-254 SS3 addition, 2026-07-17): the implant/browser app manifest carries available_in_companion = true (the default). Because the companion shell is a generic implant host, this app appears in the standalone Atlas automatically the moment it registers — no companion-side wiring.', NULL, '2026-07-17 06:10:33', '2026-07-17 06:10:33.806', '2026-07-17 06:10:33.806', NULL, 'ad3e415206ac29b0827bddabff09ad45', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPS6QD5FG9TC2WXTDVA44FPW', 'status', 'in_progress', 'review', NULL, '2026-07-17 06:25:17', '2026-07-17 06:25:17.793', '2026-07-17 06:25:17.793', NULL, '6df5610c9e6e310eca58013dedf3f493', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPS6RRBF9HHAED5QKTKQCY1G', 'status', 'in_progress', 'review', NULL, '2026-07-17 06:25:17', '2026-07-17 06:25:17.795', '2026-07-17 06:25:17.795', NULL, '9f9b44c5ca4fbf811e14fab37259f6e2', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPS6TF9XDZPKZY8DHG1T0E2R', 'status', 'in_progress', 'review', NULL, '2026-07-17 06:25:17', '2026-07-17 06:25:17.795', '2026-07-17 06:25:17.795', NULL, 'f21585d66cc4ccd3c726186982f92eb5', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPS6QD5FG9TC2WXTDVA44FPW', 'status', 'review', 'done', NULL, '2026-07-17 06:36:05', '2026-07-17 06:36:05.018', '2026-07-17 06:36:05.018', NULL, '01cf6177ffbc79d6599bfdbe3a9458c8', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPS6RRBF9HHAED5QKTKQCY1G', 'status', 'review', 'done', NULL, '2026-07-17 06:36:05', '2026-07-17 06:36:05.021', '2026-07-17 06:36:05.021', NULL, 'f5c4072188f4f0acc309f37cc2a9a107', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPS6TF9XDZPKZY8DHG1T0E2R', 'status', 'review', 'done', NULL, '2026-07-17 06:36:05', '2026-07-17 06:36:05.022', '2026-07-17 06:36:05.022', NULL, 'ecd510bf9c15187292bce916dfd25fa8', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPX7HZY1CK3VSTRXP1NP9VYW', 'status', 'in_progress', 'review', NULL, '2026-07-17 07:16:47', '2026-07-17 07:16:47.103', '2026-07-17 07:16:47.103', NULL, 'd8b73dc6faef3d1a5d3573045c475b62', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPXAS26J3BS7ZJVRFT5JDXP8', 'status', 'in_progress', 'review', NULL, '2026-07-17 07:16:47', '2026-07-17 07:16:47.106', '2026-07-17 07:16:47.106', NULL, '3b30b41a05b18914a5664024712e3435', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPXAWGRH9QK5QKV7584Q92Z8', 'status', 'in_progress', 'review', NULL, '2026-07-17 07:16:47', '2026-07-17 07:16:47.106', '2026-07-17 07:16:47.106', NULL, 'db5fa6e8953f5df39e0c49c81d06be74', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPX7HZY1CK3VSTRXP1NP9VYW', 'status', 'review', 'done', NULL, '2026-07-17 07:33:14', '2026-07-17 07:33:14.221', '2026-07-17 07:33:14.221', NULL, '8e59f6cc9dcc0967b6a2c77b444d3baa', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPXAS26J3BS7ZJVRFT5JDXP8', 'status', 'review', 'done', NULL, '2026-07-17 07:33:14', '2026-07-17 07:33:14.223', '2026-07-17 07:33:14.223', NULL, 'f95e0e0fa6a14edb36ef926a094eb550', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPXAWGRH9QK5QKV7584Q92Z8', 'status', 'review', 'done', NULL, '2026-07-17 07:33:14', '2026-07-17 07:33:14.224', '2026-07-17 07:33:14.224', NULL, '7b6bed8f8be45d9ed6bfad8ffb52d599', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPXATGN8QJAJVR0WCRHJS2TG', 'status', 'backlog', 'in_progress', NULL, '2026-07-17 07:34:22', '2026-07-17 07:34:22.189', '2026-07-17 07:34:22.189', NULL, '68970342b3e64d173fd3a650699e2743', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPXB28V72K8ZPE5WSNJS1SP8', 'status', 'backlog', 'in_progress', NULL, '2026-07-17 07:34:22', '2026-07-17 07:34:22.191', '2026-07-17 07:34:22.191', NULL, 'f2c4221be9f8284f42cf30df6e2923a8', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPXATGN8QJAJVR0WCRHJS2TG', 'status', 'in_progress', 'review', NULL, '2026-07-17 08:44:33', '2026-07-17 08:44:33.133', '2026-07-17 08:44:33.133', NULL, 'acdc54129303a07fbfa6b17ae466dcca', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPXB28V72K8ZPE5WSNJS1SP8', 'status', 'in_progress', 'review', NULL, '2026-07-17 08:44:33', '2026-07-17 08:44:33.136', '2026-07-17 08:44:33.136', NULL, '1f0a7c19bc19621fba62d8990c338482', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPXATGN8QJAJVR0WCRHJS2TG', 'status', 'review', 'done', NULL, '2026-07-17 08:57:02', '2026-07-17 08:57:02.425', '2026-07-17 08:57:02.425', NULL, '83126a9bdaada931c2ac8ef0ab43a2e4', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPXB28V72K8ZPE5WSNJS1SP8', 'status', 'review', 'done', NULL, '2026-07-17 08:57:02', '2026-07-17 08:57:02.427', '2026-07-17 08:57:02.427', NULL, 'f0716dd68297e94be7a286dcc0a47d2b', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPRZZ0P42NHC1QR5S3737EV4', 'status', 'backlog', 'in_progress', NULL, '2026-07-18 09:44:19', '2026-07-18 09:44:19.604', '2026-07-18 09:44:19.604', NULL, '034cfbb43d43cb8a54d00c41a9b416bf', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPQXFFHXEEDQEM7PGXAH3534', 'status', 'backlog', 'in_progress', NULL, '2026-07-18 09:44:19', '2026-07-18 09:44:19.607', '2026-07-18 09:44:19.607', NULL, '44a39bf35870cfbe5c92de6c7a0ba255', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPQXHDSMSVD3VADV38NG9STW', 'status', 'backlog', 'in_progress', NULL, '2026-07-18 09:44:19', '2026-07-18 09:44:19.608', '2026-07-18 09:44:19.608', NULL, 'f0e0177fc117f4a6e8102069ce5c17a5', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPRZZ0P42NHC1QR5S3737EV4', 'description', 'Jeroen (2026-07-16): the Atlas needs the jet-plane altitude — a windowed district-resolution (2km-cell) map screen bridging the planetary canvas and the (never-mapped, D-226(d)) chunk/voxel world. Today the viewer is one whole-body texture with client-side pan/zoom; AtlasLayerRequest is {body_id, up_to} whole-body only — no rect/window/LOD machinery exists anywhere (recon-verified). Design pass (Tyre data shape + Araminta encoding, the T-1112 pattern): (1) windowed request protocol — rect/center+radius params on a new or extended layer request, served by calling derive_district per cell (district_profile.rs:1256, pure/on-demand — NOT the coarse eager grid); (2) which fields ship at district resolution (morphology, elev_q, temperature, moisture, vegetation — wire-integer discipline per D-010); (3) the screen: entry from a planetary-map click/settlement, second canvas vs zoom-threshold LOD swap, overlay/legend reuse; (4) budget: window size caps, caching, re-request-on-pan. Record as a D-226 amendment. District resolution is ABOVE the D-226(d) quarter-skeleton floor — in remit. Wiring is a follow-up ticket once the design is recorded. Natural batch-mates: T-1118 (climate overlay) + T-1119 (quarter glyphs). T-1123 (server-side window renderer) is the data-side proof and shares the per-cell derive pattern.', 'Jeroen (2026-07-16): the Atlas needs the jet-plane altitude — a windowed district-resolution (2km-cell) map screen bridging the planetary canvas and the (never-mapped, D-226(d)) chunk/voxel world. Today the viewer is one whole-body texture with client-side pan/zoom; AtlasLayerRequest is {body_id, up_to} whole-body only — no rect/window/LOD machinery exists anywhere (recon-verified). Design pass (Tyre data shape + Araminta encoding, the T-1112 pattern): (1) windowed request protocol — rect/center+radius params on a new or extended layer request, served by calling derive_district per cell (district_profile.rs:1256, pure/on-demand — NOT the coarse eager grid); (2) which fields ship at district resolution (morphology, elev_q, temperature, moisture, vegetation — wire-integer discipline per D-010); (3) the screen: entry from a planetary-map click/settlement, second canvas vs zoom-threshold LOD swap, overlay/legend reuse; (4) budget: window size caps, caching, re-request-on-pan. Record as a D-226 amendment. District resolution is ABOVE the D-226(d) quarter-skeleton floor — in remit. Wiring is a follow-up ticket once the design is recorded. Natural batch-mates: T-1118 (climate overlay) + T-1119 (quarter glyphs). T-1123 (server-side window renderer) is the data-side proof and shares the per-cell derive pattern.
|
||
|
||
---
|
||
Refinement (2026-07-18, Si review + lead rulings — binding for the design pass):
|
||
|
||
CORRECTED ANCHORS (post PR #182 rewrite): derive_district is now district_profile.rs:1415 (signature gained climate: &ClimateConstants; delegates to the shared invent_primitives — still pure/on-demand, still NOT the coarse eager grid). AtlasLayerRequest is server/src/atlas/layer_proxy.rs:39 (not bridge/mod.rs); its up_to field is currently unwired (cascade always runs to Region). AtlasLayerResponse growth-ceiling doc at layer_proxy.rs:76-79. Five-shape demux cap at bridge/mod.rs:60-76.
|
||
|
||
RULING 1 — request side (closed, not open): the windowed request MUST be optional window fields ON AtlasLayerRequest (serde-default; absent = whole-body, wire back-compat) — a new top-level request shape is FORBIDDEN by the five-shape demux ceiling (PR #184 Tyre ruling: the sixth shape triggers the D-225 tagged-envelope migration; a window param does not justify paying that now). The ticket phrase ''a new or extended layer request'' is superseded: extended only.
|
||
|
||
RULING 2 — response side (mandatory explicit resolution IN the amendment): the AtlasLayerResponse one-Option-field-per-layer pattern tops out around six per its own doc; region_grid is the fifth and quarter_footprints (T-1119, THIS batch) consumes the sixth. The windowed district payload is therefore the SEVENTH — the design must explicitly choose and record its carrier: (a) a seventh Option field busting the soft response ceiling with rationale + a re-pinned ceiling, (b) a response-side tagged-envelope/second-response-shape migration, or (c) another mechanism (e.g. the window response as its own payload kind inside the existing atlas request/response buffers). Cite the T-1127 ruling (the ceiling governs NEW TOP-LEVEL Option layers, not per-cell fields inside a shipped layer) and keep the request-cap and response-budget questions explicitly distinct — they are different ceilings with different hardness.
|
||
|
||
FIELD LIST — two mandatory dispositions: (1) glaciation_grade — T-1127 explicitly deferred its wire+client half to this design pass (Vec of u8, elev_q precedent, probe ice-tint as the render pattern); accept or reject EXPLICITLY, lean accept. (2) vegetation now includes Marine at discriminant 6 (T-1126) — any palette/legend must be exhaustive (the probe palette match is a compile-time guard; the GDScript side needs the discipline manually).
|
||
|
||
Reusable precedents verified: aliveness_probe --render (T-1123) is the working per-cell derive_district-in-a-window loop + 17-entry MORPHOLOGY_RGB palette; RegionGridLayer (layer_proxy.rs:154-165) is the dense-grid wire-shape precedent (parallel Vec arrays, documented sentinels e.g. REGION_TEMP_NONE_DC); DistrictPos = (i32,i32) at scale.rs:75. Deliverable unchanged: D-226 amendment + proposed follow-up wiring ticket(s); no implementation in this ticket.', NULL, '2026-07-18 09:46:46', '2026-07-18 09:46:46.436', '2026-07-18 09:46:46.436', NULL, '37f572ff3cdfa9e5ec94bacd0fb28c05', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPQXFFHXEEDQEM7PGXAH3534', 'description', 'Follow-up to T-1113 (merged PR #179): the server now serves RegionGridLayer (dense row-major; season/weather repr(u8) discriminants, mean_temp deci-degC i16 with i16::MIN airless sentinel, moisture_q u8) through AtlasLayerResponse.region_grid, and protocol.gd passes it through. Build the client overlay per the D-226 incremental-overlay pattern: OVERLAY_DEFS gen_* id (atlas_viewer.gd), _draw_gen_* renderer (atlas_marker_overlay.gd — a region-grid fill analogous to _draw_gen_district but at region granularity), GENERATION_LEGEND entry (atlas_legend_panel.gd). Pick ONE visual channel (mean temp ramp is the obvious first; season/weather as tooltip or variant overlays). Also add a populated region_grid wire fixture (all three committed fixtures carry nil — noted in PR #179).', 'Follow-up to T-1113 (merged PR #179): the server now serves RegionGridLayer (dense row-major; season/weather repr(u8) discriminants, mean_temp deci-degC i16 with i16::MIN airless sentinel, moisture_q u8) through AtlasLayerResponse.region_grid, and protocol.gd passes it through. Build the client overlay per the D-226 incremental-overlay pattern: OVERLAY_DEFS gen_* id (atlas_viewer.gd), _draw_gen_* renderer (atlas_marker_overlay.gd — a region-grid fill analogous to _draw_gen_district but at region granularity), GENERATION_LEGEND entry (atlas_legend_panel.gd). Pick ONE visual channel (mean temp ramp is the obvious first; season/weather as tooltip or variant overlays). Also add a populated region_grid wire fixture (all three committed fixtures carry nil — noted in PR #179).
|
||
|
||
---
|
||
Refinement (2026-07-18, Si review — verified anchors): protocol.gd = client/scripts/protocol/protocol.gd (passthrough already shipped at :821). Touch points with directly-copyable district_grid precedent: atlas_viewer.gd:149-153 (OVERLAY_DEFS pattern) + :376-385 (set/get_generation_district_grid accessor pair to mirror) + :436 (dispatch in _on_atlas_layers_received); atlas_marker_overlay.gd:477-494 (_draw_gen_district, dispatched :185-188); atlas_legend_panel.gd:82-88.
|
||
|
||
COORDINATE PATH (explicit, two patterns coexist in the same file): copy _draw_gen_district''s SELF-CONTAINED mapping — cols/rows come from the layer dict itself (server-computed extent), cw = tex_w/cols, ch = tex_h/rows, fills the whole heightmap texture. Do NOT use the _gen_pos/_gen_grid_w/_gen_grid_h path (that is for Layer1 point data like rivers).
|
||
|
||
Legend row is GATE-ENFORCED: test_atlas_overlays.gd:192-209 generically asserts every gen_* overlay id has a legend row — the legend entry is required for the suite to pass, not polish.
|
||
|
||
Fixtures: client/tests/fixtures/msgpack/atlas_response_{ready,pending,not_found}.msgpack, generated by server/tests/gen_fixtures.rs::generate_atlas_layer_response_fixtures (:627/:641/:655 currently hardcode region_grid: None). Regen = make fixtures (NOT make fixtures-gauntlet — separate live pipeline). Populated fixture = add a non-empty RegionGridLayer literal following the road_graph/settlements populated literals at :577-618, run make fixtures, extend the Tier-2 replay test at test_atlas_overlays.gd:149. The server-side literal edit lands via Dudley (batch-mate, owns server/tests in this batch) — coordinate the literal''s contents with him; the client-side replay-test extension is this ticket''s.
|
||
|
||
Channel ruling confirmed: mean-temp ramp first (i16 deci-degC, REGION_TEMP_NONE_DC = i16::MIN airless sentinel needs an explicit render disposition — distinct sentinel color or skip); season/weather/moisture as tooltip or later variant overlays, not this ticket.', NULL, '2026-07-18 09:46:57', '2026-07-18 09:46:57.153', '2026-07-18 09:46:57.153', NULL, '5ed9dd3831ca7d36da1e425356ca0bde', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPQXHDSMSVD3VADV38NG9STW', 'description', 'Implements the design recorded in the D-226 amendment (2026-07-16, T-1112, merged PR #179). Six touch points, each named in the amendment SS4: (1) ZoningType gains PartialOrd/Ord derives mirroring DistrictType''s T-994 precedent (enables the dominant_zoning declaration-order tie-break); (2) AtlasLayerResponse.quarter_footprints field + build_quarter_footprint_layer() mirroring build_district_grid, keyed off non-empty state.quarters, aggregates keyed by city_id (join via the same deterministic QuarterId derivation the dispatch uses); (3) protocol.gd passthrough; (4) OVERLAY_DEFS gen_* id (atlas_viewer.gd); (5) _draw_gen_* scaled-glyph renderer anchored on the L3 settlement dot — shape=dominant district type, color=density ramp on the settlement-gold family, zoom-gated at SETTLEMENT_LABEL_MIN_ZOOM (atlas_marker_overlay.gd); (6) GENERATION_LEGEND entry (atlas_legend_panel.gd). Five aggregate fields: density_avg_pct u8, dominant_district_type, dominant_zoning, landmark_count u8, corridor_count u8; landmark/corridor tooltip-only per the D-226(d) ceiling.', 'Implements the design recorded in the D-226 amendment (2026-07-16, T-1112, merged PR #179). Six touch points, each named in the amendment SS4: (1) ZoningType gains PartialOrd/Ord derives mirroring DistrictType''s T-994 precedent (enables the dominant_zoning declaration-order tie-break); (2) AtlasLayerResponse.quarter_footprints field + build_quarter_footprint_layer() mirroring build_district_grid, keyed off non-empty state.quarters, aggregates keyed by city_id (join via the same deterministic QuarterId derivation the dispatch uses); (3) protocol.gd passthrough; (4) OVERLAY_DEFS gen_* id (atlas_viewer.gd); (5) _draw_gen_* scaled-glyph renderer anchored on the L3 settlement dot — shape=dominant district type, color=density ramp on the settlement-gold family, zoom-gated at SETTLEMENT_LABEL_MIN_ZOOM (atlas_marker_overlay.gd); (6) GENERATION_LEGEND entry (atlas_legend_panel.gd). Five aggregate fields: density_avg_pct u8, dominant_district_type, dominant_zoning, landmark_count u8, corridor_count u8; landmark/corridor tooltip-only per the D-226(d) ceiling.
|
||
|
||
---
|
||
Refinement (2026-07-18, Si review — READY, all anchors verified current): ZoningType at generator.rs:234-235 missing PartialOrd/Ord exactly as stated (DistrictType''s T-994 derive block at :207 is the mirror). build_district_grid mirror template at layer_proxy.rs:106-133 (None-on-empty-source pattern confirmed); AtlasLayerResponse currently 5 layer fields — quarter_footprints is the SIXTH and, per the struct''s own growth doc at :76-79, the final one the current pattern allows (T-1124''s design pass, same batch, resolves what carries any seventh — do not resolve it here, just implement the sixth cleanly).
|
||
|
||
QUARTERS ARE POPULATED TODAY (critical check passed): BodyWorldState.quarters (body_world_state.rs:98) is filled by plugin.rs:365-367 on GenCompletion::SkeletonGenerated, and the executor (gen_queue.rs:436-474 GenerateSkeleton arm) calls the real generate_quarter_skeleton() + assign_all_block_tags() — NOT a stub. The stale TODO(#957) comment at plugin.rs:361-363 predates T-957 landing; delete it in passing. QuarterId derivation: plugin.rs:430/:648 via SeedDomain::Layer4Quarter (seed.rs:301).
|
||
|
||
Client anchors: SETTLEMENT_LABEL_MIN_ZOOM = 2.0 at atlas_marker_overlay.gd:113; L3 settlement-dot anchor _draw_gen_settlements at :695; _draw_gen_district shape template at :477; GENERATION_LEGEND at atlas_legend_panel.gd:41 (pure additive table; legend rows are gate-enforced by test_atlas_overlays.gd:192-209); protocol.gd:821 region_grid passthrough is the freshest sibling to mirror.
|
||
|
||
IN-SCOPE boilerplate not named in the six points: the get/set_generation_quarter_footprints accessor pair on atlas_viewer.gd (folded into touch point 4, exactly as region_grid''s accessors ride its OVERLAY_DEFS entry; protocol dispatch calls the setter — see protocol.gd:436 pattern).
|
||
|
||
Batch split (lead): points 1-2 (server) = Dudley, who also owns the gen_fixtures.rs edits for this batch (consider adding a populated quarter_footprints literal alongside T-1118''s region_grid literal — reviewers will expect the new layer to have fixture coverage); points 3-6 (client) + T-1118 = Stig. Dudley pins the quarter_footprints wire field names/types FIRST and messages Stig the shape before Stig wires the client half.', NULL, '2026-07-18 09:47:00', '2026-07-18 09:47:00.752', '2026-07-18 09:47:00.752', NULL, '402a9036e13ef222b0a8b7911cad1c04', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FQ9B977KGH3BWP1YQTN32TYM', 'description', 'Implement the D-226 T-1124 amendment SS5 (client half). protocol.gd passthrough: encode_atlas_layer_request gains the window params (serde-default absent = whole-body); atlas_response_from_raw gains district_window passthrough (the doc comment near protocol.gd:801 names this the one client-side spot). New regional viewing mode per SS5: zoom-threshold LOD swap in the existing AtlasViewer (new DISTRICT_WINDOW_MIN_ZOOM past SETTLEMENT_LABEL_MIN_ZOOM — not a new screen, not a nav push); morphology base layer lightness-modulated by elev_q (probe MORPHOLOGY_RGB hues); gen_dw_temp/gen_dw_moisture/gen_dw_veg toggle overlays (temp reuses the T-1118 region-ramp colorizer EXACTLY — one colorizer across both zoom levels; Marine=6 renders transparent; glaciation is an always-on ice-tint modifier, not a toggle); GENERATION_LEGEND entries with the 17-zone base folded to ~5 family rows. Client window cache keyed (body_id, center, n), LRU-evict only (D-227 determinism — no freshness check). Re-request on PAN ONLY when the view passes the held window''s edge (zoom never refetches); 150ms post-drag-release debounce; windows float on the pan center (not grid-snapped). Implant chrome: ImplantHeader anchor name + extent subtitle; map palettes stay out of theme accent roles (ACCENT_ACTIVE gold is the settlement marker''s).', 'Implement the D-226 T-1124 amendment SS5 (client half). protocol.gd passthrough: encode_atlas_layer_request gains the window params (serde-default absent = whole-body); atlas_response_from_raw gains district_window passthrough (the doc comment near protocol.gd:801 names this the one client-side spot). New regional viewing mode per SS5: zoom-threshold LOD swap in the existing AtlasViewer (new DISTRICT_WINDOW_MIN_ZOOM past SETTLEMENT_LABEL_MIN_ZOOM — not a new screen, not a nav push); morphology base layer lightness-modulated by elev_q (probe MORPHOLOGY_RGB hues); gen_dw_temp/gen_dw_moisture/gen_dw_veg toggle overlays (temp reuses the T-1118 region-ramp colorizer EXACTLY — one colorizer across both zoom levels; Marine=6 renders transparent; glaciation is an always-on ice-tint modifier, not a toggle); GENERATION_LEGEND entries with the 17-zone base folded to ~5 family rows. Client window cache keyed (body_id, center, n), LRU-evict only (D-227 determinism — no freshness check). Re-request on PAN ONLY when the view passes the held window''s edge (zoom never refetches); 150ms post-drag-release debounce; windows float on the pan center (not grid-snapped). Implant chrome: ImplantHeader anchor name + extent subtitle; map palettes stay out of theme accent roles (ACCENT_ACTIVE gold is the settlement marker''s).
|
||
|
||
Implementation note (Tyre, T-1124 report): DISTRICT_WINDOW_MIN_ZOOM proposed at 6.0 but atlas_viewer.gd caps _view_zoom at MAX_ZOOM = 8.0 — only a 6.0-8.0 band for the whole in-window-zoom detail story the SS5 legibility argument depends on. Tunable client constant, not wire contract: either lower the swap threshold or raise MAX_ZOOM; decide with on-screen-scale math at implementation.', NULL, '2026-07-18 10:02:32', '2026-07-18 10:02:32.846', '2026-07-18 10:02:32.846', NULL, 'b7437067dede390cbbf5d5d758b3b1a7', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPRZZ0P42NHC1QR5S3737EV4', 'status', 'in_progress', 'review', NULL, '2026-07-18 10:30:08', '2026-07-18 10:30:08.113', '2026-07-18 10:30:08.113', NULL, '475845ef730811d0a00675fcffba98fe', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPQXHDSMSVD3VADV38NG9STW', 'status', 'in_progress', 'review', NULL, '2026-07-18 10:30:08', '2026-07-18 10:30:08.116', '2026-07-18 10:30:08.116', NULL, '4446cca99e042920271275c7e16b4934', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPQXFFHXEEDQEM7PGXAH3534', 'status', 'in_progress', 'review', NULL, '2026-07-18 10:30:08', '2026-07-18 10:30:08.116', '2026-07-18 10:30:08.116', NULL, '748ea7e1d521afc72a2f34adf71c4f50', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FQ9B8F39QD7PGPG4W35AWCRG', 'description', 'Implement the D-226 T-1124 amendment SS1-SS4 (server half). (1) AtlasLayerRequest gains window_center: Option-DistrictPos + window_n: u32, both serde(default) — absent = whole-body, wire back-compat. (2) AtlasLayerResponse gains district_window: Option-DistrictWindowLayer per the amendment''s exact field list (echoed center/n + six parallel arrays: morphology u8, elev_q u8, temp_dc i16 with the RegionGridLayer sentinel, moisture_q u8, vegetation u8 incl Marine=6, glaciation u8). (3) handle_atlas_request gains a window-serving branch calling derive_district per cell (district_profile.rs:1415), clamping window_n to 1..=DISTRICT_WINDOW_MAX_N=64 server-side (never trust the wire).
|
||
|
||
MUST RESOLVE FIRST — the TerrainAnalysis availability decision (named in the amendment + T-1124 report): BodyWorldState does NOT retain TerrainAnalysis after cascade completion (transient ~2 MB, dropped at cascade.rs:141 per D-203 memory budget), but derive_district needs a reference to it. Either (a) cache TerrainAnalysis alongside BodyWorldState (quantify the ~2 MB/body cost against BodyWorldStateCache LRU capacity) or (b) re-derive via run_layer1 per cache miss (quantify the O(w*h) whole-body re-analysis as a window-request tax — aliveness_probe''s current workaround). Decide with numbers, record the choice in the PR.
|
||
|
||
(4) Tests mirroring build_region_grid/build_district_grid precedents: empty/clamped-window edges, msgpack round-trip, and a determinism spot-check (two full passes byte-identical — promoting the T-1123 probe-only proof to a real test, since this is the first served layer built from the on-demand derive path).', 'Implement the D-226 T-1124 amendment SS1-SS4 (server half). (1) AtlasLayerRequest gains window_center: Option-DistrictPos + window_n: u32, both serde(default) — absent = whole-body, wire back-compat. (2) AtlasLayerResponse gains district_window: Option-DistrictWindowLayer per the amendment''s exact field list (echoed center/n + six parallel arrays: morphology u8, elev_q u8, temp_dc i16 with the RegionGridLayer sentinel, moisture_q u8, vegetation u8 incl Marine=6, glaciation u8). (3) handle_atlas_request gains a window-serving branch calling derive_district per cell (district_profile.rs:1415), clamping window_n to 1..=DISTRICT_WINDOW_MAX_N=64 server-side (never trust the wire).
|
||
|
||
MUST RESOLVE FIRST — the TerrainAnalysis availability decision (named in the amendment + T-1124 report): BodyWorldState does NOT retain TerrainAnalysis after cascade completion (transient ~2 MB, dropped at cascade.rs:141 per D-203 memory budget), but derive_district needs a reference to it. Either (a) cache TerrainAnalysis alongside BodyWorldState (quantify the ~2 MB/body cost against BodyWorldStateCache LRU capacity) or (b) re-derive via run_layer1 per cache miss (quantify the O(w*h) whole-body re-analysis as a window-request tax — aliveness_probe''s current workaround). Decide with numbers, record the choice in the PR.
|
||
|
||
(4) Tests mirroring build_region_grid/build_district_grid precedents: empty/clamped-window edges, msgpack round-trip, and a determinism spot-check (two full passes byte-identical — promoting the T-1123 probe-only proof to a real test, since this is the first served layer built from the on-demand derive path).
|
||
|
||
Design change from the PR #185 Troblum review (binding, folded into the amendment): the window-serving branch must NOT call derive_district inline in serve_atlas_requests/PreInput — window derives ride the SAME Rayon background queue + Pending-response pattern the whole-body cache-miss path uses (response on a later tick; the client''s SS5 border-fade covers the wait). Recommended: per-connection coalescing — a newly queued window request supersedes an unserved older one for the same body. The SS4 numbers (~7ms n=32 / ~29ms n=64 debug) are background-queue latency, not tick-thread cost. Also: the amendment now pins a windowed-family ceiling — district_window is the ONLY windowed-query field this struct may carry; a second windowed query is a dedicated response message by rule.', NULL, '2026-07-18 10:38:20', '2026-07-18 10:38:20.072', '2026-07-18 10:38:20.072', NULL, '118a77ac05211ca1045f7d0cbfa07fae', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPRZZ0P42NHC1QR5S3737EV4', 'status', 'review', 'done', NULL, '2026-07-18 10:47:49', '2026-07-18 10:47:49.025', '2026-07-18 10:47:49.025', NULL, 'ba6fc0953709dac9cc737c7f5899fa6d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPQXFFHXEEDQEM7PGXAH3534', 'status', 'review', 'done', NULL, '2026-07-18 10:47:49', '2026-07-18 10:47:49.028', '2026-07-18 10:47:49.028', NULL, '4ae28f9b2965c36f1c4b7e6f88c5355f', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPQXHDSMSVD3VADV38NG9STW', 'status', 'review', 'done', NULL, '2026-07-18 10:47:49', '2026-07-18 10:47:49.029', '2026-07-18 10:47:49.029', NULL, 'f329401a96278d3e8ee18598e2bc601a', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FQ9B977KGH3BWP1YQTN32TYM', 'description', 'Implement the D-226 T-1124 amendment SS5 (client half). protocol.gd passthrough: encode_atlas_layer_request gains the window params (serde-default absent = whole-body); atlas_response_from_raw gains district_window passthrough (the doc comment near protocol.gd:801 names this the one client-side spot). New regional viewing mode per SS5: zoom-threshold LOD swap in the existing AtlasViewer (new DISTRICT_WINDOW_MIN_ZOOM past SETTLEMENT_LABEL_MIN_ZOOM — not a new screen, not a nav push); morphology base layer lightness-modulated by elev_q (probe MORPHOLOGY_RGB hues); gen_dw_temp/gen_dw_moisture/gen_dw_veg toggle overlays (temp reuses the T-1118 region-ramp colorizer EXACTLY — one colorizer across both zoom levels; Marine=6 renders transparent; glaciation is an always-on ice-tint modifier, not a toggle); GENERATION_LEGEND entries with the 17-zone base folded to ~5 family rows. Client window cache keyed (body_id, center, n), LRU-evict only (D-227 determinism — no freshness check). Re-request on PAN ONLY when the view passes the held window''s edge (zoom never refetches); 150ms post-drag-release debounce; windows float on the pan center (not grid-snapped). Implant chrome: ImplantHeader anchor name + extent subtitle; map palettes stay out of theme accent roles (ACCENT_ACTIVE gold is the settlement marker''s).
|
||
|
||
Implementation note (Tyre, T-1124 report): DISTRICT_WINDOW_MIN_ZOOM proposed at 6.0 but atlas_viewer.gd caps _view_zoom at MAX_ZOOM = 8.0 — only a 6.0-8.0 band for the whole in-window-zoom detail story the SS5 legibility argument depends on. Tunable client constant, not wire contract: either lower the swap threshold or raise MAX_ZOOM; decide with on-screen-scale math at implementation.', 'Implement the D-226 T-1124 amendment SS5 (client half). protocol.gd passthrough: encode_atlas_layer_request gains the window params (serde-default absent = whole-body); atlas_response_from_raw gains district_window passthrough (the doc comment near protocol.gd:801 names this the one client-side spot). New regional viewing mode per SS5: zoom-threshold LOD swap in the existing AtlasViewer (new DISTRICT_WINDOW_MIN_ZOOM past SETTLEMENT_LABEL_MIN_ZOOM — not a new screen, not a nav push); morphology base layer lightness-modulated by elev_q (probe MORPHOLOGY_RGB hues); gen_dw_temp/gen_dw_moisture/gen_dw_veg toggle overlays (temp reuses the T-1118 region-ramp colorizer EXACTLY — one colorizer across both zoom levels; Marine=6 renders transparent; glaciation is an always-on ice-tint modifier, not a toggle); GENERATION_LEGEND entries with the 17-zone base folded to ~5 family rows. Client window cache keyed (body_id, center, n), LRU-evict only (D-227 determinism — no freshness check). Re-request on PAN ONLY when the view passes the held window''s edge (zoom never refetches); 150ms post-drag-release debounce; windows float on the pan center (not grid-snapped). Implant chrome: ImplantHeader anchor name + extent subtitle; map palettes stay out of theme accent roles (ACCENT_ACTIVE gold is the settlement marker''s).
|
||
|
||
Implementation note (Tyre, T-1124 report): DISTRICT_WINDOW_MIN_ZOOM proposed at 6.0 but atlas_viewer.gd caps _view_zoom at MAX_ZOOM = 8.0 — only a 6.0-8.0 band for the whole in-window-zoom detail story the SS5 legibility argument depends on. Tunable client constant, not wire contract: either lower the swap threshold or raise MAX_ZOOM; decide with on-screen-scale math at implementation.
|
||
|
||
SUPERSEDED ENTRY MECHANIC (Jeroen, 2026-07-21 companion hands-on — recorded as the D-226 T-1124 SS5 entry revision): NO zoom-threshold LOD swap and NO DISTRICT_WINDOW_MIN_ZOOM — the earlier zoom-headroom note is moot. The planetary heightmap view becomes FIXED: remove drag-pan/wheel-zoom of the planetary canvas IN THIS TICKET, same change as the replacement (never strand close inspection), and update the header hint text accordingly. Entry: hovering the planetary heightmap shows a rectangle cursor representing the regional-mode bounds; click descends into the regional map centered on the click point''s derived DistrictPos (float-on-center rules carry over with pan-center read as click-point). In-mode behavior unchanged (pan-only refetch, 150ms debounce, D-227 cache, border-fade). Morph transition between modes explicitly deferred — the descent may cut. Open design point: the rectangle cursor is an affordance, not to scale (n=64 = ~131km = a few px on a planetary canvas) — resolve the honest representation (true-extent rectangle + zoom-in cut, or not-to-scale reticle with the real extent labeled) without implying more coverage than real. Note: set_view/get_view_offset (T-1120 capture API) must survive for the visual-golden harness even after user pan/zoom is removed.', NULL, '2026-07-21 06:58:26', '2026-07-21 06:58:26.870', '2026-07-21 06:58:26.870', NULL, '60f8b73d47b3a1ec7ddf8f6024f640b7', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FR6Y1CNA5JJ68RN897RM7FBC', 'status', 'backlog', 'in_progress', NULL, '2026-07-21 06:58:48', '2026-07-21 06:58:48.125', '2026-07-21 06:58:48.125', NULL, '07436c6c5318eca6cd011f2dd67c2dc1', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FR6Y1CNA5JJ68RN897RM7FBC', 'status', 'in_progress', 'review', NULL, '2026-07-21 07:16:21', '2026-07-21 07:16:21.984', '2026-07-21 07:16:21.984', NULL, 'c17c3d899e4addd70522da86c66db245', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FR6Y1CNA5JJ68RN897RM7FBC', 'status', 'review', 'done', NULL, '2026-07-21 07:30:24', '2026-07-21 07:30:24.988', '2026-07-21 07:30:24.988', NULL, 'c422e25bdefe3e51a1b5db3ed272b54d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FQ9B8F39QD7PGPG4W35AWCRG', 'status', 'backlog', 'in_progress', NULL, '2026-07-21 09:51:17', '2026-07-21 09:51:17.157', '2026-07-21 09:51:17.157', NULL, '817bb1654d0c0e45b538ce75cf29c32d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FQ9B977KGH3BWP1YQTN32TYM', 'status', 'backlog', 'in_progress', NULL, '2026-07-21 09:51:17', '2026-07-21 09:51:17.164', '2026-07-21 09:51:17.164', NULL, 'b8ad42d6070f54896dd9690c6eb0c344', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FQ9B8F39QD7PGPG4W35AWCRG', 'status', 'in_progress', 'review', NULL, '2026-07-21 11:36:01', '2026-07-21 11:36:01.469', '2026-07-21 11:36:01.469', NULL, 'aa66d02097b26bf3c5d60de099add7ae', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FQ9B977KGH3BWP1YQTN32TYM', 'status', 'in_progress', 'review', NULL, '2026-07-21 11:36:01', '2026-07-21 11:36:01.472', '2026-07-21 11:36:01.472', NULL, 'd533c4a7a3725cbfd9d627f4d8e51a37', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FQ9B8F39QD7PGPG4W35AWCRG', 'status', 'review', 'done', NULL, '2026-07-21 12:03:40', '2026-07-21 12:03:40.353', '2026-07-21 12:03:40.353', NULL, 'cc7df4e537775f8ce9167f5c5d7d7851', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FQ9B977KGH3BWP1YQTN32TYM', 'status', 'review', 'done', NULL, '2026-07-21 12:03:40', '2026-07-21 12:03:40.355', '2026-07-21 12:03:40.355', NULL, 'dc60887c48f8e2aa55786cd884e8b0bf', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FR97BZHA6DV68S1BFG0HBN8G', 'status', 'backlog', 'in_progress', NULL, '2026-07-21 12:20:47', '2026-07-21 12:20:47.188', '2026-07-21 12:20:47.188', NULL, 'ff85feaa7a633ecabb8187d5ea68b7ba', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FR97BZHA6DV68S1BFG0HBN8G', 'status', 'in_progress', 'review', NULL, '2026-07-21 13:11:49', '2026-07-21 13:11:49.373', '2026-07-21 13:11:49.373', NULL, '4b5378198de50d36b509b1fbdbc14ac1', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FR97BZHA6DV68S1BFG0HBN8G', 'status', 'review', 'done', NULL, '2026-07-21 13:26:53', '2026-07-21 13:26:53.798', '2026-07-21 13:26:53.798', NULL, '3964092ac3e27946107a24acd5563ade', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FR97DPEHANCYX2AC4021BSJC', 'description', 'Follow-on from Jeroen''s first descent (2026-07-21): even with T-1142 fixed, many interior windows are genuinely one morphology zone across 66km, and the composite''s absolute lightness modulation (0.7 + 0.3 x elev_q/100, D-226 T-1124 SS5) spans only ~1-3% lightness over a window whose local elev range is small — the window reads as a dead flat fill rather than terrain. Proposal to evaluate WITH Araminta (SS5 is her encoding): window-local contrast stretch — normalize lightness within the window''s own elev min..max (fixed band, e.g. 0.62..0.92) with a degenerate floor (single-value window stays honestly flat), deterministic per window, mirroring how the aliveness_probe elev panel achieved its 12-level local texture. Alternative/complement: a faint deterministic per-cell variation or contour hinting. Any change to the recorded SS5 encoding gets a one-line amendment note. Assess AFTER T-1142 lands — real clicks will then land on real terrain and the residual flatness can be judged on coastal vs interior windows.', 'Follow-on from Jeroen''s first descent (2026-07-21): even with T-1142 fixed, many interior windows are genuinely one morphology zone across 66km, and the composite''s absolute lightness modulation (0.7 + 0.3 x elev_q/100, D-226 T-1124 SS5) spans only ~1-3% lightness over a window whose local elev range is small — the window reads as a dead flat fill rather than terrain. Proposal to evaluate WITH Araminta (SS5 is her encoding): window-local contrast stretch — normalize lightness within the window''s own elev min..max (fixed band, e.g. 0.62..0.92) with a degenerate floor (single-value window stays honestly flat), deterministic per window, mirroring how the aliveness_probe elev panel achieved its 12-level local texture. Alternative/complement: a faint deterministic per-cell variation or contour hinting. Any change to the recorded SS5 encoding gets a one-line amendment note. Assess AFTER T-1142 lands — real clicks will then land on real terrain and the residual flatness can be judged on coastal vs interior windows.
|
||
|
||
Scope expansion (Jeroen round-2, 2026-07-21): beyond window-local contrast, evaluate SUB-DISTRICT SAMPLING to de-block the composite at the data level — the D-227 invention fields (invent_primitives: warped envelope, scatter, character) are continuous at metre resolution and quarter granularity (512m, 4x4 per district) sits WITHIN the D-226(d) Atlas ceiling (the cap rules out chunk/tile mapping, not quarters). But classification (derive_district) is per-district today — finer sampling means a new derivation mode (e.g. sample the continuous primitives at quarter spacing and reuse the district''s classification for hue while modulating lightness/moisture per quarter, or classify per quarter at 16x the derive cost — n=32 window = 16384 quarter cells x ~7us = ~115ms background). Needs Dudley/Tyre on data feasibility + cost, Araminta on encoding. INTERIM already shipping in T-1145: linear-filtered texture rendering (presentation smoothing, no data change) — judge the residual need after both T-1145 and real-aim clicking land.', NULL, '2026-07-21 14:17:24', '2026-07-21 14:17:24.702', '2026-07-21 14:17:24.702', NULL, 'a3e548c138e93161250dd60001d6487d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRA2DAZ2PDWE2YH76YBSQ2DW', 'status', 'backlog', 'in_progress', NULL, '2026-07-21 14:17:33', '2026-07-21 14:17:33.958', '2026-07-21 14:17:33.958', NULL, '2e1259f990abb2360e258955d1a451ea', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRA2DAZ2PDWE2YH76YBSQ2DW', 'status', 'in_progress', 'review', NULL, '2026-07-21 15:03:29', '2026-07-21 15:03:29.644', '2026-07-21 15:03:29.644', NULL, '190dbcb439bb02c1758b4c55f52c04c6', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRA2DAZ2PDWE2YH76YBSQ2DW', 'status', 'review', 'done', NULL, '2026-07-21 15:08:57', '2026-07-21 15:08:57.829', '2026-07-21 15:08:57.829', NULL, '9ed4da25de534fabf827b4f6989a10a9', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRA9Z84VKCZ3ECQDEGDW4MSW', 'status', 'backlog', 'in_progress', NULL, '2026-07-21 16:55:45', '2026-07-21 16:55:45.245', '2026-07-21 16:55:45.245', NULL, 'bc53fb15ce6f74470d7da22c01f52cb3', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FR97DPEHANCYX2AC4021BSJC', 'description', 'Follow-on from Jeroen''s first descent (2026-07-21): even with T-1142 fixed, many interior windows are genuinely one morphology zone across 66km, and the composite''s absolute lightness modulation (0.7 + 0.3 x elev_q/100, D-226 T-1124 SS5) spans only ~1-3% lightness over a window whose local elev range is small — the window reads as a dead flat fill rather than terrain. Proposal to evaluate WITH Araminta (SS5 is her encoding): window-local contrast stretch — normalize lightness within the window''s own elev min..max (fixed band, e.g. 0.62..0.92) with a degenerate floor (single-value window stays honestly flat), deterministic per window, mirroring how the aliveness_probe elev panel achieved its 12-level local texture. Alternative/complement: a faint deterministic per-cell variation or contour hinting. Any change to the recorded SS5 encoding gets a one-line amendment note. Assess AFTER T-1142 lands — real clicks will then land on real terrain and the residual flatness can be judged on coastal vs interior windows.
|
||
|
||
Scope expansion (Jeroen round-2, 2026-07-21): beyond window-local contrast, evaluate SUB-DISTRICT SAMPLING to de-block the composite at the data level — the D-227 invention fields (invent_primitives: warped envelope, scatter, character) are continuous at metre resolution and quarter granularity (512m, 4x4 per district) sits WITHIN the D-226(d) Atlas ceiling (the cap rules out chunk/tile mapping, not quarters). But classification (derive_district) is per-district today — finer sampling means a new derivation mode (e.g. sample the continuous primitives at quarter spacing and reuse the district''s classification for hue while modulating lightness/moisture per quarter, or classify per quarter at 16x the derive cost — n=32 window = 16384 quarter cells x ~7us = ~115ms background). Needs Dudley/Tyre on data feasibility + cost, Araminta on encoding. INTERIM already shipping in T-1145: linear-filtered texture rendering (presentation smoothing, no data change) — judge the residual need after both T-1145 and real-aim clicking land.', 'Follow-on from Jeroen''s first descent (2026-07-21): even with T-1142 fixed, many interior windows are genuinely one morphology zone across 66km, and the composite''s absolute lightness modulation (0.7 + 0.3 x elev_q/100, D-226 T-1124 SS5) spans only ~1-3% lightness over a window whose local elev range is small — the window reads as a dead flat fill rather than terrain. Proposal to evaluate WITH Araminta (SS5 is her encoding): window-local contrast stretch — normalize lightness within the window''s own elev min..max (fixed band, e.g. 0.62..0.92) with a degenerate floor (single-value window stays honestly flat), deterministic per window, mirroring how the aliveness_probe elev panel achieved its 12-level local texture. Alternative/complement: a faint deterministic per-cell variation or contour hinting. Any change to the recorded SS5 encoding gets a one-line amendment note. Assess AFTER T-1142 lands — real clicks will then land on real terrain and the residual flatness can be judged on coastal vs interior windows.
|
||
|
||
Scope expansion (Jeroen round-2, 2026-07-21): beyond window-local contrast, evaluate SUB-DISTRICT SAMPLING to de-block the composite at the data level — the D-227 invention fields (invent_primitives: warped envelope, scatter, character) are continuous at metre resolution and quarter granularity (512m, 4x4 per district) sits WITHIN the D-226(d) Atlas ceiling (the cap rules out chunk/tile mapping, not quarters). But classification (derive_district) is per-district today — finer sampling means a new derivation mode (e.g. sample the continuous primitives at quarter spacing and reuse the district''s classification for hue while modulating lightness/moisture per quarter, or classify per quarter at 16x the derive cost — n=32 window = 16384 quarter cells x ~7us = ~115ms background). Needs Dudley/Tyre on data feasibility + cost, Araminta on encoding. INTERIM already shipping in T-1145: linear-filtered texture rendering (presentation smoothing, no data change) — judge the residual need after both T-1145 and real-aim clicking land.
|
||
|
||
RULING (Jeroen, 2026-07-21, round-3 direction): the smooth-gradient rendering is INTERIM ONLY — he expects not to like it as the destination. The destination is SMALLER DETERMINISTICALLY-CALCULATED PIXELS (sub-district sampling, the sketch above), and the larger vision: SCROLL-ZOOM AS CONTINUOUS INFORMATION LoD — zooming in from the regional level progressively refines the sampled resolution seamlessly (no mode transition), ''zoom in to tile size from this level'' in his words. The design pass must therefore produce: (a) the granularity ladder the zoom traverses (district 2048m -> quarter 512m -> ? ), with derivation modes + per-window costs at each rung; (b) wire implications — finer windows multiply cell counts (quarter = 16x district cells/window); weigh against the windowed-family ceiling and the SS4 budget model (likely per-rung window requests reusing the same district_window carrier at different granularity, or a granularity param — design call); (c) THE FLOOR QUESTION back to Jeroen explicitly: ''tile size'' intersects the D-226(d) ceiling (chunk/tile output never Atlas-mapped; quarter is the current legal floor) — the pass presents the options (stop at quarter vs supersede D-226(d) for the window view) rather than assuming; (d) Araminta: encoding continuity across rungs (one colorizer family, hue stability as resolution refines). The COMPOSITE_SMOOTH linear-filter path ships until this lands, then is expected to be retired.', NULL, '2026-07-21 17:00:31', '2026-07-21 17:00:31.999', '2026-07-21 17:00:31.999', NULL, 'c2418a61461bee5600fd26e7e7081325', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRA9Z84VKCZ3ECQDEGDW4MSW', 'status', 'in_progress', 'review', NULL, '2026-07-21 17:52:07', '2026-07-21 17:52:07.607', '2026-07-21 17:52:07.607', NULL, '3c63f148664245c3e75cb1db2ee27052', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRA9Z84VKCZ3ECQDEGDW4MSW', 'status', 'review', 'done', NULL, '2026-07-21 18:02:45', '2026-07-21 18:02:45.248', '2026-07-21 18:02:45.248', NULL, 'c515eb85a2d4ea403834823693a55228', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FR97DPEHANCYX2AC4021BSJC', 'description', 'Follow-on from Jeroen''s first descent (2026-07-21): even with T-1142 fixed, many interior windows are genuinely one morphology zone across 66km, and the composite''s absolute lightness modulation (0.7 + 0.3 x elev_q/100, D-226 T-1124 SS5) spans only ~1-3% lightness over a window whose local elev range is small — the window reads as a dead flat fill rather than terrain. Proposal to evaluate WITH Araminta (SS5 is her encoding): window-local contrast stretch — normalize lightness within the window''s own elev min..max (fixed band, e.g. 0.62..0.92) with a degenerate floor (single-value window stays honestly flat), deterministic per window, mirroring how the aliveness_probe elev panel achieved its 12-level local texture. Alternative/complement: a faint deterministic per-cell variation or contour hinting. Any change to the recorded SS5 encoding gets a one-line amendment note. Assess AFTER T-1142 lands — real clicks will then land on real terrain and the residual flatness can be judged on coastal vs interior windows.
|
||
|
||
Scope expansion (Jeroen round-2, 2026-07-21): beyond window-local contrast, evaluate SUB-DISTRICT SAMPLING to de-block the composite at the data level — the D-227 invention fields (invent_primitives: warped envelope, scatter, character) are continuous at metre resolution and quarter granularity (512m, 4x4 per district) sits WITHIN the D-226(d) Atlas ceiling (the cap rules out chunk/tile mapping, not quarters). But classification (derive_district) is per-district today — finer sampling means a new derivation mode (e.g. sample the continuous primitives at quarter spacing and reuse the district''s classification for hue while modulating lightness/moisture per quarter, or classify per quarter at 16x the derive cost — n=32 window = 16384 quarter cells x ~7us = ~115ms background). Needs Dudley/Tyre on data feasibility + cost, Araminta on encoding. INTERIM already shipping in T-1145: linear-filtered texture rendering (presentation smoothing, no data change) — judge the residual need after both T-1145 and real-aim clicking land.
|
||
|
||
RULING (Jeroen, 2026-07-21, round-3 direction): the smooth-gradient rendering is INTERIM ONLY — he expects not to like it as the destination. The destination is SMALLER DETERMINISTICALLY-CALCULATED PIXELS (sub-district sampling, the sketch above), and the larger vision: SCROLL-ZOOM AS CONTINUOUS INFORMATION LoD — zooming in from the regional level progressively refines the sampled resolution seamlessly (no mode transition), ''zoom in to tile size from this level'' in his words. The design pass must therefore produce: (a) the granularity ladder the zoom traverses (district 2048m -> quarter 512m -> ? ), with derivation modes + per-window costs at each rung; (b) wire implications — finer windows multiply cell counts (quarter = 16x district cells/window); weigh against the windowed-family ceiling and the SS4 budget model (likely per-rung window requests reusing the same district_window carrier at different granularity, or a granularity param — design call); (c) THE FLOOR QUESTION back to Jeroen explicitly: ''tile size'' intersects the D-226(d) ceiling (chunk/tile output never Atlas-mapped; quarter is the current legal floor) — the pass presents the options (stop at quarter vs supersede D-226(d) for the window view) rather than assuming; (d) Araminta: encoding continuity across rungs (one colorizer family, hue stability as resolution refines). The COMPOSITE_SMOOTH linear-filter path ships until this lands, then is expected to be retired.', 'Follow-on from Jeroen''s first descent (2026-07-21): even with T-1142 fixed, many interior windows are genuinely one morphology zone across 66km, and the composite''s absolute lightness modulation (0.7 + 0.3 x elev_q/100, D-226 T-1124 SS5) spans only ~1-3% lightness over a window whose local elev range is small — the window reads as a dead flat fill rather than terrain. Proposal to evaluate WITH Araminta (SS5 is her encoding): window-local contrast stretch — normalize lightness within the window''s own elev min..max (fixed band, e.g. 0.62..0.92) with a degenerate floor (single-value window stays honestly flat), deterministic per window, mirroring how the aliveness_probe elev panel achieved its 12-level local texture. Alternative/complement: a faint deterministic per-cell variation or contour hinting. Any change to the recorded SS5 encoding gets a one-line amendment note. Assess AFTER T-1142 lands — real clicks will then land on real terrain and the residual flatness can be judged on coastal vs interior windows.
|
||
|
||
Scope expansion (Jeroen round-2, 2026-07-21): beyond window-local contrast, evaluate SUB-DISTRICT SAMPLING to de-block the composite at the data level — the D-227 invention fields (invent_primitives: warped envelope, scatter, character) are continuous at metre resolution and quarter granularity (512m, 4x4 per district) sits WITHIN the D-226(d) Atlas ceiling (the cap rules out chunk/tile mapping, not quarters). But classification (derive_district) is per-district today — finer sampling means a new derivation mode (e.g. sample the continuous primitives at quarter spacing and reuse the district''s classification for hue while modulating lightness/moisture per quarter, or classify per quarter at 16x the derive cost — n=32 window = 16384 quarter cells x ~7us = ~115ms background). Needs Dudley/Tyre on data feasibility + cost, Araminta on encoding. INTERIM already shipping in T-1145: linear-filtered texture rendering (presentation smoothing, no data change) — judge the residual need after both T-1145 and real-aim clicking land.
|
||
|
||
RULING (Jeroen, 2026-07-21, round-3 direction): the smooth-gradient rendering is INTERIM ONLY — he expects not to like it as the destination. The destination is SMALLER DETERMINISTICALLY-CALCULATED PIXELS (sub-district sampling, the sketch above), and the larger vision: SCROLL-ZOOM AS CONTINUOUS INFORMATION LoD — zooming in from the regional level progressively refines the sampled resolution seamlessly (no mode transition), ''zoom in to tile size from this level'' in his words. The design pass must therefore produce: (a) the granularity ladder the zoom traverses (district 2048m -> quarter 512m -> ? ), with derivation modes + per-window costs at each rung; (b) wire implications — finer windows multiply cell counts (quarter = 16x district cells/window); weigh against the windowed-family ceiling and the SS4 budget model (likely per-rung window requests reusing the same district_window carrier at different granularity, or a granularity param — design call); (c) THE FLOOR QUESTION back to Jeroen explicitly: ''tile size'' intersects the D-226(d) ceiling (chunk/tile output never Atlas-mapped; quarter is the current legal floor) — the pass presents the options (stop at quarter vs supersede D-226(d) for the window view) rather than assuming; (d) Araminta: encoding continuity across rungs (one colorizer family, hue stability as resolution refines). The COMPOSITE_SMOOTH linear-filter path ships until this lands, then is expected to be retired.
|
||
|
||
D-166 amendment 2026-07-21 (Jeroen, from the Groombridge/Lendel zoom captures): the seamless zoom ladder this ticket designs is now a HARD Phase-4 deliverable condition — T-750 does not close until the ladder stands (planetary map -> tile scale, every level deterministically derived at native granularity, never magnified interpolation; BHAG itself unchanged). Evidence baked into the amendment: at Lendel scale one heightmap px spans ~19 districts, so the current 16-district window is sub-pixel vs its source — beyond fit-zoom the viewer can only magnify the same composite, and the real waterline sat ~36 districts from the pixel-edge estimate (all window-scale-and-below information is D-227 invented detail and must be derived, not smoothed). This raises the design pass''s stakes: the granularity-rung ladder, wire budget, and the D-226(d) floor question are now phase-gating.', NULL, '2026-07-21 19:01:45', '2026-07-21 19:01:45.387', '2026-07-21 19:01:45.387', NULL, '0b7b95e7418d0b279a5e4e115085a453', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FR97DPEHANCYX2AC4021BSJC', 'priority', 'medium', 'high', NULL, '2026-07-21 19:01:54', '2026-07-21 19:01:54.239', '2026-07-21 19:01:54.239', NULL, '7d0d4a6b25d6430273ce7df42230dc3a', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FR97DPEHANCYX2AC4021BSJC', 'description', 'Follow-on from Jeroen''s first descent (2026-07-21): even with T-1142 fixed, many interior windows are genuinely one morphology zone across 66km, and the composite''s absolute lightness modulation (0.7 + 0.3 x elev_q/100, D-226 T-1124 SS5) spans only ~1-3% lightness over a window whose local elev range is small — the window reads as a dead flat fill rather than terrain. Proposal to evaluate WITH Araminta (SS5 is her encoding): window-local contrast stretch — normalize lightness within the window''s own elev min..max (fixed band, e.g. 0.62..0.92) with a degenerate floor (single-value window stays honestly flat), deterministic per window, mirroring how the aliveness_probe elev panel achieved its 12-level local texture. Alternative/complement: a faint deterministic per-cell variation or contour hinting. Any change to the recorded SS5 encoding gets a one-line amendment note. Assess AFTER T-1142 lands — real clicks will then land on real terrain and the residual flatness can be judged on coastal vs interior windows.
|
||
|
||
Scope expansion (Jeroen round-2, 2026-07-21): beyond window-local contrast, evaluate SUB-DISTRICT SAMPLING to de-block the composite at the data level — the D-227 invention fields (invent_primitives: warped envelope, scatter, character) are continuous at metre resolution and quarter granularity (512m, 4x4 per district) sits WITHIN the D-226(d) Atlas ceiling (the cap rules out chunk/tile mapping, not quarters). But classification (derive_district) is per-district today — finer sampling means a new derivation mode (e.g. sample the continuous primitives at quarter spacing and reuse the district''s classification for hue while modulating lightness/moisture per quarter, or classify per quarter at 16x the derive cost — n=32 window = 16384 quarter cells x ~7us = ~115ms background). Needs Dudley/Tyre on data feasibility + cost, Araminta on encoding. INTERIM already shipping in T-1145: linear-filtered texture rendering (presentation smoothing, no data change) — judge the residual need after both T-1145 and real-aim clicking land.
|
||
|
||
RULING (Jeroen, 2026-07-21, round-3 direction): the smooth-gradient rendering is INTERIM ONLY — he expects not to like it as the destination. The destination is SMALLER DETERMINISTICALLY-CALCULATED PIXELS (sub-district sampling, the sketch above), and the larger vision: SCROLL-ZOOM AS CONTINUOUS INFORMATION LoD — zooming in from the regional level progressively refines the sampled resolution seamlessly (no mode transition), ''zoom in to tile size from this level'' in his words. The design pass must therefore produce: (a) the granularity ladder the zoom traverses (district 2048m -> quarter 512m -> ? ), with derivation modes + per-window costs at each rung; (b) wire implications — finer windows multiply cell counts (quarter = 16x district cells/window); weigh against the windowed-family ceiling and the SS4 budget model (likely per-rung window requests reusing the same district_window carrier at different granularity, or a granularity param — design call); (c) THE FLOOR QUESTION back to Jeroen explicitly: ''tile size'' intersects the D-226(d) ceiling (chunk/tile output never Atlas-mapped; quarter is the current legal floor) — the pass presents the options (stop at quarter vs supersede D-226(d) for the window view) rather than assuming; (d) Araminta: encoding continuity across rungs (one colorizer family, hue stability as resolution refines). The COMPOSITE_SMOOTH linear-filter path ships until this lands, then is expected to be retired.
|
||
|
||
D-166 amendment 2026-07-21 (Jeroen, from the Groombridge/Lendel zoom captures): the seamless zoom ladder this ticket designs is now a HARD Phase-4 deliverable condition — T-750 does not close until the ladder stands (planetary map -> tile scale, every level deterministically derived at native granularity, never magnified interpolation; BHAG itself unchanged). Evidence baked into the amendment: at Lendel scale one heightmap px spans ~19 districts, so the current 16-district window is sub-pixel vs its source — beyond fit-zoom the viewer can only magnify the same composite, and the real waterline sat ~36 districts from the pixel-edge estimate (all window-scale-and-below information is D-227 invented detail and must be derived, not smoothed). This raises the design pass''s stakes: the granularity-rung ladder, wire budget, and the D-226(d) floor question are now phase-gating.', 'Follow-on from Jeroen''s first descent (2026-07-21): even with T-1142 fixed, many interior windows are genuinely one morphology zone across 66km, and the composite''s absolute lightness modulation (0.7 + 0.3 x elev_q/100, D-226 T-1124 SS5) spans only ~1-3% lightness over a window whose local elev range is small — the window reads as a dead flat fill rather than terrain. Proposal to evaluate WITH Araminta (SS5 is her encoding): window-local contrast stretch — normalize lightness within the window''s own elev min..max (fixed band, e.g. 0.62..0.92) with a degenerate floor (single-value window stays honestly flat), deterministic per window, mirroring how the aliveness_probe elev panel achieved its 12-level local texture. Alternative/complement: a faint deterministic per-cell variation or contour hinting. Any change to the recorded SS5 encoding gets a one-line amendment note. Assess AFTER T-1142 lands — real clicks will then land on real terrain and the residual flatness can be judged on coastal vs interior windows.
|
||
|
||
Scope expansion (Jeroen round-2, 2026-07-21): beyond window-local contrast, evaluate SUB-DISTRICT SAMPLING to de-block the composite at the data level — the D-227 invention fields (invent_primitives: warped envelope, scatter, character) are continuous at metre resolution and quarter granularity (512m, 4x4 per district) sits WITHIN the D-226(d) Atlas ceiling (the cap rules out chunk/tile mapping, not quarters). But classification (derive_district) is per-district today — finer sampling means a new derivation mode (e.g. sample the continuous primitives at quarter spacing and reuse the district''s classification for hue while modulating lightness/moisture per quarter, or classify per quarter at 16x the derive cost — n=32 window = 16384 quarter cells x ~7us = ~115ms background). Needs Dudley/Tyre on data feasibility + cost, Araminta on encoding. INTERIM already shipping in T-1145: linear-filtered texture rendering (presentation smoothing, no data change) — judge the residual need after both T-1145 and real-aim clicking land.
|
||
|
||
RULING (Jeroen, 2026-07-21, round-3 direction): the smooth-gradient rendering is INTERIM ONLY — he expects not to like it as the destination. The destination is SMALLER DETERMINISTICALLY-CALCULATED PIXELS (sub-district sampling, the sketch above), and the larger vision: SCROLL-ZOOM AS CONTINUOUS INFORMATION LoD — zooming in from the regional level progressively refines the sampled resolution seamlessly (no mode transition), ''zoom in to tile size from this level'' in his words. The design pass must therefore produce: (a) the granularity ladder the zoom traverses (district 2048m -> quarter 512m -> ? ), with derivation modes + per-window costs at each rung; (b) wire implications — finer windows multiply cell counts (quarter = 16x district cells/window); weigh against the windowed-family ceiling and the SS4 budget model (likely per-rung window requests reusing the same district_window carrier at different granularity, or a granularity param — design call); (c) THE FLOOR QUESTION back to Jeroen explicitly: ''tile size'' intersects the D-226(d) ceiling (chunk/tile output never Atlas-mapped; quarter is the current legal floor) — the pass presents the options (stop at quarter vs supersede D-226(d) for the window view) rather than assuming; (d) Araminta: encoding continuity across rungs (one colorizer family, hue stability as resolution refines). The COMPOSITE_SMOOTH linear-filter path ships until this lands, then is expected to be retired.
|
||
|
||
D-166 amendment 2026-07-21 (Jeroen, from the Groombridge/Lendel zoom captures): the seamless zoom ladder this ticket designs is now a HARD Phase-4 deliverable condition — T-750 does not close until the ladder stands (planetary map -> tile scale, every level deterministically derived at native granularity, never magnified interpolation; BHAG itself unchanged). Evidence baked into the amendment: at Lendel scale one heightmap px spans ~19 districts, so the current 16-district window is sub-pixel vs its source — beyond fit-zoom the viewer can only magnify the same composite, and the real waterline sat ~36 districts from the pixel-edge estimate (all window-scale-and-below information is D-227 invented detail and must be derived, not smoothed). This raises the design pass''s stakes: the granularity-rung ladder, wire budget, and the D-226(d) floor question are now phase-gating.
|
||
|
||
Corollary to the D-166 2026-07-21 amendment (Jeroen, same day): heightmap PNGs are demoted to INVISIBLE derivation input — no zoom level displays them, including orbital/planetary, which must itself be FULLY DERIVED. Display at every rung samples the derivation at CANVAS RESOLUTION (continuous field, not fixed rasters) — this drops zoom over- and undersampling by construction and makes the map adapt to any viewport size. Design-pass additions: (e) the planetary/orbital rung becomes derived output — spec its derivation mode + cost (whole-planet at canvas res; today''s AtlasViewer texture path retires when it lands); (f) canvas-resolution-adaptive sampling replaces fixed per-rung display granularity — the rung ladder defines DERIVATION granularity available at each scale, while sampling density tracks the viewport; (g) import_heightmaps stays as input storage only.', NULL, '2026-07-21 19:06:30', '2026-07-21 19:06:30.921', '2026-07-21 19:06:30.921', NULL, '9204f1e54fcf03591a9c3bdf4ddc90a6', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FR97DPEHANCYX2AC4021BSJC', 'status', 'backlog', 'in_progress', NULL, '2026-07-21 19:10:46', '2026-07-21 19:10:46.894', '2026-07-21 19:10:46.894', NULL, 'c1fc1b7447ced35a13b1df723a01f0b2', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FR97DPEHANCYX2AC4021BSJC', 'description', 'Follow-on from Jeroen''s first descent (2026-07-21): even with T-1142 fixed, many interior windows are genuinely one morphology zone across 66km, and the composite''s absolute lightness modulation (0.7 + 0.3 x elev_q/100, D-226 T-1124 SS5) spans only ~1-3% lightness over a window whose local elev range is small — the window reads as a dead flat fill rather than terrain. Proposal to evaluate WITH Araminta (SS5 is her encoding): window-local contrast stretch — normalize lightness within the window''s own elev min..max (fixed band, e.g. 0.62..0.92) with a degenerate floor (single-value window stays honestly flat), deterministic per window, mirroring how the aliveness_probe elev panel achieved its 12-level local texture. Alternative/complement: a faint deterministic per-cell variation or contour hinting. Any change to the recorded SS5 encoding gets a one-line amendment note. Assess AFTER T-1142 lands — real clicks will then land on real terrain and the residual flatness can be judged on coastal vs interior windows.
|
||
|
||
Scope expansion (Jeroen round-2, 2026-07-21): beyond window-local contrast, evaluate SUB-DISTRICT SAMPLING to de-block the composite at the data level — the D-227 invention fields (invent_primitives: warped envelope, scatter, character) are continuous at metre resolution and quarter granularity (512m, 4x4 per district) sits WITHIN the D-226(d) Atlas ceiling (the cap rules out chunk/tile mapping, not quarters). But classification (derive_district) is per-district today — finer sampling means a new derivation mode (e.g. sample the continuous primitives at quarter spacing and reuse the district''s classification for hue while modulating lightness/moisture per quarter, or classify per quarter at 16x the derive cost — n=32 window = 16384 quarter cells x ~7us = ~115ms background). Needs Dudley/Tyre on data feasibility + cost, Araminta on encoding. INTERIM already shipping in T-1145: linear-filtered texture rendering (presentation smoothing, no data change) — judge the residual need after both T-1145 and real-aim clicking land.
|
||
|
||
RULING (Jeroen, 2026-07-21, round-3 direction): the smooth-gradient rendering is INTERIM ONLY — he expects not to like it as the destination. The destination is SMALLER DETERMINISTICALLY-CALCULATED PIXELS (sub-district sampling, the sketch above), and the larger vision: SCROLL-ZOOM AS CONTINUOUS INFORMATION LoD — zooming in from the regional level progressively refines the sampled resolution seamlessly (no mode transition), ''zoom in to tile size from this level'' in his words. The design pass must therefore produce: (a) the granularity ladder the zoom traverses (district 2048m -> quarter 512m -> ? ), with derivation modes + per-window costs at each rung; (b) wire implications — finer windows multiply cell counts (quarter = 16x district cells/window); weigh against the windowed-family ceiling and the SS4 budget model (likely per-rung window requests reusing the same district_window carrier at different granularity, or a granularity param — design call); (c) THE FLOOR QUESTION back to Jeroen explicitly: ''tile size'' intersects the D-226(d) ceiling (chunk/tile output never Atlas-mapped; quarter is the current legal floor) — the pass presents the options (stop at quarter vs supersede D-226(d) for the window view) rather than assuming; (d) Araminta: encoding continuity across rungs (one colorizer family, hue stability as resolution refines). The COMPOSITE_SMOOTH linear-filter path ships until this lands, then is expected to be retired.
|
||
|
||
D-166 amendment 2026-07-21 (Jeroen, from the Groombridge/Lendel zoom captures): the seamless zoom ladder this ticket designs is now a HARD Phase-4 deliverable condition — T-750 does not close until the ladder stands (planetary map -> tile scale, every level deterministically derived at native granularity, never magnified interpolation; BHAG itself unchanged). Evidence baked into the amendment: at Lendel scale one heightmap px spans ~19 districts, so the current 16-district window is sub-pixel vs its source — beyond fit-zoom the viewer can only magnify the same composite, and the real waterline sat ~36 districts from the pixel-edge estimate (all window-scale-and-below information is D-227 invented detail and must be derived, not smoothed). This raises the design pass''s stakes: the granularity-rung ladder, wire budget, and the D-226(d) floor question are now phase-gating.
|
||
|
||
Corollary to the D-166 2026-07-21 amendment (Jeroen, same day): heightmap PNGs are demoted to INVISIBLE derivation input — no zoom level displays them, including orbital/planetary, which must itself be FULLY DERIVED. Display at every rung samples the derivation at CANVAS RESOLUTION (continuous field, not fixed rasters) — this drops zoom over- and undersampling by construction and makes the map adapt to any viewport size. Design-pass additions: (e) the planetary/orbital rung becomes derived output — spec its derivation mode + cost (whole-planet at canvas res; today''s AtlasViewer texture path retires when it lands); (f) canvas-resolution-adaptive sampling replaces fixed per-rung display granularity — the rung ladder defines DERIVATION granularity available at each scale, while sampling density tracks the viewport; (g) import_heightmaps stays as input storage only.', 'Follow-on from Jeroen''s first descent (2026-07-21): even with T-1142 fixed, many interior windows are genuinely one morphology zone across 66km, and the composite''s absolute lightness modulation (0.7 + 0.3 x elev_q/100, D-226 T-1124 SS5) spans only ~1-3% lightness over a window whose local elev range is small — the window reads as a dead flat fill rather than terrain. Proposal to evaluate WITH Araminta (SS5 is her encoding): window-local contrast stretch — normalize lightness within the window''s own elev min..max (fixed band, e.g. 0.62..0.92) with a degenerate floor (single-value window stays honestly flat), deterministic per window, mirroring how the aliveness_probe elev panel achieved its 12-level local texture. Alternative/complement: a faint deterministic per-cell variation or contour hinting. Any change to the recorded SS5 encoding gets a one-line amendment note. Assess AFTER T-1142 lands — real clicks will then land on real terrain and the residual flatness can be judged on coastal vs interior windows.
|
||
|
||
Scope expansion (Jeroen round-2, 2026-07-21): beyond window-local contrast, evaluate SUB-DISTRICT SAMPLING to de-block the composite at the data level — the D-227 invention fields (invent_primitives: warped envelope, scatter, character) are continuous at metre resolution and quarter granularity (512m, 4x4 per district) sits WITHIN the D-226(d) Atlas ceiling (the cap rules out chunk/tile mapping, not quarters). But classification (derive_district) is per-district today — finer sampling means a new derivation mode (e.g. sample the continuous primitives at quarter spacing and reuse the district''s classification for hue while modulating lightness/moisture per quarter, or classify per quarter at 16x the derive cost — n=32 window = 16384 quarter cells x ~7us = ~115ms background). Needs Dudley/Tyre on data feasibility + cost, Araminta on encoding. INTERIM already shipping in T-1145: linear-filtered texture rendering (presentation smoothing, no data change) — judge the residual need after both T-1145 and real-aim clicking land.
|
||
|
||
RULING (Jeroen, 2026-07-21, round-3 direction): the smooth-gradient rendering is INTERIM ONLY — he expects not to like it as the destination. The destination is SMALLER DETERMINISTICALLY-CALCULATED PIXELS (sub-district sampling, the sketch above), and the larger vision: SCROLL-ZOOM AS CONTINUOUS INFORMATION LoD — zooming in from the regional level progressively refines the sampled resolution seamlessly (no mode transition), ''zoom in to tile size from this level'' in his words. The design pass must therefore produce: (a) the granularity ladder the zoom traverses (district 2048m -> quarter 512m -> ? ), with derivation modes + per-window costs at each rung; (b) wire implications — finer windows multiply cell counts (quarter = 16x district cells/window); weigh against the windowed-family ceiling and the SS4 budget model (likely per-rung window requests reusing the same district_window carrier at different granularity, or a granularity param — design call); (c) THE FLOOR QUESTION back to Jeroen explicitly: ''tile size'' intersects the D-226(d) ceiling (chunk/tile output never Atlas-mapped; quarter is the current legal floor) — the pass presents the options (stop at quarter vs supersede D-226(d) for the window view) rather than assuming; (d) Araminta: encoding continuity across rungs (one colorizer family, hue stability as resolution refines). The COMPOSITE_SMOOTH linear-filter path ships until this lands, then is expected to be retired.
|
||
|
||
D-166 amendment 2026-07-21 (Jeroen, from the Groombridge/Lendel zoom captures): the seamless zoom ladder this ticket designs is now a HARD Phase-4 deliverable condition — T-750 does not close until the ladder stands (planetary map -> tile scale, every level deterministically derived at native granularity, never magnified interpolation; BHAG itself unchanged). Evidence baked into the amendment: at Lendel scale one heightmap px spans ~19 districts, so the current 16-district window is sub-pixel vs its source — beyond fit-zoom the viewer can only magnify the same composite, and the real waterline sat ~36 districts from the pixel-edge estimate (all window-scale-and-below information is D-227 invented detail and must be derived, not smoothed). This raises the design pass''s stakes: the granularity-rung ladder, wire budget, and the D-226(d) floor question are now phase-gating.
|
||
|
||
Corollary to the D-166 2026-07-21 amendment (Jeroen, same day): heightmap PNGs are demoted to INVISIBLE derivation input — no zoom level displays them, including orbital/planetary, which must itself be FULLY DERIVED. Display at every rung samples the derivation at CANVAS RESOLUTION (continuous field, not fixed rasters) — this drops zoom over- and undersampling by construction and makes the map adapt to any viewport size. Design-pass additions: (e) the planetary/orbital rung becomes derived output — spec its derivation mode + cost (whole-planet at canvas res; today''s AtlasViewer texture path retires when it lands); (f) canvas-resolution-adaptive sampling replaces fixed per-rung display granularity — the rung ladder defines DERIVATION granularity available at each scale, while sampling density tracks the viewport; (g) import_heightmaps stays as input storage only.
|
||
|
||
DESIGN PASS DELIVERED (2026-07-21): docs/architecture/atlas-zoom-ladder-t1143.md — 9-agent pass (Tyre/Dudley/Araminta design, Troblum adversarial + completeness critique, Qatux synthesis). Jeroen''s three rulings recorded as a D-226 amendment: (1) floor OPENED — ''we set a new BHAG so old restrictions are up for debate''; ladder may descend below quarter, gated on the T-1154 measurement pass; (2) planetary carrier = progressive capped-density tiling on the generalized district_window carrier; (3) entry seam = continuous cursor-anchored zoom with full-zoom-out reset to the canonical planetary frame (supersedes the click-through-only cut). Implementation chain created: T-1149 (derive_at_metres + octave cutoff, keystone) -> T-1150 (granularity carrier, five touch points + aliasing test) + T-1151 (window par_iter) -> T-1152 (derived planetary rung) + T-1153 (client continuous ladder) -> T-1155 (COMPOSITE_SMOOTH retirement); T-1154 (below-quarter measurement gate). Original scope items resolved by the ladder: window-local contrast stretch judged obsolete under quarter sampling (SS6), COMPOSITE_SMOOTH interim retires at T-1155.', NULL, '2026-07-21 19:52:27', '2026-07-21 19:52:27.616', '2026-07-21 19:52:27.616', NULL, 'f52022c88cefd0dcc1d65326af982756', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FR97DPEHANCYX2AC4021BSJC', 'status', 'in_progress', 'done', NULL, '2026-07-21 19:52:32', '2026-07-21 19:52:32.105', '2026-07-21 19:52:32.105', NULL, '3d864118d925071e6e5b4b182264ccac', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCET0RKD7ED9D9RY5Q99RQG', 'status', 'backlog', 'in_progress', NULL, '2026-07-21 21:50:03', '2026-07-21 21:50:03.771', '2026-07-21 21:50:03.771', NULL, '89f8a1771109ee95f9abde50d1cbb52e', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCEV8Q32C2FW9Y6733419DG', 'status', 'backlog', 'in_progress', NULL, '2026-07-21 21:50:03', '2026-07-21 21:50:03.778', '2026-07-21 21:50:03.778', NULL, '82d421b440a60a51671401b7d443af78', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCEWBS5RC5YET0SMSPZ1E9W', 'status', 'backlog', 'in_progress', NULL, '2026-07-21 21:50:03', '2026-07-21 21:50:03.779', '2026-07-21 21:50:03.779', NULL, 'b3fcdcbb65bdb39523bd09ed1a2252e8', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCET0RKD7ED9D9RY5Q99RQG', 'status', 'in_progress', 'review', NULL, '2026-07-21 22:28:45', '2026-07-21 22:28:45.442', '2026-07-21 22:28:45.442', NULL, '3aa3ea7868511c67552c4290fbfba1c5', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCEV8Q32C2FW9Y6733419DG', 'status', 'in_progress', 'review', NULL, '2026-07-21 22:28:45', '2026-07-21 22:28:45.449', '2026-07-21 22:28:45.449', NULL, 'e452314267c88b737d3de199b44b8757', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCEWBS5RC5YET0SMSPZ1E9W', 'status', 'in_progress', 'review', NULL, '2026-07-21 22:28:45', '2026-07-21 22:28:45.450', '2026-07-21 22:28:45.450', NULL, '44c750b1ef79e5b5cf1994b61160a28e', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCET0RKD7ED9D9RY5Q99RQG', 'status', 'review', 'done', NULL, '2026-07-21 22:54:32', '2026-07-21 22:54:32.382', '2026-07-21 22:54:32.382', NULL, '20d7be4411eb2ffc6ef2089443040a53', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCEV8Q32C2FW9Y6733419DG', 'status', 'review', 'done', NULL, '2026-07-21 22:54:32', '2026-07-21 22:54:32.389', '2026-07-21 22:54:32.389', NULL, '9823d7bfcb7ee233020fb0d7b740651d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCEWBS5RC5YET0SMSPZ1E9W', 'status', 'review', 'done', NULL, '2026-07-21 22:54:32', '2026-07-21 22:54:32.390', '2026-07-21 22:54:32.390', NULL, '40cbabb32cf6ebabaf362d536ce3a3a5', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCEXHYP8RVBPB8QNZHTNTR0', 'status', 'backlog', 'in_progress', NULL, '2026-07-22 08:00:52', '2026-07-22 08:00:52.300', '2026-07-22 08:00:52.300', NULL, 'd8baca0fa0c74bce4ec0387c8a0699bd', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCEZ47J16E3XKE957HGR8H4', 'status', 'backlog', 'in_progress', NULL, '2026-07-22 08:00:52', '2026-07-22 08:00:52.307', '2026-07-22 08:00:52.307', NULL, '2b5b5fb32f256dfd64f8d8b2135b42bf', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRJD6EKPBQE08NA8VHP692W8', 'description', 'T-1153 broke the T-1120/T-1121 golden capture harness: client/tests/visual_scenarios.gd and visual_capture.gd call app._regional_screen._viewer.get_heightmap_texture()/show_body() — both crash against AtlasWindowViewer (regional_screen now wraps the ladder viewer; AtlasViewer is unreachable from nav). Confirmed NOT wired into tests/run-godot or the pre-push hook (no reference in either), so nothing blocks, but the 12 curated atlas_* goldens and the --atlas-matrix capture path are dead until redesigned for the ladder (capture at defined rungs/zooms instead of the fixed heightmap frame; the new canonical orbital frame is the natural replacement for the old whole-body shot). Also decide the fate of the retired AtlasViewer code these harnesses were the last live consumers of — likely deletable once T-1156 (overlay port) settles what carries forward.', 'T-1153 broke the T-1120/T-1121 golden capture harness: client/tests/visual_scenarios.gd and visual_capture.gd call app._regional_screen._viewer.get_heightmap_texture()/show_body() — both crash against AtlasWindowViewer (regional_screen now wraps the ladder viewer; AtlasViewer is unreachable from nav). Confirmed NOT wired into tests/run-godot or the pre-push hook (no reference in either), so nothing blocks, but the 12 curated atlas_* goldens and the --atlas-matrix capture path are dead until redesigned for the ladder (capture at defined rungs/zooms instead of the fixed heightmap frame; the new canonical orbital frame is the natural replacement for the old whole-body shot). Also decide the fate of the retired AtlasViewer code these harnesses were the last live consumers of — likely deletable once T-1156 (overlay port) settles what carries forward.
|
||
|
||
Live round 4 addendum: client/tests/test_atlas_window_overlay_draw_smoke.gd (3 scenarios -> now 2 after removing a flaky harness-sanity check: single-window draw + tile-mosaic draw, both asserting real composited pixels via SubViewport render) is a standalone gdUnit file with its own headless-skip guard, added because this redesign hadn''t landed yet. When this ticket lands, migrate its 2 scenarios into the redesigned tests/visual.json harness (folding the standalone file away) for consistency with the rest of the real-rendering test suite — see docs/DEVOPS.md''s ''Real-rendering test exception'' note for the interim rationale.', NULL, '2026-07-22 12:37:50', '2026-07-22 12:37:50.448', '2026-07-22 12:37:50.448', NULL, '84a225b957e0106d111f3aa334f882c2', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCEXHYP8RVBPB8QNZHTNTR0', 'status', 'in_progress', 'review', NULL, '2026-07-22 14:50:50', '2026-07-22 14:50:50.781', '2026-07-22 14:50:50.781', NULL, 'ff6f498d0949127287e7a885729c020d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCEZ47J16E3XKE957HGR8H4', 'status', 'in_progress', 'review', NULL, '2026-07-22 14:50:50', '2026-07-22 14:50:50.784', '2026-07-22 14:50:50.784', NULL, 'fb6f65da8857906958d2865936070c78', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCEXHYP8RVBPB8QNZHTNTR0', 'status', 'review', 'done', NULL, '2026-07-22 15:40:43', '2026-07-22 15:40:43.466', '2026-07-22 15:40:43.466', NULL, 'cfe2434143354d1d9eb28a7f5b87a6d8', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCEZ47J16E3XKE957HGR8H4', 'status', 'review', 'done', NULL, '2026-07-22 15:40:43', '2026-07-22 15:40:43.468', '2026-07-22 15:40:43.468', NULL, 'e04949dc75c415f6fe274c3e5ba7d5c4', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRNAHD35YPZHJWMJCRZK62Z4', 'description', 'Jeroen, 2026-07-22, after first hands-on with the shipped ladder: ''zero detail on lower levels, just a green field, and the green-blue transition is a fade — it should be a more detailed coastline.'' Root cause confirmed by octave audit: the window classification consumes terrain_detail whose octaves span 32768-4096m (OCTAVE_WAVELENGTHS_M, detail_scatter.rs:33) and coast_invention whose warp octaves span 262144-16384m (WARP_OCTAVE_WAVELENGTHS_M, coast_invention.rs:56) — so at Quarter spacing (512m) the sampled field is genuinely smooth (~8 cells per finest terrain wave; ~32 per finest coast wave). The ladder''s TRANSPORT reaches 512m but its CONTENT floor is 4km/16km. The finer bands already exist (VOXEL_OCTAVE_WAVELENGTHS_M 1024-128m ''the rolling hills a walking character navigates by''; MOSAIC 64-8m) but feed only the Phase-5 voxel path — never the window derivation. Work: (a) extend coast_warp octaves below 16km down through quarter-visible wavelengths (bays/headlands/islets appearing as you zoom — THE headline visual ask) with min_wavelength_m cutoff discipline per rung; (b) feed the sub-district relief band into Quarter-rung classification (derive_at_metres already takes the cutoff — decide which bands activate per rung and re-bench; the T-1149 bench harness is the tool); (c) re-tune MIN_WL_BANDS_M to match the extended ladder; (d) determinism goldens updated deliberately (this CHANGES derived output — a golden-regeneration commit with rationale, not silent). Costs measured before merge per the T-1149 discipline. Visual acceptance: a coastal Quarter capture must show structurally more coastline detail than the same coast at District — the differentiation Araminta flagged as never yet demonstrated. Pairs with T-1161 (NEAREST at sparse rungs) — together these answer both of Jeroen''s specific complaints.', 'Jeroen, 2026-07-22, after first hands-on with the shipped ladder: ''zero detail on lower levels, just a green field, and the green-blue transition is a fade — it should be a more detailed coastline.'' Root cause confirmed by octave audit: the window classification consumes terrain_detail whose octaves span 32768-4096m (OCTAVE_WAVELENGTHS_M, detail_scatter.rs:33) and coast_invention whose warp octaves span 262144-16384m (WARP_OCTAVE_WAVELENGTHS_M, coast_invention.rs:56) — so at Quarter spacing (512m) the sampled field is genuinely smooth (~8 cells per finest terrain wave; ~32 per finest coast wave). The ladder''s TRANSPORT reaches 512m but its CONTENT floor is 4km/16km. The finer bands already exist (VOXEL_OCTAVE_WAVELENGTHS_M 1024-128m ''the rolling hills a walking character navigates by''; MOSAIC 64-8m) but feed only the Phase-5 voxel path — never the window derivation. Work: (a) extend coast_warp octaves below 16km down through quarter-visible wavelengths (bays/headlands/islets appearing as you zoom — THE headline visual ask) with min_wavelength_m cutoff discipline per rung; (b) feed the sub-district relief band into Quarter-rung classification (derive_at_metres already takes the cutoff — decide which bands activate per rung and re-bench; the T-1149 bench harness is the tool); (c) re-tune MIN_WL_BANDS_M to match the extended ladder; (d) determinism goldens updated deliberately (this CHANGES derived output — a golden-regeneration commit with rationale, not silent). Costs measured before merge per the T-1149 discipline. Visual acceptance: a coastal Quarter capture must show structurally more coastline detail than the same coast at District — the differentiation Araminta flagged as never yet demonstrated. Pairs with T-1161 (NEAREST at sparse rungs) — together these answer both of Jeroen''s specific complaints.
|
||
|
||
SCOPE CLARIFICATION (Jeroen, 2026-07-22): the current aim is the NATURE layer — geo + wild growth — per D-166''s outside-in order; cities/settlements stay uncolored for now. This ticket''s octave extension therefore covers not just coast + relief but VEGETATION PATCHINESS as spatial content: forests as massifs at region scale resolving to distinct woods (district), copses and clearings (quarter), desert/steppe transitions as shapes — the invention fields (detail_scatter character/envelope) driving per-rung vegetation patterning in the BASE layer rather than uniform per-cell class tint. His words: ''even the nature layer should produce rivers, forests, copses, bushes, deserts, elevation.'' Rivers are T-1156''s nature half (see its re-scope); this ticket owns the continuous-field content (coastline, relief, vegetation/moisture patchiness).', NULL, '2026-07-22 16:32:47', '2026-07-22 16:32:47.939', '2026-07-22 16:32:47.939', NULL, '9fb82408741df2989f6c74bb181da796', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRJD57678SVWD7XTSV9E3MSW', 'description', 'T-1153/T-1152 retired the AtlasViewer heightmap screen as the atlas entry; its 17-entry overlay surface did NOT carry to the Region-rung ladder view (AtlasWindowViewer has only gen_dw_temp/moisture/veg). Deferred wholesale by Stig with rationale: these overlays key off markers.json/city-names/road-graph/settlement data the DistrictWindowLayer wire shape does not carry — porting is a per-overlay design + wire question (at what rung does a settlement marker fade in? does POL make sense over a Region composite?), not a mechanical copy. Deferred set: city markers + click-to-inspect city data sidebar; roads/rail/settlements/quarter-footprint generation overlays (gen_l1_rivers/basins/attractors, gen_district, gen_l2_roads, gen_l3_settlements, gen_region_grid, gen_l4_quarters); political zones, population density, corp presence, production/stockpile toggles, gate markers, named features. The retired code survives intact and unreachable on atlas_viewer.gd — reuse it or retire it explicitly per overlay. Needs Araminta (per-rung affordance/fade rules) + Tyre/Dudley (which overlays need new wire fields vs client-side joins). Until this lands the ladder view is terrain-only — a real capability regression vs the old planetary screen, accepted knowingly in the T-1152/T-1153 batch.', 'T-1153/T-1152 retired the AtlasViewer heightmap screen as the atlas entry; its 17-entry overlay surface did NOT carry to the Region-rung ladder view (AtlasWindowViewer has only gen_dw_temp/moisture/veg). Deferred wholesale by Stig with rationale: these overlays key off markers.json/city-names/road-graph/settlement data the DistrictWindowLayer wire shape does not carry — porting is a per-overlay design + wire question (at what rung does a settlement marker fade in? does POL make sense over a Region composite?), not a mechanical copy. Deferred set: city markers + click-to-inspect city data sidebar; roads/rail/settlements/quarter-footprint generation overlays (gen_l1_rivers/basins/attractors, gen_district, gen_l2_roads, gen_l3_settlements, gen_region_grid, gen_l4_quarters); political zones, population density, corp presence, production/stockpile toggles, gate markers, named features. The retired code survives intact and unreachable on atlas_viewer.gd — reuse it or retire it explicitly per overlay. Needs Araminta (per-rung affordance/fade rules) + Tyre/Dudley (which overlays need new wire fields vs client-side joins). Until this lands the ladder view is terrain-only — a real capability regression vs the old planetary screen, accepted knowingly in the T-1152/T-1153 batch.
|
||
|
||
RE-SCOPED (Jeroen, 2026-07-22): ''we are aiming for not coloring in the cities at the moment — the nature layer (geo and wild growth) first,'' matching D-166''s outside-in order. SPLIT this ticket''s overlay set into two waves. WAVE 1 (this ticket, promoted): the NATURE overlays — gen_l1_rivers/basins/attractors onto the ladder (rivers as per-rung refining features: trunk rivers at Region, tributaries at District, streams at Quarter — the wire/derivation question of serving river skeletons windowed is the real work), plus named natural features (rivers/oceans/ranges labels) if cheap. WAVE 2 (deferred until the nature layer stands, per Jeroen): everything civilizational — city markers + sidebar, settlements/quarters footprints, roads/rail, POL/POP/CRP/gate markers. Do not port wave 2 with wave 1.', NULL, '2026-07-22 16:32:58', '2026-07-22 16:32:58.189', '2026-07-22 16:32:58.189', NULL, '9eb8e20a198920c024087e6153d4806b', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRPCJ4KD6SB9TB8TH9SJH1E0', 'status', 'backlog', 'review', NULL, '2026-07-22 18:59:22', '2026-07-22 18:59:22.418', '2026-07-22 18:59:22.418', NULL, 'ec51e983461658e7857f3c04a1ff73e5', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRPCJ4KD6SB9TB8TH9SJH1E0', 'status', 'review', 'done', NULL, '2026-07-22 19:29:52', '2026-07-22 19:29:52.281', '2026-07-22 19:29:52.281', NULL, 'd56f979255d7655437b286362d412900', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRNAHD35YPZHJWMJCRZK62Z4', 'status', 'backlog', 'in_progress', NULL, '2026-07-22 20:24:43', '2026-07-22 20:24:43.745', '2026-07-22 20:24:43.745', NULL, '43b44fba8bd2305f8d2fbfab666c1f51', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRMPY76TYY76FSBV2Y5P8QHM', 'status', 'backlog', 'in_progress', NULL, '2026-07-22 20:24:43', '2026-07-22 20:24:43.752', '2026-07-22 20:24:43.752', NULL, '50ed7f47477b51cebebc4604d38cc94e', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRNAHD35YPZHJWMJCRZK62Z4', 'description', 'Jeroen, 2026-07-22, after first hands-on with the shipped ladder: ''zero detail on lower levels, just a green field, and the green-blue transition is a fade — it should be a more detailed coastline.'' Root cause confirmed by octave audit: the window classification consumes terrain_detail whose octaves span 32768-4096m (OCTAVE_WAVELENGTHS_M, detail_scatter.rs:33) and coast_invention whose warp octaves span 262144-16384m (WARP_OCTAVE_WAVELENGTHS_M, coast_invention.rs:56) — so at Quarter spacing (512m) the sampled field is genuinely smooth (~8 cells per finest terrain wave; ~32 per finest coast wave). The ladder''s TRANSPORT reaches 512m but its CONTENT floor is 4km/16km. The finer bands already exist (VOXEL_OCTAVE_WAVELENGTHS_M 1024-128m ''the rolling hills a walking character navigates by''; MOSAIC 64-8m) but feed only the Phase-5 voxel path — never the window derivation. Work: (a) extend coast_warp octaves below 16km down through quarter-visible wavelengths (bays/headlands/islets appearing as you zoom — THE headline visual ask) with min_wavelength_m cutoff discipline per rung; (b) feed the sub-district relief band into Quarter-rung classification (derive_at_metres already takes the cutoff — decide which bands activate per rung and re-bench; the T-1149 bench harness is the tool); (c) re-tune MIN_WL_BANDS_M to match the extended ladder; (d) determinism goldens updated deliberately (this CHANGES derived output — a golden-regeneration commit with rationale, not silent). Costs measured before merge per the T-1149 discipline. Visual acceptance: a coastal Quarter capture must show structurally more coastline detail than the same coast at District — the differentiation Araminta flagged as never yet demonstrated. Pairs with T-1161 (NEAREST at sparse rungs) — together these answer both of Jeroen''s specific complaints.
|
||
|
||
SCOPE CLARIFICATION (Jeroen, 2026-07-22): the current aim is the NATURE layer — geo + wild growth — per D-166''s outside-in order; cities/settlements stay uncolored for now. This ticket''s octave extension therefore covers not just coast + relief but VEGETATION PATCHINESS as spatial content: forests as massifs at region scale resolving to distinct woods (district), copses and clearings (quarter), desert/steppe transitions as shapes — the invention fields (detail_scatter character/envelope) driving per-rung vegetation patterning in the BASE layer rather than uniform per-cell class tint. His words: ''even the nature layer should produce rivers, forests, copses, bushes, deserts, elevation.'' Rivers are T-1156''s nature half (see its re-scope); this ticket owns the continuous-field content (coastline, relief, vegetation/moisture patchiness).', 'Jeroen, 2026-07-22, after first hands-on with the shipped ladder: ''zero detail on lower levels, just a green field, and the green-blue transition is a fade — it should be a more detailed coastline.'' Root cause confirmed by octave audit: the window classification consumes terrain_detail whose octaves span 32768-4096m (OCTAVE_WAVELENGTHS_M, detail_scatter.rs:33) and coast_invention whose warp octaves span 262144-16384m (WARP_OCTAVE_WAVELENGTHS_M, coast_invention.rs:56) — so at Quarter spacing (512m) the sampled field is genuinely smooth (~8 cells per finest terrain wave; ~32 per finest coast wave). The ladder''s TRANSPORT reaches 512m but its CONTENT floor is 4km/16km. The finer bands already exist (VOXEL_OCTAVE_WAVELENGTHS_M 1024-128m ''the rolling hills a walking character navigates by''; MOSAIC 64-8m) but feed only the Phase-5 voxel path — never the window derivation. Work: (a) extend coast_warp octaves below 16km down through quarter-visible wavelengths (bays/headlands/islets appearing as you zoom — THE headline visual ask) with min_wavelength_m cutoff discipline per rung; (b) feed the sub-district relief band into Quarter-rung classification (derive_at_metres already takes the cutoff — decide which bands activate per rung and re-bench; the T-1149 bench harness is the tool); (c) re-tune MIN_WL_BANDS_M to match the extended ladder; (d) determinism goldens updated deliberately (this CHANGES derived output — a golden-regeneration commit with rationale, not silent). Costs measured before merge per the T-1149 discipline. Visual acceptance: a coastal Quarter capture must show structurally more coastline detail than the same coast at District — the differentiation Araminta flagged as never yet demonstrated. Pairs with T-1161 (NEAREST at sparse rungs) — together these answer both of Jeroen''s specific complaints.
|
||
|
||
SCOPE CLARIFICATION (Jeroen, 2026-07-22): the current aim is the NATURE layer — geo + wild growth — per D-166''s outside-in order; cities/settlements stay uncolored for now. This ticket''s octave extension therefore covers not just coast + relief but VEGETATION PATCHINESS as spatial content: forests as massifs at region scale resolving to distinct woods (district), copses and clearings (quarter), desert/steppe transitions as shapes — the invention fields (detail_scatter character/envelope) driving per-rung vegetation patterning in the BASE layer rather than uniform per-cell class tint. His words: ''even the nature layer should produce rivers, forests, copses, bushes, deserts, elevation.'' Rivers are T-1156''s nature half (see its re-scope); this ticket owns the continuous-field content (coastline, relief, vegetation/moisture patchiness).
|
||
|
||
REFINEMENT RESOLUTIONS (lead, 2026-07-22, from Si audit): (1) Bench baseline: none recorded anywhere — implementer runs server/tests/zoom_ladder_bench.rs (cargo test --release --test zoom_ladder_bench -- --ignored --nocapture) BEFORE any code change to establish the pre-change baseline, and again after; both sets of numbers go in the PR. (2) ''Goldens'' corrected: no golden file pins derive_at_metres/invent_primitives today (derivation_harness.json is voxel-chain; cascade_layer1.json is heightmap-river). Explicit scope: ADD a golden fixture for the window-derivation path (mirroring derivation_harness.rs''s pattern) so this and every future octave change gets a deliberate-regen commit discipline. (3) Vegetation patchiness confirmed NET-NEW, in scope (not split): today derive_vegetation (district_profile.rs:398-490) is pure per-cell classification with no positional field. Build the vegetation invention mechanism mirroring coast_invention.rs''s two-tier envelope+character model (Jeroen''s nature-first ruling is the direction; the tiered invention-field pattern is the established shape to imitate). Non-blocking notes: VOXEL octaves feeding Quarter classification does NOT conflict with D-226(d) — that ruling caps request granularity, not contributing wavelengths (coast warp already crosses scales the other way); MIN_WL_BANDS_M (layer_proxy.rs:415-421) needs new entries once the ladder extends, quantize_min_wl_m generalizes as-is.', NULL, '2026-07-22 20:27:10', '2026-07-22 20:27:10.426', '2026-07-22 20:27:10.426', NULL, '9c68eb51f80be06b8ba7236a1fed554c', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRNAHD35YPZHJWMJCRZK62Z4', 'status', 'in_progress', 'review', NULL, '2026-07-22 21:12:56', '2026-07-22 21:12:56.083', '2026-07-22 21:12:56.083', NULL, 'de22bdfa1dc98f8ff39accf77465af08', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRMPY76TYY76FSBV2Y5P8QHM', 'status', 'in_progress', 'review', NULL, '2026-07-22 21:12:56', '2026-07-22 21:12:56.086', '2026-07-22 21:12:56.086', NULL, '3f36b034fae900e91aae07591e26f2fd', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRNAHD35YPZHJWMJCRZK62Z4', 'status', 'review', 'done', NULL, '2026-07-22 21:39:18', '2026-07-22 21:39:18.433', '2026-07-22 21:39:18.433', NULL, '1ba2e86c9a7fd8b4c96c483bf15059c5', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRMPY76TYY76FSBV2Y5P8QHM', 'status', 'review', 'done', NULL, '2026-07-22 21:39:18', '2026-07-22 21:39:18.440', '2026-07-22 21:39:18.440', NULL, '5d5bceae118f89658b766b1960ccddc5', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCF1A0K41K6S85X0HTXACHM', 'status', 'backlog', 'cancelled', NULL, '2026-07-22 21:39:18', '2026-07-22 21:39:18.463', '2026-07-22 21:39:18.463', NULL, '57a833d67fd2d02aea02a9d87fe5a46e', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCF1A0K41K6S85X0HTXACHM', 'description', 'Zoom-ladder migration step 6 (docs/architecture/atlas-zoom-ladder-t1143.md SS8). The linear-filter interim (atlas_window_overlay.gd:60, T-1145) retires once granularity-4 quarter windows are the default at close zoom — real classified quarter cells replace GPU bilinear smoothing as the source of sub-district texture (Jeroen''s ruling: smoothing was never the destination). Remove the compile-time const and the crisp/smooth dual path; keep one render path. Blocked by the client zoom ladder.', 'Zoom-ladder migration step 6 (docs/architecture/atlas-zoom-ladder-t1143.md SS8). The linear-filter interim (atlas_window_overlay.gd:60, T-1145) retires once granularity-4 quarter windows are the default at close zoom — real classified quarter cells replace GPU bilinear smoothing as the source of sub-district texture (Jeroen''s ruling: smoothing was never the destination). Remove the compile-time const and the crisp/smooth dual path; keep one render path. Blocked by the client zoom ladder.
|
||
|
||
CANCELLED 2026-07-22 (PR #194 merge): superseded by T-1161''s two-axes outcome — COMPOSITE_SMOOTH survives as the compile-time pipeline axis (crisp draw_rect path kept for debug/compare); the crispness-at-sparse-rungs requirement is delivered by the per-rung sampling-filter policy (_filter_for_granularity_v2) instead of deleting the const. Design doc §8 step 6 errata''d + D-226 filter-axis note added in the same PR. No partial version of this ticket survives that outcome (Si audit + Tyre''s Q4 ruling agree: close-both, not do-first).', NULL, '2026-07-22 21:39:25', '2026-07-22 21:39:25.586', '2026-07-22 21:39:25.586', NULL, 'a0b8ff87488ca33009bff81f18ff0689', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRJD57678SVWD7XTSV9E3MSW', 'status', 'backlog', 'in_progress', NULL, '2026-07-23 05:48:12', '2026-07-23 05:48:12.602', '2026-07-23 05:48:12.602', NULL, '6afbef11d2d6391784bbc1e4686e13cb', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRJD57678SVWD7XTSV9E3MSW', 'status', 'in_progress', 'review', NULL, '2026-07-23 07:03:09', '2026-07-23 07:03:09.251', '2026-07-23 07:03:09.251', NULL, 'f7b016fa815ab8b383b06a37e5afa513', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRV2GT1FQVATWX641KY9K66C', 'description', 'Named experience gap from T-1156 wave 1 (Si audit + lead, 2026-07-23): the D8 river skeleton lives at heightmap working-grid resolution (512x256 — ~76.6 km per river cell on Lendel). Wave 1''s per-rung class filtering makes planetary/Region river courses real, but at District (2 km cells, ~65 km window) and Quarter the geometry is SPARSER THAN THE WINDOW — a window typically contains zero or one river cell, so ''tributaries at District, streams at Quarter'' cannot materialize as visible courses from the stored skeleton alone. The fix is the linear-feature analog of T-1162''s coast crinkle: deterministically INVENT river course geometry between/below D8 cells — domain-warped polyline interpolation between adjacent river cells (seeded per body+cell pair, D-227 discipline, elevation-aware so courses prefer invented-terrain valleys where feasible), refining with rung the same way the coast warp refines the coastline. Also the natural home for reconciling rivers with T-1162''s invented relief (a wave-1 known gap: drawn rivers may cross invented hills — acceptable at 76 km dot spacing, glaring once courses are continuous). Depends on wave 1''s carrier (river_class on RiverNetwork) landing first.', 'Named experience gap from T-1156 wave 1 (Si audit + lead, 2026-07-23): the D8 river skeleton lives at heightmap working-grid resolution (512x256 — ~76.6 km per river cell on Lendel). Wave 1''s per-rung class filtering makes planetary/Region river courses real, but at District (2 km cells, ~65 km window) and Quarter the geometry is SPARSER THAN THE WINDOW — a window typically contains zero or one river cell, so ''tributaries at District, streams at Quarter'' cannot materialize as visible courses from the stored skeleton alone. The fix is the linear-feature analog of T-1162''s coast crinkle: deterministically INVENT river course geometry between/below D8 cells — domain-warped polyline interpolation between adjacent river cells (seeded per body+cell pair, D-227 discipline, elevation-aware so courses prefer invented-terrain valleys where feasible), refining with rung the same way the coast warp refines the coastline. Also the natural home for reconciling rivers with T-1162''s invented relief (a wave-1 known gap: drawn rivers may cross invented hills — acceptable at 76 km dot spacing, glaring once courses are continuous). Depends on wave 1''s carrier (river_class on RiverNetwork) landing first.
|
||
|
||
T-1156 review forward-note (Tyre, PR #195 Q1): when this ticket redesigns the binning corner, consider PER-BASIN anchoring as an explicit option — every watershed gets its own trunk regardless of the body''s dominant river (the right eventual model once basins are player-inspectable), at the cost of a second normalization pass and a cross-basin legibility decision at Region scale (several equal-weight ''trunks'' of wildly different magnitude undersell the dominant drainage). The wave-1 global-per-body anchor is correct for ''show the main river system at a glance''. Single revisit points: classify_river_cell (server) and RIVER_CLASS_VISIBLE_BY_RUNG (client).', NULL, '2026-07-23 07:15:25', '2026-07-23 07:15:25.347', '2026-07-23 07:15:25.347', NULL, 'ade0e3edd8e491abc0375968d954f15d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRJD57678SVWD7XTSV9E3MSW', 'description', 'T-1153/T-1152 retired the AtlasViewer heightmap screen as the atlas entry; its 17-entry overlay surface did NOT carry to the Region-rung ladder view (AtlasWindowViewer has only gen_dw_temp/moisture/veg). Deferred wholesale by Stig with rationale: these overlays key off markers.json/city-names/road-graph/settlement data the DistrictWindowLayer wire shape does not carry — porting is a per-overlay design + wire question (at what rung does a settlement marker fade in? does POL make sense over a Region composite?), not a mechanical copy. Deferred set: city markers + click-to-inspect city data sidebar; roads/rail/settlements/quarter-footprint generation overlays (gen_l1_rivers/basins/attractors, gen_district, gen_l2_roads, gen_l3_settlements, gen_region_grid, gen_l4_quarters); political zones, population density, corp presence, production/stockpile toggles, gate markers, named features. The retired code survives intact and unreachable on atlas_viewer.gd — reuse it or retire it explicitly per overlay. Needs Araminta (per-rung affordance/fade rules) + Tyre/Dudley (which overlays need new wire fields vs client-side joins). Until this lands the ladder view is terrain-only — a real capability regression vs the old planetary screen, accepted knowingly in the T-1152/T-1153 batch.
|
||
|
||
RE-SCOPED (Jeroen, 2026-07-22): ''we are aiming for not coloring in the cities at the moment — the nature layer (geo and wild growth) first,'' matching D-166''s outside-in order. SPLIT this ticket''s overlay set into two waves. WAVE 1 (this ticket, promoted): the NATURE overlays — gen_l1_rivers/basins/attractors onto the ladder (rivers as per-rung refining features: trunk rivers at Region, tributaries at District, streams at Quarter — the wire/derivation question of serving river skeletons windowed is the real work), plus named natural features (rivers/oceans/ranges labels) if cheap. WAVE 2 (deferred until the nature layer stands, per Jeroen): everything civilizational — city markers + sidebar, settlements/quarters footprints, roads/rail, POL/POP/CRP/gate markers. Do not port wave 2 with wave 1.', 'T-1153/T-1152 retired the AtlasViewer heightmap screen as the atlas entry; its 17-entry overlay surface did NOT carry to the Region-rung ladder view (AtlasWindowViewer has only gen_dw_temp/moisture/veg). Deferred wholesale by Stig with rationale: these overlays key off markers.json/city-names/road-graph/settlement data the DistrictWindowLayer wire shape does not carry — porting is a per-overlay design + wire question (at what rung does a settlement marker fade in? does POL make sense over a Region composite?), not a mechanical copy. Deferred set: city markers + click-to-inspect city data sidebar; roads/rail/settlements/quarter-footprint generation overlays (gen_l1_rivers/basins/attractors, gen_district, gen_l2_roads, gen_l3_settlements, gen_region_grid, gen_l4_quarters); political zones, population density, corp presence, production/stockpile toggles, gate markers, named features. The retired code survives intact and unreachable on atlas_viewer.gd — reuse it or retire it explicitly per overlay. Needs Araminta (per-rung affordance/fade rules) + Tyre/Dudley (which overlays need new wire fields vs client-side joins). Until this lands the ladder view is terrain-only — a real capability regression vs the old planetary screen, accepted knowingly in the T-1152/T-1153 batch.
|
||
|
||
RE-SCOPED (Jeroen, 2026-07-22): ''we are aiming for not coloring in the cities at the moment — the nature layer (geo and wild growth) first,'' matching D-166''s outside-in order. SPLIT this ticket''s overlay set into two waves. WAVE 1 (this ticket, promoted): the NATURE overlays — gen_l1_rivers/basins/attractors onto the ladder (rivers as per-rung refining features: trunk rivers at Region, tributaries at District, streams at Quarter — the wire/derivation question of serving river skeletons windowed is the real work), plus named natural features (rivers/oceans/ranges labels) if cheap. WAVE 2 (deferred until the nature layer stands, per Jeroen): everything civilizational — city markers + sidebar, settlements/quarters footprints, roads/rail, POL/POP/CRP/gate markers. Do not port wave 2 with wave 1.
|
||
|
||
WAVE-2 REFACTOR NOTE (Tyre, PR #195 Q3): when the civilizational overlays land, host the whole discrete-marker family (city markers, labels, gate glyphs, click targets — all screen-space-constant) on an UNSCALED screen-space sibling Node2D (transform positions into screen space, leave .scale at 1.0) and retire per-call zoom compensation (_zs/zoom_compensated_size) — screen-space-constant becomes correct by construction instead of a per-call-site discipline that silently degrades when one site is missed (PR #195 I1 was exactly that miss). The divide-by-zoom approach shipped in wave 1 is fine once compensated, but the sibling-layer shape is the standard ''HUD annotations over a zoomed canvas'' pattern and pays for itself at wave-2 marker volume. T-1158-adjacent.', NULL, '2026-07-23 07:15:25', '2026-07-23 07:15:25.374', '2026-07-23 07:15:25.374', NULL, '55f2c203cb7e77b39d563a5aaaf1aef2', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRJD57678SVWD7XTSV9E3MSW', 'status', 'review', 'done', NULL, '2026-07-23 07:35:36', '2026-07-23 07:35:36.008', '2026-07-23 07:35:36.008', NULL, 'c624aea58ec451336f11296924898ff3', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRW2ABEG6HQHVKQ9F7NQ1K8R', 'status', 'backlog', 'in_progress', NULL, '2026-07-23 08:16:50', '2026-07-23 08:16:50.647', '2026-07-23 08:16:50.647', NULL, 'd79b72f2f56ec852a84b123b52159f3e', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRW2ABEG6HQHVKQ9F7NQ1K8R', 'description', 'Jeroen, 2026-07-23, first hands-on with PR #195''s merged captures: ''the rivers seem to be continuing under the waterline of the ocean.'' Mechanism confirmed by code inspection: river_cells/mouths are filtered against the RAW 512x256 heightmap sea level (drainage.rs:258-259, elevation[i] >= sea_level), but the drawn ocean is the derived MORPHOLOGY verdict (district_profile.rs:1464-1465 open_water) — which post-T-1162 includes the coast-warp invention (the drawn coastline is deterministically displaced from the heightmap coast) and at Region rung aggregates at 204.8 km cells. Anywhere the two waterlines disagree, a raw-land river dot renders over painted ocean; mouths are worst-case by definition (last land cell on the RAW coast — wherever the drawn coast is displaced inland, mouths render offshore). Long ocean-crossing dot trails = low-lying raw-land chains the derived morphology paints as water. This is the Q-100 dual-artifact class Si''s wave-1 audit pre-flagged. Fix-layer options for Tyre''s ruling: (A) client-side clip against the arrived composite''s per-cell water class (cheap, presentational, keeps two truths but hides disagreement; needs a mouth rule — snap-to-drawn-land vs suppress); (B) server-side reconciliation — classify skeleton cells against the WARPED/derived coast at extraction (one truthful waterline per D-166 honesty; couples drainage to the invention layer, golden + cost implications); (C) fold into T-1170 course invention (courses terminate at the invented coast naturally) and accept the artifact until then.', 'Jeroen, 2026-07-23, first hands-on with PR #195''s merged captures: ''the rivers seem to be continuing under the waterline of the ocean.'' Mechanism confirmed by code inspection: river_cells/mouths are filtered against the RAW 512x256 heightmap sea level (drainage.rs:258-259, elevation[i] >= sea_level), but the drawn ocean is the derived MORPHOLOGY verdict (district_profile.rs:1464-1465 open_water) — which post-T-1162 includes the coast-warp invention (the drawn coastline is deterministically displaced from the heightmap coast) and at Region rung aggregates at 204.8 km cells. Anywhere the two waterlines disagree, a raw-land river dot renders over painted ocean; mouths are worst-case by definition (last land cell on the RAW coast — wherever the drawn coast is displaced inland, mouths render offshore). Long ocean-crossing dot trails = low-lying raw-land chains the derived morphology paints as water. This is the Q-100 dual-artifact class Si''s wave-1 audit pre-flagged. Fix-layer options for Tyre''s ruling: (A) client-side clip against the arrived composite''s per-cell water class (cheap, presentational, keeps two truths but hides disagreement; needs a mouth rule — snap-to-drawn-land vs suppress); (B) server-side reconciliation — classify skeleton cells against the WARPED/derived coast at extraction (one truthful waterline per D-166 honesty; couples drainage to the invention layer, golden + cost implications); (C) fold into T-1170 course invention (courses terminate at the invented coast naturally) and accept the artifact until then.
|
||
|
||
TYRE RULING (2026-07-23, full text in PR record): option (D) — client-side draw-time clip now, retired into T-1170. Mechanism sizing corrected: WARP_AMPLITUDE_CAP_PX=0.75 (sub-pixel, ~57km max on Lendel) proves the warp is fringe-only — the ocean-crossing trails are Region morphology AGGREGATION painting low raw-land shelves as OpenOcean. Decisive architecture point: the drawn coast is RUNG-INDEXED (warp_fbm''s cutoff admits more octaves at finer rungs — a family of curves, not one), so no single server-side waterline is well-defined; option (B) rejected on well-definedness, not cost. Rules: (1) clip river dots + confluences against the arrived composite''s per-cell morphology water verdict (OpenOcean/Lake) at the rung being painted — strict drop, no snap; (2) Region 205km-cell amputation of final coastal dots accepted (invisible vs the trails it kills); (3) mouths in drawn-water cells SUPPRESSED, never snapped (snapping invents an uncomputed landmark; suppressed mouths return with real geometry in T-1170) — flagged to Jeroen as the one taste call, proceeding on Tyre''s recommendation; (4) basin boundaries NOT clipped (faint watershed overlay, legitimately grazes offshore pour-points — out of scope); (5) dot-pop across rungs is the honest consequence of the rung-indexed coast, not a regression; (6) retirement marker at the clip site, retired in the same change as T-1170''s coast-terminating courses. D-226 two-waterline note text supplied (rides the fix branch).', NULL, '2026-07-23 08:16:50', '2026-07-23 08:16:50.672', '2026-07-23 08:16:50.672', NULL, '002af7c88b10a6983314622bacd2bcbe', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRV2GT1FQVATWX641KY9K66C', 'description', 'Named experience gap from T-1156 wave 1 (Si audit + lead, 2026-07-23): the D8 river skeleton lives at heightmap working-grid resolution (512x256 — ~76.6 km per river cell on Lendel). Wave 1''s per-rung class filtering makes planetary/Region river courses real, but at District (2 km cells, ~65 km window) and Quarter the geometry is SPARSER THAN THE WINDOW — a window typically contains zero or one river cell, so ''tributaries at District, streams at Quarter'' cannot materialize as visible courses from the stored skeleton alone. The fix is the linear-feature analog of T-1162''s coast crinkle: deterministically INVENT river course geometry between/below D8 cells — domain-warped polyline interpolation between adjacent river cells (seeded per body+cell pair, D-227 discipline, elevation-aware so courses prefer invented-terrain valleys where feasible), refining with rung the same way the coast warp refines the coastline. Also the natural home for reconciling rivers with T-1162''s invented relief (a wave-1 known gap: drawn rivers may cross invented hills — acceptable at 76 km dot spacing, glaring once courses are continuous). Depends on wave 1''s carrier (river_class on RiverNetwork) landing first.
|
||
|
||
T-1156 review forward-note (Tyre, PR #195 Q1): when this ticket redesigns the binning corner, consider PER-BASIN anchoring as an explicit option — every watershed gets its own trunk regardless of the body''s dominant river (the right eventual model once basins are player-inspectable), at the cost of a second normalization pass and a cross-basin legibility decision at Region scale (several equal-weight ''trunks'' of wildly different magnitude undersell the dominant drainage). The wave-1 global-per-body anchor is correct for ''show the main river system at a glance''. Single revisit points: classify_river_cell (server) and RIVER_CLASS_VISIBLE_BY_RUNG (client).', 'Named experience gap from T-1156 wave 1 (Si audit + lead, 2026-07-23): the D8 river skeleton lives at heightmap working-grid resolution (512x256 — ~76.6 km per river cell on Lendel). Wave 1''s per-rung class filtering makes planetary/Region river courses real, but at District (2 km cells, ~65 km window) and Quarter the geometry is SPARSER THAN THE WINDOW — a window typically contains zero or one river cell, so ''tributaries at District, streams at Quarter'' cannot materialize as visible courses from the stored skeleton alone. The fix is the linear-feature analog of T-1162''s coast crinkle: deterministically INVENT river course geometry between/below D8 cells — domain-warped polyline interpolation between adjacent river cells (seeded per body+cell pair, D-227 discipline, elevation-aware so courses prefer invented-terrain valleys where feasible), refining with rung the same way the coast warp refines the coastline. Also the natural home for reconciling rivers with T-1162''s invented relief (a wave-1 known gap: drawn rivers may cross invented hills — acceptable at 76 km dot spacing, glaring once courses are continuous). Depends on wave 1''s carrier (river_class on RiverNetwork) landing first.
|
||
|
||
T-1156 review forward-note (Tyre, PR #195 Q1): when this ticket redesigns the binning corner, consider PER-BASIN anchoring as an explicit option — every watershed gets its own trunk regardless of the body''s dominant river (the right eventual model once basins are player-inspectable), at the cost of a second normalization pass and a cross-basin legibility decision at Region scale (several equal-weight ''trunks'' of wildly different magnitude undersell the dominant drainage). The wave-1 global-per-body anchor is correct for ''show the main river system at a glance''. Single revisit points: classify_river_cell (server) and RIVER_CLASS_VISIBLE_BY_RUNG (client).
|
||
|
||
T-1172 retirement dependency (Tyre''s clip ruling): when this ticket''s course invention terminates courses at the invented coast with continuous geometry, RETIRE the T-1172 draw-time water clip in the same change (marker comment at the clip site in atlas_window_nature_overlay.gd) — suppressed offshore mouths return with real coast-terminus geometry here. Also: the clip''s strict-drop behavior at Region 205km cells (accepted amputation of final coastal dots) is superseded by real course termini.', NULL, '2026-07-23 08:16:58', '2026-07-23 08:16:58.392', '2026-07-23 08:16:58.392', NULL, '030830007916704b01876509cd9ca935', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRW2ABEG6HQHVKQ9F7NQ1K8R', 'status', 'in_progress', 'review', NULL, '2026-07-23 09:42:13', '2026-07-23 09:42:13.597', '2026-07-23 09:42:13.597', NULL, '2a77ca9ca37d0488b84238555336a4a4', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRW2ABEG6HQHVKQ9F7NQ1K8R', 'status', 'review', 'done', NULL, '2026-07-23 09:52:33', '2026-07-23 09:52:33.559', '2026-07-23 09:52:33.559', NULL, 'a7d971731b6f0ebded33ff1c43236d60', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRV2GT1FQVATWX641KY9K66C', 'description', 'Named experience gap from T-1156 wave 1 (Si audit + lead, 2026-07-23): the D8 river skeleton lives at heightmap working-grid resolution (512x256 — ~76.6 km per river cell on Lendel). Wave 1''s per-rung class filtering makes planetary/Region river courses real, but at District (2 km cells, ~65 km window) and Quarter the geometry is SPARSER THAN THE WINDOW — a window typically contains zero or one river cell, so ''tributaries at District, streams at Quarter'' cannot materialize as visible courses from the stored skeleton alone. The fix is the linear-feature analog of T-1162''s coast crinkle: deterministically INVENT river course geometry between/below D8 cells — domain-warped polyline interpolation between adjacent river cells (seeded per body+cell pair, D-227 discipline, elevation-aware so courses prefer invented-terrain valleys where feasible), refining with rung the same way the coast warp refines the coastline. Also the natural home for reconciling rivers with T-1162''s invented relief (a wave-1 known gap: drawn rivers may cross invented hills — acceptable at 76 km dot spacing, glaring once courses are continuous). Depends on wave 1''s carrier (river_class on RiverNetwork) landing first.
|
||
|
||
T-1156 review forward-note (Tyre, PR #195 Q1): when this ticket redesigns the binning corner, consider PER-BASIN anchoring as an explicit option — every watershed gets its own trunk regardless of the body''s dominant river (the right eventual model once basins are player-inspectable), at the cost of a second normalization pass and a cross-basin legibility decision at Region scale (several equal-weight ''trunks'' of wildly different magnitude undersell the dominant drainage). The wave-1 global-per-body anchor is correct for ''show the main river system at a glance''. Single revisit points: classify_river_cell (server) and RIVER_CLASS_VISIBLE_BY_RUNG (client).
|
||
|
||
T-1172 retirement dependency (Tyre''s clip ruling): when this ticket''s course invention terminates courses at the invented coast with continuous geometry, RETIRE the T-1172 draw-time water clip in the same change (marker comment at the clip site in atlas_window_nature_overlay.gd) — suppressed offshore mouths return with real coast-terminus geometry here. Also: the clip''s strict-drop behavior at Region 205km cells (accepted amputation of final coastal dots) is superseded by real course termini.', 'Named experience gap from T-1156 wave 1 (Si audit + lead, 2026-07-23): the D8 river skeleton lives at heightmap working-grid resolution (512x256 — ~76.6 km per river cell on Lendel). Wave 1''s per-rung class filtering makes planetary/Region river courses real, but at District (2 km cells, ~65 km window) and Quarter the geometry is SPARSER THAN THE WINDOW — a window typically contains zero or one river cell, so ''tributaries at District, streams at Quarter'' cannot materialize as visible courses from the stored skeleton alone. The fix is the linear-feature analog of T-1162''s coast crinkle: deterministically INVENT river course geometry between/below D8 cells — domain-warped polyline interpolation between adjacent river cells (seeded per body+cell pair, D-227 discipline, elevation-aware so courses prefer invented-terrain valleys where feasible), refining with rung the same way the coast warp refines the coastline. Also the natural home for reconciling rivers with T-1162''s invented relief (a wave-1 known gap: drawn rivers may cross invented hills — acceptable at 76 km dot spacing, glaring once courses are continuous). Depends on wave 1''s carrier (river_class on RiverNetwork) landing first.
|
||
|
||
T-1156 review forward-note (Tyre, PR #195 Q1): when this ticket redesigns the binning corner, consider PER-BASIN anchoring as an explicit option — every watershed gets its own trunk regardless of the body''s dominant river (the right eventual model once basins are player-inspectable), at the cost of a second normalization pass and a cross-basin legibility decision at Region scale (several equal-weight ''trunks'' of wildly different magnitude undersell the dominant drainage). The wave-1 global-per-body anchor is correct for ''show the main river system at a glance''. Single revisit points: classify_river_cell (server) and RIVER_CLASS_VISIBLE_BY_RUNG (client).
|
||
|
||
T-1172 retirement dependency (Tyre''s clip ruling): when this ticket''s course invention terminates courses at the invented coast with continuous geometry, RETIRE the T-1172 draw-time water clip in the same change (marker comment at the clip site in atlas_window_nature_overlay.gd) — suppressed offshore mouths return with real coast-terminus geometry here. Also: the clip''s strict-drop behavior at Region 205km cells (accepted amputation of final coastal dots) is superseded by real course termini.
|
||
|
||
Mouth semantics follow-up (Jeroen''s capture question, 2026-07-23): two mouth-placement oddities to resolve when courses/termini become real geometry here — (1) inland-reading mouths: the raw-coast mouth cell can sit landward of the drawn coastline (the mirror of T-1172''s offshore case; not clipped since it''s on drawn land) — mouths should move to the course''s actual invented-coast terminus; (2) pole-edge drains: drainage.rs counts rivers draining off the grid''s top/bottom edge as ''mouths'', rendering double-rings in polar ice with no sea adjacent — revisit whether these render as mouths at all (probably not; they are grid artifacts, not river-meets-sea events).', NULL, '2026-07-23 10:14:21', '2026-07-23 10:14:21.616', '2026-07-23 10:14:21.616', NULL, 'c7763d4d559c04562995b482fbc99e86', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRV2GT1FQVATWX641KY9K66C', 'status', 'backlog', 'in_progress', NULL, '2026-07-23 10:16:37', '2026-07-23 10:16:37.345', '2026-07-23 10:16:37.345', NULL, '00600e9065760bae47f0e410dfaa155f', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRV224PD3NMWKR1AAC0J0D58', 'status', 'backlog', 'in_progress', NULL, '2026-07-23 10:16:37', '2026-07-23 10:16:37.347', '2026-07-23 10:16:37.347', NULL, '6459dedd47ca4ca7384c9aaf0e934ea1', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRXKFEJMDEPQ0PZ5Q862DHKG', 'description', 'Jeroen, 2026-07-23, reviewing the T-1170 course captures: ''there are a bunch of graphical cleanups I would want to suggest around line thickness and tapering off to a point at the source to make the map read more fluent, but I feel map polish like that is better off as a single large pass later.'' This ticket is that pass''s collector — park presentation refinements here rather than folding them into feature batches. Seeded items: (1) river line thickness tuning across rungs (beyond the functional per-class defaults Araminta confirmed in T-1170); (2) SOURCE TAPERING — courses should taper to a point at their upstream source rather than starting at full class width (the classic cartographic river grammar; likely per-vertex width via Polygon2D strip or per-segment width ramp, since draw_polyline is single-width); (3) candidates declined-as-scope during T-1170 review: class-tinted color ramp (Araminta: width+opacity sufficient for now, hue is solvable-later). Accumulate further items via pql ticket append as they come up in captures/reviews. Scope discipline: correctness issues (ruled values not rendering, clip bugs) are NEVER parked here — they get fixed in their own batches; this pass is aesthetics only. Schedule: after the nature layer stands (post T-1156 wave 2 at the earliest), as one coherent Araminta-led pass.', 'Jeroen, 2026-07-23, reviewing the T-1170 course captures: ''there are a bunch of graphical cleanups I would want to suggest around line thickness and tapering off to a point at the source to make the map read more fluent, but I feel map polish like that is better off as a single large pass later.'' This ticket is that pass''s collector — park presentation refinements here rather than folding them into feature batches. Seeded items: (1) river line thickness tuning across rungs (beyond the functional per-class defaults Araminta confirmed in T-1170); (2) SOURCE TAPERING — courses should taper to a point at their upstream source rather than starting at full class width (the classic cartographic river grammar; likely per-vertex width via Polygon2D strip or per-segment width ramp, since draw_polyline is single-width); (3) candidates declined-as-scope during T-1170 review: class-tinted color ramp (Araminta: width+opacity sufficient for now, hue is solvable-later). Accumulate further items via pql ticket append as they come up in captures/reviews. Scope discipline: correctness issues (ruled values not rendering, clip bugs) are NEVER parked here — they get fixed in their own batches; this pass is aesthetics only. Schedule: after the nature layer stands (post T-1156 wave 2 at the earliest), as one coherent Araminta-led pass.
|
||
|
||
REFERENCE (Jeroen, 2026-07-23): RimWorld''s world map as the fluency benchmark — ''the rimworld maps do roads, rivers, coasts and biomes quite well'' (hex substrate explicitly NOT us; the techniques transfer, the tiling doesn''t). Extracted techniques for this pass: (1) RIVERS AS NETWORKS — visible tributary-joins-trunk convergence, subtle width variation along the run, taper-to-source (his earlier item 2), thin/consistent/restrained overall; (2) ROADS VS RIVERS disambiguated by COLOR + STRAIGHTNESS (grey chord-like vs blue winding), not width — the wave-2 road-rendering rule; (3) COASTS as a shoreline GRADIENT — beach/transition band + subtle near-shore water shading (our coastal/transition morphology class already exists; presentation only); (4) BIOME/RELIEF TEXTURE — stipple/texture density carrying hills/mountains/forest on top of hue; strong fit for us since T-1162''s vegetation-patchiness and relief fields can DRIVE stipple density (texture as data, not decoration); (5) geographic LABELS do heavy fluency lifting — that half lives in T-1169, coordinate the passes. Screenshot reference in the session record 2026-07-23.', NULL, '2026-07-23 11:51:22', '2026-07-23 11:51:22.672', '2026-07-23 11:51:22.672', NULL, 'ab3cb347c7e35cf45ce867a5ead8fe61', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRXKFEJMDEPQ0PZ5Q862DHKG', 'description', 'Jeroen, 2026-07-23, reviewing the T-1170 course captures: ''there are a bunch of graphical cleanups I would want to suggest around line thickness and tapering off to a point at the source to make the map read more fluent, but I feel map polish like that is better off as a single large pass later.'' This ticket is that pass''s collector — park presentation refinements here rather than folding them into feature batches. Seeded items: (1) river line thickness tuning across rungs (beyond the functional per-class defaults Araminta confirmed in T-1170); (2) SOURCE TAPERING — courses should taper to a point at their upstream source rather than starting at full class width (the classic cartographic river grammar; likely per-vertex width via Polygon2D strip or per-segment width ramp, since draw_polyline is single-width); (3) candidates declined-as-scope during T-1170 review: class-tinted color ramp (Araminta: width+opacity sufficient for now, hue is solvable-later). Accumulate further items via pql ticket append as they come up in captures/reviews. Scope discipline: correctness issues (ruled values not rendering, clip bugs) are NEVER parked here — they get fixed in their own batches; this pass is aesthetics only. Schedule: after the nature layer stands (post T-1156 wave 2 at the earliest), as one coherent Araminta-led pass.
|
||
|
||
REFERENCE (Jeroen, 2026-07-23): RimWorld''s world map as the fluency benchmark — ''the rimworld maps do roads, rivers, coasts and biomes quite well'' (hex substrate explicitly NOT us; the techniques transfer, the tiling doesn''t). Extracted techniques for this pass: (1) RIVERS AS NETWORKS — visible tributary-joins-trunk convergence, subtle width variation along the run, taper-to-source (his earlier item 2), thin/consistent/restrained overall; (2) ROADS VS RIVERS disambiguated by COLOR + STRAIGHTNESS (grey chord-like vs blue winding), not width — the wave-2 road-rendering rule; (3) COASTS as a shoreline GRADIENT — beach/transition band + subtle near-shore water shading (our coastal/transition morphology class already exists; presentation only); (4) BIOME/RELIEF TEXTURE — stipple/texture density carrying hills/mountains/forest on top of hue; strong fit for us since T-1162''s vegetation-patchiness and relief fields can DRIVE stipple density (texture as data, not decoration); (5) geographic LABELS do heavy fluency lifting — that half lives in T-1169, coordinate the passes. Screenshot reference in the session record 2026-07-23.', 'Jeroen, 2026-07-23, reviewing the T-1170 course captures: ''there are a bunch of graphical cleanups I would want to suggest around line thickness and tapering off to a point at the source to make the map read more fluent, but I feel map polish like that is better off as a single large pass later.'' This ticket is that pass''s collector — park presentation refinements here rather than folding them into feature batches. Seeded items: (1) river line thickness tuning across rungs (beyond the functional per-class defaults Araminta confirmed in T-1170); (2) SOURCE TAPERING — courses should taper to a point at their upstream source rather than starting at full class width (the classic cartographic river grammar; likely per-vertex width via Polygon2D strip or per-segment width ramp, since draw_polyline is single-width); (3) candidates declined-as-scope during T-1170 review: class-tinted color ramp (Araminta: width+opacity sufficient for now, hue is solvable-later). Accumulate further items via pql ticket append as they come up in captures/reviews. Scope discipline: correctness issues (ruled values not rendering, clip bugs) are NEVER parked here — they get fixed in their own batches; this pass is aesthetics only. Schedule: after the nature layer stands (post T-1156 wave 2 at the earliest), as one coherent Araminta-led pass.
|
||
|
||
REFERENCE (Jeroen, 2026-07-23): RimWorld''s world map as the fluency benchmark — ''the rimworld maps do roads, rivers, coasts and biomes quite well'' (hex substrate explicitly NOT us; the techniques transfer, the tiling doesn''t). Extracted techniques for this pass: (1) RIVERS AS NETWORKS — visible tributary-joins-trunk convergence, subtle width variation along the run, taper-to-source (his earlier item 2), thin/consistent/restrained overall; (2) ROADS VS RIVERS disambiguated by COLOR + STRAIGHTNESS (grey chord-like vs blue winding), not width — the wave-2 road-rendering rule; (3) COASTS as a shoreline GRADIENT — beach/transition band + subtle near-shore water shading (our coastal/transition morphology class already exists; presentation only); (4) BIOME/RELIEF TEXTURE — stipple/texture density carrying hills/mountains/forest on top of hue; strong fit for us since T-1162''s vegetation-patchiness and relief fields can DRIVE stipple density (texture as data, not decoration); (5) geographic LABELS do heavy fluency lifting — that half lives in T-1169, coordinate the passes. Screenshot reference in the session record 2026-07-23.
|
||
|
||
Reference screenshot saved in-repo: docs/design/references/rimworld-world-map-fluency.jpg (+ README note in that dir) — supersedes the ''session record'' pointer in the previous append.', NULL, '2026-07-23 11:54:02', '2026-07-23 11:54:02.271', '2026-07-23 11:54:02.271', NULL, 'e71da503fceba44369e5f8d340b4be06', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRV2GT1FQVATWX641KY9K66C', 'status', 'in_progress', 'review', NULL, '2026-07-23 12:17:43', '2026-07-23 12:17:43.879', '2026-07-23 12:17:43.879', NULL, '3d138bba01b1a29a446bb1e6bbc29471', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRV224PD3NMWKR1AAC0J0D58', 'status', 'in_progress', 'review', NULL, '2026-07-23 12:17:43', '2026-07-23 12:17:43.882', '2026-07-23 12:17:43.882', NULL, 'af2b75b65c86ae0a671896913511ccd1', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRV2GT1FQVATWX641KY9K66C', 'status', 'review', 'done', NULL, '2026-07-23 14:10:16', '2026-07-23 14:10:16.116', '2026-07-23 14:10:16.116', NULL, 'ce544d9b754a1d453011ea7c7d2bbec0', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRV224PD3NMWKR1AAC0J0D58', 'status', 'review', 'done', NULL, '2026-07-23 14:10:16', '2026-07-23 14:10:16.118', '2026-07-23 14:10:16.118', NULL, '36ba42d3ba653a87d39335d2e55591c6', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRY9W24PV55Z6FMW8TEM7XER', 'status', 'backlog', 'in_progress', NULL, '2026-07-23 16:26:46', '2026-07-23 16:26:46.891', '2026-07-23 16:26:46.891', NULL, 'db18073562f0b55539223e544f912186', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRY9W24PV55Z6FMW8TEM7XER', 'description', 'Jeroen, 2026-07-23, during the T-1170 live rounds: ''I want to discuss and maybe revise the pixel scan/output mechanism for drawing the map. I feel we can be smarter about this and bypass an entire class of errors we are seeing as well as probably improve performance.'' DISCUSSION FIRST — this is a design conversation with Jeroen (pair/workshop mode), not autonomous work; scheduled after the T-1170/T-1168 cycle closes. The error class in evidence, all descending from immediate-mode draw calls inside a zoom-scaled canvas (_canvas.scale = view_zoom): the per-call-site zoom compensation discipline (_zs/_zs_stroke, silently degrading when one site is missed — PR #195 I1, PR #197 stroke sites), Godot''s line-rasterizer width floor (sub-1.0-canvas-unit strokes collapse to hairline — the T-1170 width bug), the radius-smaller-than-stroke draw_arc regime (the mouth-ring investigation), and arguably the wrap-image resolution family. Candidate directions to bring to the discussion: (a) Tyre''s unscaled screen-space sibling layer (positions transformed, sizes literal — already noted on T-1156 wave 2/T-1158); (b) render-to-texture per window/tile at native resolution, composited as textures (sizes become texel-exact, zoom becomes pure texture transform); (c) shader-side composition of the per-cell data (morphology/courses as data textures, coloring+features in fragment shader — likely the performance win); (d) hybrid. Inputs to gather before the discussion: current draw-call counts/frame costs per rung, the T-1175 polish requirements (per-vertex tapering wants Polygon2D strips or shaders anyway), and the wave-2 marker volume. Relates: T-1158 (viewer decomposition), T-1175 (polish pass), Tyre''s PR #197 Q5 note.', 'Jeroen, 2026-07-23, during the T-1170 live rounds: ''I want to discuss and maybe revise the pixel scan/output mechanism for drawing the map. I feel we can be smarter about this and bypass an entire class of errors we are seeing as well as probably improve performance.'' DISCUSSION FIRST — this is a design conversation with Jeroen (pair/workshop mode), not autonomous work; scheduled after the T-1170/T-1168 cycle closes. The error class in evidence, all descending from immediate-mode draw calls inside a zoom-scaled canvas (_canvas.scale = view_zoom): the per-call-site zoom compensation discipline (_zs/_zs_stroke, silently degrading when one site is missed — PR #195 I1, PR #197 stroke sites), Godot''s line-rasterizer width floor (sub-1.0-canvas-unit strokes collapse to hairline — the T-1170 width bug), the radius-smaller-than-stroke draw_arc regime (the mouth-ring investigation), and arguably the wrap-image resolution family. Candidate directions to bring to the discussion: (a) Tyre''s unscaled screen-space sibling layer (positions transformed, sizes literal — already noted on T-1156 wave 2/T-1158); (b) render-to-texture per window/tile at native resolution, composited as textures (sizes become texel-exact, zoom becomes pure texture transform); (c) shader-side composition of the per-cell data (morphology/courses as data textures, coloring+features in fragment shader — likely the performance win); (d) hybrid. Inputs to gather before the discussion: current draw-call counts/frame costs per rung, the T-1175 polish requirements (per-vertex tapering wants Polygon2D strips or shaders anyway), and the wave-2 marker volume. Relates: T-1158 (viewer decomposition), T-1175 (polish pass), Tyre''s PR #197 Q5 note.
|
||
|
||
PREP SESSION COMPLETE + BRIEF SIGNED OFF (2026-07-25, Jeroen + lead + Tyre). Jeroen''s design outline captured and clarified over two AskUserQuestion rounds; Tyre delivered governance-delta/implications pass and ratified the brief (zero misrepresentations, zero blocking gaps). Signed-off workshop brief: docs/workshops/body-map-viewer/body-map-viewer-workshop-brief.md (session artifacts: jeroen-outline.md, clarifications.md, tyre-implications.md, prep-grounding.md in the same dir). Settled premises: server-side content determination per zoom step; client map-art function; RTT terrain + screen-space vector annotations baseline (locks T-1176 candidates b+a; c1 styling open); GPU presentation-only; stepped zoom (supersedes continuous — recorded at workshop filing); tile=1m only, ''gridunit (at zoom level)'' coined; data resolution tunable (1px ideal, 5x5 fallback); hydrology = deterministic equilibrium; client-primary cache (store shape open: server-side SQLite cache / godot-sqlite / file cache — SQLite ships in the Rust server, NOT the Godot client). Workshop: 5 seats (Dudley/Araminta/Stig/Tyre + Troblum r2), 2 rounds + lead interview, extendable at Jeroen''s call, round 1 GATED on measurements — see blocker edges. Expected Output 2 mandates an explicit deprecation sweep (Clerk audit) of all conflicting DQR records/tickets at filing.', NULL, '2026-07-23 16:26:57', '2026-07-23 16:26:57.202', '2026-07-23 16:26:57.202', NULL, '1e3fa8ea5af24a3e8eafd1433d603f4e', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCF0CX1Y5DTD3ER2JCDT27G', 'description', 'Gate ticket from Jeroen''s floor ruling (2026-07-21, D-226 amendment: ''we set a new BHAG so old restrictions are up for debate'' — the Atlas ladder may descend below quarter toward tile, implementation-gated on THIS pass). Measure what the design pass could not (docs/architecture/atlas-zoom-ladder-t1143.md SS2 marks block/tile ''not estimated''): per-cell derive cost at block (128m) and tile-adjacent spacings with the min_wavelength cutoff active; realistic window cell counts and wire bytes at those granularities vs the SS4 budget; memory/caching behavior; whether voxel_relief/voxel_mosaic math is reusable as-is for Atlas sampling or needs an extraction like derive_at_metres. Output: a costs appendix to the design doc + go/no-go recommendation per rung. Constraint preserved by the ruling: chunk/tile output never appears as a whole-body planetary layer — windowed viewport only. Blocked by derive_at_metres (the cutoff must exist to measure with it).', 'Gate ticket from Jeroen''s floor ruling (2026-07-21, D-226 amendment: ''we set a new BHAG so old restrictions are up for debate'' — the Atlas ladder may descend below quarter toward tile, implementation-gated on THIS pass). Measure what the design pass could not (docs/architecture/atlas-zoom-ladder-t1143.md SS2 marks block/tile ''not estimated''): per-cell derive cost at block (128m) and tile-adjacent spacings with the min_wavelength cutoff active; realistic window cell counts and wire bytes at those granularities vs the SS4 budget; memory/caching behavior; whether voxel_relief/voxel_mosaic math is reusable as-is for Atlas sampling or needs an extraction like derive_at_metres. Output: a costs appendix to the design doc + go/no-go recommendation per rung. Constraint preserved by the ruling: chunk/tile output never appears as a whole-body planetary layer — windowed viewport only. Blocked by derive_at_metres (the cutoff must exist to measure with it).
|
||
|
||
REPURPOSED as body-map-viewer workshop gate measurement ③ (2026-07-25, brief appendix ③: docs/workshops/body-map-viewer/body-map-viewer-workshop-brief.md). Unblocked since T-1162 shipped the octave-cutoff plumbing this was blocked on. Scope unchanged (block/tile rung per-cell costs + wire at those granularities); its numbers now price the bottom of the stepped gridunit ladder (~10px per 1m tile bottom-out). Round 1 of the workshop is gated on this landing alongside T-1177/T-1178/T-1179.', NULL, '2026-07-23 16:27:35', '2026-07-23 16:27:35.477', '2026-07-23 16:27:35.477', NULL, '2b58b58df3a9b9baccf6703ae0062aac', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCF0CX1Y5DTD3ER2JCDT27G', 'status', 'backlog', 'ready', NULL, '2026-07-23 16:27:39', '2026-07-23 16:27:39.311', '2026-07-23 16:27:39.311', NULL, 'd1b13c21562034e52caafe97a8ad2ab2', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRZKBTD7VKSXNWADWHV3QDQ8', 'status', 'backlog', 'ready', NULL, '2026-07-23 16:27:39', '2026-07-23 16:27:39.318', '2026-07-23 16:27:39.318', NULL, '7076af166f03bdabaed9d1981203672a', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRZKAV6ZK4KAZ6YCGFNBQ4T0', 'status', 'backlog', 'ready', NULL, '2026-07-23 16:27:39', '2026-07-23 16:27:39.318', '2026-07-23 16:27:39.318', NULL, 'e9ed3f756f2703b64399eecbe1e3b210', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRZKDFB23YFACY2G4M6WRSXC', 'status', 'backlog', 'ready', NULL, '2026-07-23 16:27:39', '2026-07-23 16:27:39.319', '2026-07-23 16:27:39.319', NULL, '03b325b1daa7dfd7b7b10199a78dcc87', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRZKCN13EF5TD9EZTXMSJ7EG', 'status', 'backlog', 'ready', NULL, '2026-07-23 16:27:39', '2026-07-23 16:27:39.319', '2026-07-23 16:27:39.319', NULL, 'e864c7885306075f0c00700043ba9615', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRZKAV6ZK4KAZ6YCGFNBQ4T0', 'status', 'ready', 'in_progress', NULL, '2026-07-23 16:31:37', '2026-07-23 16:31:37.581', '2026-07-23 16:31:37.581', NULL, '29b5deb71fcc65f341804be11dc1a0ce', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCF0CX1Y5DTD3ER2JCDT27G', 'status', 'ready', 'in_progress', NULL, '2026-07-23 16:31:37', '2026-07-23 16:31:37.588', '2026-07-23 16:31:37.588', NULL, '194a5fd121a3a3615f8daa7f566cff5c', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRZKCN13EF5TD9EZTXMSJ7EG', 'status', 'ready', 'in_progress', NULL, '2026-07-23 16:31:37', '2026-07-23 16:31:37.588', '2026-07-23 16:31:37.588', NULL, '74c95e46254d1b4e556114373955ce3f', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRZKBTD7VKSXNWADWHV3QDQ8', 'status', 'ready', 'in_progress', NULL, '2026-07-23 16:31:37', '2026-07-23 16:31:37.588', '2026-07-23 16:31:37.588', NULL, 'be43c8468b1f8b982f29bd8f86131d60', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRZKDFB23YFACY2G4M6WRSXC', 'status', 'ready', 'in_progress', NULL, '2026-07-23 16:31:37', '2026-07-23 16:31:37.589', '2026-07-23 16:31:37.589', NULL, '780d0a11c4150daecb3b2ccf9c5263fa', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRZKAV6ZK4KAZ6YCGFNBQ4T0', 'status', 'in_progress', 'review', NULL, '2026-07-23 17:28:10', '2026-07-23 17:28:10.723', '2026-07-23 17:28:10.723', NULL, 'ac94abc9cb74e2aad992d6db501186e6', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRZKBTD7VKSXNWADWHV3QDQ8', 'status', 'in_progress', 'review', NULL, '2026-07-23 17:28:10', '2026-07-23 17:28:10.725', '2026-07-23 17:28:10.725', NULL, 'aaa25832f40b1128b95eca8c645905c6', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCF0CX1Y5DTD3ER2JCDT27G', 'status', 'in_progress', 'review', NULL, '2026-07-23 17:28:10', '2026-07-23 17:28:10.725', '2026-07-23 17:28:10.725', NULL, 'e922419468e1ce927a31a4c44c02c97e', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRZKCN13EF5TD9EZTXMSJ7EG', 'status', 'in_progress', 'review', NULL, '2026-07-23 17:28:10', '2026-07-23 17:28:10.726', '2026-07-23 17:28:10.726', NULL, 'c69971d04aa8e133f36c2d49ab08976d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRZKDFB23YFACY2G4M6WRSXC', 'status', 'in_progress', 'review', NULL, '2026-07-23 17:28:10', '2026-07-23 17:28:10.726', '2026-07-23 17:28:10.726', NULL, 'f4db07b59ed9e0aa398948c23433b870', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRZKAV6ZK4KAZ6YCGFNBQ4T0', 'status', 'review', 'done', NULL, '2026-07-23 18:06:12', '2026-07-23 18:06:12.143', '2026-07-23 18:06:12.143', NULL, '7ce2aa2053d1cd118391e50669ac6c53', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRZKBTD7VKSXNWADWHV3QDQ8', 'status', 'review', 'done', NULL, '2026-07-23 18:06:12', '2026-07-23 18:06:12.145', '2026-07-23 18:06:12.145', NULL, '37189119cf3dffcc4fd582e0f791da40', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRCF0CX1Y5DTD3ER2JCDT27G', 'status', 'review', 'done', NULL, '2026-07-23 18:06:12', '2026-07-23 18:06:12.146', '2026-07-23 18:06:12.146', NULL, 'b2f9dd6df75e6fc00da53a9d85582167', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRZKCN13EF5TD9EZTXMSJ7EG', 'status', 'review', 'done', NULL, '2026-07-23 18:06:12', '2026-07-23 18:06:12.147', '2026-07-23 18:06:12.147', NULL, '03911a8b5220fca15a57cac632fdeeea', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRZKDFB23YFACY2G4M6WRSXC', 'status', 'review', 'done', NULL, '2026-07-23 18:06:12', '2026-07-23 18:06:12.147', '2026-07-23 18:06:12.147', NULL, '9356438925d73d203f8201d9eebfbd09', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRXGSXBZKXTHR7MR5K9H2HRG', 'description', 'Pre-existing architectural quirk found by Dudley during T-1168 integration testing (2026-07-23, not introduced by that batch): derive_district_profile''s cell-aggregate-centre sampling and the window path''s district-origin sampling resolve to genuinely different world positions for ''the same DistrictPos'' — full DistrictProfile output legitimately differs between paths (morphology/elev/moisture) at the same nominal district. His integration test was redesigned to compare the riparian signal at a shared exact world position instead (the right test). Investigate whether any existing batch/window consumer pair assumes positional agreement (city placement vs window rendering?), decide the canonical sampling convention, and either unify or document the divergence as intentional with the reasoning.', 'Pre-existing architectural quirk found by Dudley during T-1168 integration testing (2026-07-23, not introduced by that batch): derive_district_profile''s cell-aggregate-centre sampling and the window path''s district-origin sampling resolve to genuinely different world positions for ''the same DistrictPos'' — full DistrictProfile output legitimately differs between paths (morphology/elev/moisture) at the same nominal district. His integration test was redesigned to compare the riparian signal at a shared exact world position instead (the right test). Investigate whether any existing batch/window consumer pair assumes positional agreement (city placement vs window rendering?), decide the canonical sampling convention, and either unify or document the divergence as intentional with the reasoning.
|
||
|
||
D-255 (2026-07-24): the tagged-envelope step-canvas serving (T-1181) depends on batch and window derive agreeing cell-for-cell — this bug now also blocks the step-canvas serving path, and priority is raised accordingly (Tyre disposition, body-map-viewer workshop). No supersession; intent unchanged.', NULL, '2026-07-24 07:12:48', '2026-07-24 07:12:48.893', '2026-07-24 07:12:48.893', NULL, '00522c2052d6e2ef32fc4d363ac60981', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRXKFEJMDEPQ0PZ5Q862DHKG', 'description', 'Jeroen, 2026-07-23, reviewing the T-1170 course captures: ''there are a bunch of graphical cleanups I would want to suggest around line thickness and tapering off to a point at the source to make the map read more fluent, but I feel map polish like that is better off as a single large pass later.'' This ticket is that pass''s collector — park presentation refinements here rather than folding them into feature batches. Seeded items: (1) river line thickness tuning across rungs (beyond the functional per-class defaults Araminta confirmed in T-1170); (2) SOURCE TAPERING — courses should taper to a point at their upstream source rather than starting at full class width (the classic cartographic river grammar; likely per-vertex width via Polygon2D strip or per-segment width ramp, since draw_polyline is single-width); (3) candidates declined-as-scope during T-1170 review: class-tinted color ramp (Araminta: width+opacity sufficient for now, hue is solvable-later). Accumulate further items via pql ticket append as they come up in captures/reviews. Scope discipline: correctness issues (ruled values not rendering, clip bugs) are NEVER parked here — they get fixed in their own batches; this pass is aesthetics only. Schedule: after the nature layer stands (post T-1156 wave 2 at the earliest), as one coherent Araminta-led pass.
|
||
|
||
REFERENCE (Jeroen, 2026-07-23): RimWorld''s world map as the fluency benchmark — ''the rimworld maps do roads, rivers, coasts and biomes quite well'' (hex substrate explicitly NOT us; the techniques transfer, the tiling doesn''t). Extracted techniques for this pass: (1) RIVERS AS NETWORKS — visible tributary-joins-trunk convergence, subtle width variation along the run, taper-to-source (his earlier item 2), thin/consistent/restrained overall; (2) ROADS VS RIVERS disambiguated by COLOR + STRAIGHTNESS (grey chord-like vs blue winding), not width — the wave-2 road-rendering rule; (3) COASTS as a shoreline GRADIENT — beach/transition band + subtle near-shore water shading (our coastal/transition morphology class already exists; presentation only); (4) BIOME/RELIEF TEXTURE — stipple/texture density carrying hills/mountains/forest on top of hue; strong fit for us since T-1162''s vegetation-patchiness and relief fields can DRIVE stipple density (texture as data, not decoration); (5) geographic LABELS do heavy fluency lifting — that half lives in T-1169, coordinate the passes. Screenshot reference in the session record 2026-07-23.
|
||
|
||
Reference screenshot saved in-repo: docs/design/references/rimworld-world-map-fluency.jpg (+ README note in that dir) — supersedes the ''session record'' pointer in the previous append.', 'Jeroen, 2026-07-23, reviewing the T-1170 course captures: ''there are a bunch of graphical cleanups I would want to suggest around line thickness and tapering off to a point at the source to make the map read more fluent, but I feel map polish like that is better off as a single large pass later.'' This ticket is that pass''s collector — park presentation refinements here rather than folding them into feature batches. Seeded items: (1) river line thickness tuning across rungs (beyond the functional per-class defaults Araminta confirmed in T-1170); (2) SOURCE TAPERING — courses should taper to a point at their upstream source rather than starting at full class width (the classic cartographic river grammar; likely per-vertex width via Polygon2D strip or per-segment width ramp, since draw_polyline is single-width); (3) candidates declined-as-scope during T-1170 review: class-tinted color ramp (Araminta: width+opacity sufficient for now, hue is solvable-later). Accumulate further items via pql ticket append as they come up in captures/reviews. Scope discipline: correctness issues (ruled values not rendering, clip bugs) are NEVER parked here — they get fixed in their own batches; this pass is aesthetics only. Schedule: after the nature layer stands (post T-1156 wave 2 at the earliest), as one coherent Araminta-led pass.
|
||
|
||
REFERENCE (Jeroen, 2026-07-23): RimWorld''s world map as the fluency benchmark — ''the rimworld maps do roads, rivers, coasts and biomes quite well'' (hex substrate explicitly NOT us; the techniques transfer, the tiling doesn''t). Extracted techniques for this pass: (1) RIVERS AS NETWORKS — visible tributary-joins-trunk convergence, subtle width variation along the run, taper-to-source (his earlier item 2), thin/consistent/restrained overall; (2) ROADS VS RIVERS disambiguated by COLOR + STRAIGHTNESS (grey chord-like vs blue winding), not width — the wave-2 road-rendering rule; (3) COASTS as a shoreline GRADIENT — beach/transition band + subtle near-shore water shading (our coastal/transition morphology class already exists; presentation only); (4) BIOME/RELIEF TEXTURE — stipple/texture density carrying hills/mountains/forest on top of hue; strong fit for us since T-1162''s vegetation-patchiness and relief fields can DRIVE stipple density (texture as data, not decoration); (5) geographic LABELS do heavy fluency lifting — that half lives in T-1169, coordinate the passes. Screenshot reference in the session record 2026-07-23.
|
||
|
||
Reference screenshot saved in-repo: docs/design/references/rimworld-world-map-fluency.jpg (+ README note in that dir) — supersedes the ''session record'' pointer in the previous append.
|
||
|
||
RE-SCOPED by D-255 (2026-07-24, body-map-viewer workshop): the per-vertex river tapering/width-grammar work lands on the NEW screen-space annotation layer (T-1182) via Polygon2D strips — draw_polyline cannot taper. The c1 styling-engine blocker is DISCHARGED: measurement ⑥ landed (Image.set_pixel 77.5 ns/cell flat) and the call resolved CPU-first; shaders deferred, not a precondition. This ticket now depends only on the annotation layer landing (blocked-by T-1182, edge added). Not cancelled — re-homed onto the new component, unblocked otherwise.', NULL, '2026-07-24 07:12:51', '2026-07-24 07:12:51.866', '2026-07-24 07:12:51.866', NULL, 'b6d9c3f3d348683b2d1bb07ddd075189', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRXGSXBZKXTHR7MR5K9H2HRG', 'priority', 'low', 'high', NULL, '2026-07-24 07:13:02', '2026-07-24 07:13:02.546', '2026-07-24 07:13:02.546', NULL, '573adb2f20e62cdd046ce932ecb561dd', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRJD6EKPBQE08NA8VHP692W8', 'description', 'T-1153 broke the T-1120/T-1121 golden capture harness: client/tests/visual_scenarios.gd and visual_capture.gd call app._regional_screen._viewer.get_heightmap_texture()/show_body() — both crash against AtlasWindowViewer (regional_screen now wraps the ladder viewer; AtlasViewer is unreachable from nav). Confirmed NOT wired into tests/run-godot or the pre-push hook (no reference in either), so nothing blocks, but the 12 curated atlas_* goldens and the --atlas-matrix capture path are dead until redesigned for the ladder (capture at defined rungs/zooms instead of the fixed heightmap frame; the new canonical orbital frame is the natural replacement for the old whole-body shot). Also decide the fate of the retired AtlasViewer code these harnesses were the last live consumers of — likely deletable once T-1156 (overlay port) settles what carries forward.
|
||
|
||
Live round 4 addendum: client/tests/test_atlas_window_overlay_draw_smoke.gd (3 scenarios -> now 2 after removing a flaky harness-sanity check: single-window draw + tile-mosaic draw, both asserting real composited pixels via SubViewport render) is a standalone gdUnit file with its own headless-skip guard, added because this redesign hadn''t landed yet. When this ticket lands, migrate its 2 scenarios into the redesigned tests/visual.json harness (folding the standalone file away) for consistency with the rest of the real-rendering test suite — see docs/DEVOPS.md''s ''Real-rendering test exception'' note for the interim rationale.', 'T-1153 broke the T-1120/T-1121 golden capture harness: client/tests/visual_scenarios.gd and visual_capture.gd call app._regional_screen._viewer.get_heightmap_texture()/show_body() — both crash against AtlasWindowViewer (regional_screen now wraps the ladder viewer; AtlasViewer is unreachable from nav). Confirmed NOT wired into tests/run-godot or the pre-push hook (no reference in either), so nothing blocks, but the 12 curated atlas_* goldens and the --atlas-matrix capture path are dead until redesigned for the ladder (capture at defined rungs/zooms instead of the fixed heightmap frame; the new canonical orbital frame is the natural replacement for the old whole-body shot). Also decide the fate of the retired AtlasViewer code these harnesses were the last live consumers of — likely deletable once T-1156 (overlay port) settles what carries forward.
|
||
|
||
Live round 4 addendum: client/tests/test_atlas_window_overlay_draw_smoke.gd (3 scenarios -> now 2 after removing a flaky harness-sanity check: single-window draw + tile-mosaic draw, both asserting real composited pixels via SubViewport render) is a standalone gdUnit file with its own headless-skip guard, added because this redesign hadn''t landed yet. When this ticket lands, migrate its 2 scenarios into the redesigned tests/visual.json harness (folding the standalone file away) for consistency with the rest of the real-rendering test suite — see docs/DEVOPS.md''s ''Real-rendering test exception'' note for the interim rationale.
|
||
|
||
RE-SCOPED by D-255 (2026-07-24, body-map-viewer workshop): this becomes the capture harness for the STEPPED render architecture — goldens key on (body, step) canvases, not the retired continuous-zoom frames. The T-1152/T-1153 test suites (coverage-walk, continuous-zoom seams, compute_tile_grid mosaic) retire with their code in T-1182''s change; this re-scoped harness is their replacement and the eyeball-check substrate for every step canvas. More needed than ever — keep, don''t cancel.', NULL, '2026-07-24 07:13:05', '2026-07-24 07:13:05.192', '2026-07-24 07:13:05.192', NULL, 'bedc693c890c890566674646daebd3f7', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRMPSM9GSWK586N5GBP2N22G', 'description', 'PR #192 review (Tyre): the viewer sits at exactly gdlint''s 1000-line cap, twice trimmed to fit, and fuses three separable responsibilities: (a) input handling (_gui_input/_process/_apply_pan_delta/edge-scroll), (b) request orchestration + rung reselection (_maybe_reselect_rung/_maybe_refloat_window), (c) the canonical-frame state machine (_zoom_at zoom floor/_is_at_canonical_frame/_maybe_reset_to_canonical_frame/_canonical_fit_zoom). All six live fix rounds of the T-1152/T-1153 batch traced to held-state/transform/lifetime coupling in this file — extract cluster (c) (+ likely (b)) into its own class BEFORE the next change breaches the cap and forces either a deadline extraction or comment-gutting that loses the hard-won live-round rationale comments. The tile-set (atlas_window_tile_set.gd) and geometry (atlas_window_geometry.gd) extractions are the precedent. Behavior-preserving refactor: the zoom-ladder suites (44+122+20 tests) are the safety net.', 'PR #192 review (Tyre): the viewer sits at exactly gdlint''s 1000-line cap, twice trimmed to fit, and fuses three separable responsibilities: (a) input handling (_gui_input/_process/_apply_pan_delta/edge-scroll), (b) request orchestration + rung reselection (_maybe_reselect_rung/_maybe_refloat_window), (c) the canonical-frame state machine (_zoom_at zoom floor/_is_at_canonical_frame/_maybe_reset_to_canonical_frame/_canonical_fit_zoom). All six live fix rounds of the T-1152/T-1153 batch traced to held-state/transform/lifetime coupling in this file — extract cluster (c) (+ likely (b)) into its own class BEFORE the next change breaches the cap and forces either a deadline extraction or comment-gutting that loses the hard-won live-round rationale comments. The tile-set (atlas_window_tile_set.gd) and geometry (atlas_window_geometry.gd) extractions are the precedent. Behavior-preserving refactor: the zoom-ladder suites (44+122+20 tests) are the safety net.
|
||
|
||
SUPERSEDED by the body-map-viewer render architecture (D-255, 2026-07-24): the canonical-frame + rung-reselection state machine this ticket would extract is exactly what changes shape under stepped zoom (no continuous zoom floor, no _canonical_fit_zoom, select_rung retired). Extracting code about to be deleted is waste (Stig''s round-1 call, confirmed by the workshop). The new component''s decomposition (input/pan, step-cross orchestration, two draw layers) is decided fresh in T-1182, not by reviving this ticket. Cancelled.', NULL, '2026-07-24 07:13:14', '2026-07-24 07:13:14.172', '2026-07-24 07:13:14.172', NULL, 'f23e0d9981db5d6f939140cc8545d9d0', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRMPSM9GSWK586N5GBP2N22G', 'status', 'backlog', 'cancelled', NULL, '2026-07-24 07:13:18', '2026-07-24 07:13:18.469', '2026-07-24 07:13:18.469', NULL, '71fa27b107e5220c44fe22feda2b5c2a', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRY9W24PV55Z6FMW8TEM7XER', 'description', 'Jeroen, 2026-07-23, during the T-1170 live rounds: ''I want to discuss and maybe revise the pixel scan/output mechanism for drawing the map. I feel we can be smarter about this and bypass an entire class of errors we are seeing as well as probably improve performance.'' DISCUSSION FIRST — this is a design conversation with Jeroen (pair/workshop mode), not autonomous work; scheduled after the T-1170/T-1168 cycle closes. The error class in evidence, all descending from immediate-mode draw calls inside a zoom-scaled canvas (_canvas.scale = view_zoom): the per-call-site zoom compensation discipline (_zs/_zs_stroke, silently degrading when one site is missed — PR #195 I1, PR #197 stroke sites), Godot''s line-rasterizer width floor (sub-1.0-canvas-unit strokes collapse to hairline — the T-1170 width bug), the radius-smaller-than-stroke draw_arc regime (the mouth-ring investigation), and arguably the wrap-image resolution family. Candidate directions to bring to the discussion: (a) Tyre''s unscaled screen-space sibling layer (positions transformed, sizes literal — already noted on T-1156 wave 2/T-1158); (b) render-to-texture per window/tile at native resolution, composited as textures (sizes become texel-exact, zoom becomes pure texture transform); (c) shader-side composition of the per-cell data (morphology/courses as data textures, coloring+features in fragment shader — likely the performance win); (d) hybrid. Inputs to gather before the discussion: current draw-call counts/frame costs per rung, the T-1175 polish requirements (per-vertex tapering wants Polygon2D strips or shaders anyway), and the wave-2 marker volume. Relates: T-1158 (viewer decomposition), T-1175 (polish pass), Tyre''s PR #197 Q5 note.
|
||
|
||
PREP SESSION COMPLETE + BRIEF SIGNED OFF (2026-07-25, Jeroen + lead + Tyre). Jeroen''s design outline captured and clarified over two AskUserQuestion rounds; Tyre delivered governance-delta/implications pass and ratified the brief (zero misrepresentations, zero blocking gaps). Signed-off workshop brief: docs/workshops/body-map-viewer/body-map-viewer-workshop-brief.md (session artifacts: jeroen-outline.md, clarifications.md, tyre-implications.md, prep-grounding.md in the same dir). Settled premises: server-side content determination per zoom step; client map-art function; RTT terrain + screen-space vector annotations baseline (locks T-1176 candidates b+a; c1 styling open); GPU presentation-only; stepped zoom (supersedes continuous — recorded at workshop filing); tile=1m only, ''gridunit (at zoom level)'' coined; data resolution tunable (1px ideal, 5x5 fallback); hydrology = deterministic equilibrium; client-primary cache (store shape open: server-side SQLite cache / godot-sqlite / file cache — SQLite ships in the Rust server, NOT the Godot client). Workshop: 5 seats (Dudley/Araminta/Stig/Tyre + Troblum r2), 2 rounds + lead interview, extendable at Jeroen''s call, round 1 GATED on measurements — see blocker edges. Expected Output 2 mandates an explicit deprecation sweep (Clerk audit) of all conflicting DQR records/tickets at filing.', 'Jeroen, 2026-07-23, during the T-1170 live rounds: ''I want to discuss and maybe revise the pixel scan/output mechanism for drawing the map. I feel we can be smarter about this and bypass an entire class of errors we are seeing as well as probably improve performance.'' DISCUSSION FIRST — this is a design conversation with Jeroen (pair/workshop mode), not autonomous work; scheduled after the T-1170/T-1168 cycle closes. The error class in evidence, all descending from immediate-mode draw calls inside a zoom-scaled canvas (_canvas.scale = view_zoom): the per-call-site zoom compensation discipline (_zs/_zs_stroke, silently degrading when one site is missed — PR #195 I1, PR #197 stroke sites), Godot''s line-rasterizer width floor (sub-1.0-canvas-unit strokes collapse to hairline — the T-1170 width bug), the radius-smaller-than-stroke draw_arc regime (the mouth-ring investigation), and arguably the wrap-image resolution family. Candidate directions to bring to the discussion: (a) Tyre''s unscaled screen-space sibling layer (positions transformed, sizes literal — already noted on T-1156 wave 2/T-1158); (b) render-to-texture per window/tile at native resolution, composited as textures (sizes become texel-exact, zoom becomes pure texture transform); (c) shader-side composition of the per-cell data (morphology/courses as data textures, coloring+features in fragment shader — likely the performance win); (d) hybrid. Inputs to gather before the discussion: current draw-call counts/frame costs per rung, the T-1175 polish requirements (per-vertex tapering wants Polygon2D strips or shaders anyway), and the wave-2 marker volume. Relates: T-1158 (viewer decomposition), T-1175 (polish pass), Tyre''s PR #197 Q5 note.
|
||
|
||
PREP SESSION COMPLETE + BRIEF SIGNED OFF (2026-07-25, Jeroen + lead + Tyre). Jeroen''s design outline captured and clarified over two AskUserQuestion rounds; Tyre delivered governance-delta/implications pass and ratified the brief (zero misrepresentations, zero blocking gaps). Signed-off workshop brief: docs/workshops/body-map-viewer/body-map-viewer-workshop-brief.md (session artifacts: jeroen-outline.md, clarifications.md, tyre-implications.md, prep-grounding.md in the same dir). Settled premises: server-side content determination per zoom step; client map-art function; RTT terrain + screen-space vector annotations baseline (locks T-1176 candidates b+a; c1 styling open); GPU presentation-only; stepped zoom (supersedes continuous — recorded at workshop filing); tile=1m only, ''gridunit (at zoom level)'' coined; data resolution tunable (1px ideal, 5x5 fallback); hydrology = deterministic equilibrium; client-primary cache (store shape open: server-side SQLite cache / godot-sqlite / file cache — SQLite ships in the Rust server, NOT the Godot client). Workshop: 5 seats (Dudley/Araminta/Stig/Tyre + Troblum r2), 2 rounds + lead interview, extendable at Jeroen''s call, round 1 GATED on measurements — see blocker edges. Expected Output 2 mandates an explicit deprecation sweep (Clerk audit) of all conflicting DQR records/tickets at filing.
|
||
|
||
DELIVERED (2026-07-24): the body-map-viewer workshop is this ticket''s output. D-255 filed (stepped Atlas render architecture: server-determines-content, client map-art function, six-level ladder Global+Region→Chunk, tagged-envelope wire, three-tier cache, cache-accelerated-pure-function seed-chaining, lakes from settled hydrology) + 12 in-place amendments (D-166/D-192/D-225/D-226/D-227/D-243 + river-courses-t1170 gloss) + Clerk audit clean (2 unswept conflicts found and fixed: t1143 doc superseded banner, CLAUDE.md Phase-4 row) + measurements ①–⑥ and the population survey all MEASURED + implementation chain T-1181–T-1185 with reconciliations (T-1158 cancelled, T-1175/T-1157 re-scoped, T-1174 raised). Full record: docs/workshops/body-map-viewer/ (workshop-outcomes.md; architecture-briefing-final.md is the plain-language companion).', NULL, '2026-07-24 07:13:23', '2026-07-24 07:13:23.420', '2026-07-24 07:13:23.420', NULL, 'e4ef9dbd48334f1181f494730f0a09f3', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRY9W24PV55Z6FMW8TEM7XER', 'status', 'in_progress', 'done', NULL, '2026-07-24 07:13:28', '2026-07-24 07:13:28.217', '2026-07-24 07:13:28.217', NULL, '53966f3039143c089e5941fec3db1c86', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZXCHGS16BFHSSGSV4', 'description', '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).', '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).
|
||
|
||
SCOPE CLARIFICATION (2026-07-24, Jeroen): the seed-to-tile cascade this phase builds is ALSO the mechanism that determines what exists where the player walks in Phase 5 — not an Atlas-only pipeline. In-world streaming derives the chunk neighborhood around the player (minimum the 3x3 chunks needed to draw everything; prefetch radius a tuning constant) via the same derivation, with coarser-layer context self-provided by function composition (D-255(f) cache-accelerated pure function): Atlas interaction is never a precondition, cache only accelerates, output byte-identical either way — the T-1181 cache-hit==cache-miss determinism gate protects exactly this property. Founding driver: D-012 (''chunks load/unload around the player; the world generates as you explore''), amended 2026-07-24 to point at the cascade records. The insert minimap (Q-093) is noted as a same-derivation consumer; its design defers to Phase 5.', NULL, '2026-07-24 11:54:05', '2026-07-24 11:54:05.117', '2026-07-24 11:54:05.117', NULL, '8feb24666f25dbcdfd17f085a72614e4', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRXGSXBZKXTHR7MR5K9H2HRG', 'status', 'backlog', 'in_progress', NULL, '2026-07-24 20:56:44', '2026-07-24 20:56:44.313', '2026-07-24 20:56:44.313', NULL, 'f418ec3dce3256a1cf518e798e27f521', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRXGSXBZKXTHR7MR5K9H2HRG', 'description', 'Pre-existing architectural quirk found by Dudley during T-1168 integration testing (2026-07-23, not introduced by that batch): derive_district_profile''s cell-aggregate-centre sampling and the window path''s district-origin sampling resolve to genuinely different world positions for ''the same DistrictPos'' — full DistrictProfile output legitimately differs between paths (morphology/elev/moisture) at the same nominal district. His integration test was redesigned to compare the riparian signal at a shared exact world position instead (the right test). Investigate whether any existing batch/window consumer pair assumes positional agreement (city placement vs window rendering?), decide the canonical sampling convention, and either unify or document the divergence as intentional with the reasoning.
|
||
|
||
D-255 (2026-07-24): the tagged-envelope step-canvas serving (T-1181) depends on batch and window derive agreeing cell-for-cell — this bug now also blocks the step-canvas serving path, and priority is raised accordingly (Tyre disposition, body-map-viewer workshop). No supersession; intent unchanged.', 'Pre-existing architectural quirk found by Dudley during T-1168 integration testing (2026-07-23, not introduced by that batch): derive_district_profile''s cell-aggregate-centre sampling and the window path''s district-origin sampling resolve to genuinely different world positions for ''the same DistrictPos'' — full DistrictProfile output legitimately differs between paths (morphology/elev/moisture) at the same nominal district. His integration test was redesigned to compare the riparian signal at a shared exact world position instead (the right test). Investigate whether any existing batch/window consumer pair assumes positional agreement (city placement vs window rendering?), decide the canonical sampling convention, and either unify or document the divergence as intentional with the reasoning.
|
||
|
||
D-255 (2026-07-24): the tagged-envelope step-canvas serving (T-1181) depends on batch and window derive agreeing cell-for-cell — this bug now also blocks the step-canvas serving path, and priority is raised accordingly (Tyre disposition, body-map-viewer workshop). No supersession; intent unchanged.
|
||
|
||
RULING (2026-07-24): D-256 claimed and written on branch t1174-derive-sampling (rides the PR; syncs to main on merge). Canonical convention = derive(seed, absolute world metres) via the derive_at_metres family; batch 64x32 pseudo-grid re-scoped as a survey raster with a real SurveyCellPos newtype; derive_district_profile becomes a thin wrapper over an extracted riparian-parameterized core at survey-cell-centre positions (basin_direction preserved by post-call override; near_perennial_water_at plumbed, never the empty-slice default); skeleton morphology judgments move to exact-position derive; step canvases fenced to the window family. LayerRegionOutput rebuild deferred to T-1181 (tripwire verified: sole reader is the region_grid overlay); voxel carrier deferred to Phase 5. Consults: Tyre APPROVE-WITH-CHANGES, Dudley FEASIBLE-WITH-CHANGES (both incorporated). Settlement/road positions do NOT move (L1 attractor-sourced; T-1075 bake orthogonal); believability goldens regen, gates unchanged; window goldens must stay byte-green.', NULL, '2026-07-24 21:38:41', '2026-07-24 21:38:41.718', '2026-07-24 21:38:41.718', NULL, '68b38fb11fd680c3f568e95b18b36537', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZZ5XKET93HPHKQHKW', 'description', 'Follow-ups from the Hoshe/Tyre pre-bake review (the BLOCKER/MAJOR items were fixed inline; these are the deferred MINOR/coverage items):
|
||
|
||
TESTS:
|
||
- features.rs: full per-type attractor reachability fixtures — craft heightmaps that guarantee LakeShore (enclosed depression), PassEntrance (saddle), PlainCenter (flat), RiverCrossing (confluence). Currently only RiverMouth/CoastalAccess/ValleyFloor are exercised on the slope/sine fixtures.
|
||
- heightmap.rs: 8-bit grayscale decode path; sea_level passthrough assertion; downsample identity/upsample early-return.
|
||
- drainage.rs: basin area_pct bit-for-bit determinism (only river_cells + basin count checked today).
|
||
- layer1.rs: attach_feature_names mountain branch with a non-empty mountain pool + ≥1 Alpine attractor.
|
||
- features.rs: thin_by_spacing behavior (spacing collisions, equirectangular column wrap).
|
||
- import_economics.py: automated idempotency test — two runs on a scratch DB yield identical atlas_city_names count (not doubled), and 0 rows for system ''GJ 0'' (Sol exemption). Wire alongside check-systems-db / pre-push.
|
||
- Wire test_sim_determinism.py into pre-push or a make target.
|
||
|
||
MINOR CODE NITS:
|
||
- drainage.rs ~480-488: comment the intentional isolated-basin fallback divergence from the old merge-to-basin-0 behavior (Tyre N1).
|
||
- planet_simulation.py ~787-788: oasis_water binary_dilation iterations are fixed-pixel — scale by GRID_W/512 for biome-display consistency at 1024 (cosmetic, Atlas only, not cascade; Tyre N2).', 'Follow-ups from the Hoshe/Tyre pre-bake review (the BLOCKER/MAJOR items were fixed inline; these are the deferred MINOR/coverage items):
|
||
|
||
TESTS:
|
||
- features.rs: full per-type attractor reachability fixtures — craft heightmaps that guarantee LakeShore (enclosed depression), PassEntrance (saddle), PlainCenter (flat), RiverCrossing (confluence). Currently only RiverMouth/CoastalAccess/ValleyFloor are exercised on the slope/sine fixtures.
|
||
- heightmap.rs: 8-bit grayscale decode path; sea_level passthrough assertion; downsample identity/upsample early-return.
|
||
- drainage.rs: basin area_pct bit-for-bit determinism (only river_cells + basin count checked today).
|
||
- layer1.rs: attach_feature_names mountain branch with a non-empty mountain pool + ≥1 Alpine attractor.
|
||
- features.rs: thin_by_spacing behavior (spacing collisions, equirectangular column wrap).
|
||
- import_economics.py: automated idempotency test — two runs on a scratch DB yield identical atlas_city_names count (not doubled), and 0 rows for system ''GJ 0'' (Sol exemption). Wire alongside check-systems-db / pre-push.
|
||
- Wire test_sim_determinism.py into pre-push or a make target.
|
||
|
||
MINOR CODE NITS:
|
||
- drainage.rs ~480-488: comment the intentional isolated-basin fallback divergence from the old merge-to-basin-0 behavior (Tyre N1).
|
||
- planet_simulation.py ~787-788: oasis_water binary_dilation iterations are fixed-pixel — scale by GRID_W/512 for biome-display consistency at 1024 (cosmetic, Atlas only, not cascade; Tyre N2).
|
||
|
||
D-256/T-1174 finding (2026-07-25): the believability harness golden is INSENSITIVE to a total basin_direction regression — an all-North basin collapse (every survey cell defaulting) produced a byte-identical believability.json at current sample density (64/2048 districts; basin only reaches voxel meander phase/channel width, too localized for the coarse aggregate stats). The cross-namespace keying seam is now covered by the restored derive_all_districts_threads_supplied_basin_directions test (production-shaped survey keys), but the harness itself has no basin-sensitive metric. Candidate hardening: a basin-direction distribution stat (distinct directions >= 2 on a drained body) or a voxel-transect metric that moves with meander phase.', NULL, '2026-07-24 22:38:59', '2026-07-24 22:38:59.482', '2026-07-24 22:38:59.482', NULL, '11374469110761a33a33b8210ad53928', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRXGSXBZKXTHR7MR5K9H2HRG', 'status', 'in_progress', 'review', NULL, '2026-07-24 23:18:26', '2026-07-24 23:18:26.774', '2026-07-24 23:18:26.774', NULL, '0e4aa2b6429cbcae6e99807975ff69cf', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XQW73B1P8WKR2BCZBFXZW', 'status', 'backlog', 'in_progress', NULL, '2026-07-24 23:52:05', '2026-07-24 23:52:05.692', '2026-07-24 23:52:05.692', NULL, 'f675cb4c0fd898dad72722cbee9572ed', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XQW73B1P8WKR2BCZBFXZW', 'status', 'in_progress', 'review', NULL, '2026-07-25 00:26:42', '2026-07-25 00:26:42.634', '2026-07-25 00:26:42.634', NULL, 'ada454394fd3e1eb062c1ed4b7a0356f', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRXGSXBZKXTHR7MR5K9H2HRG', 'status', 'review', 'done', NULL, '2026-07-24 23:35:06', '2026-07-24 23:35:06.393', '2026-07-24 23:35:06.393', NULL, 'e0388f7bb73f510999e595c12fbbcfb5', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XQW73B1P8WKR2BCZBFXZW', 'status', 'backlog', 'in_progress', NULL, '2026-07-24 23:49:56', '2026-07-24 23:49:56.371', '2026-07-24 23:49:56.371', NULL, '4a54eb01cde514c7118a9b217420c857', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XXY5GNCQEXYAYQEQD0CHM', 'status', 'backlog', 'in_progress', NULL, '2026-07-24 23:49:56', '2026-07-24 23:49:56.374', '2026-07-24 23:49:56.374', NULL, 'cabecf341333b7a0e56ac7f2b05bc1b0', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XXY5GNCQEXYAYQEQD0CHM', 'description', 'Two halves, one ticket (the D-227 lakes amendment''s implementation; converged in araminta-round2.md §(e) + dudley-interview2-response.md CORRECTED section). HALF 1 — productionize: wire server/src/atlas/hydrology_equilibrium.rs (currently an inert workshop prototype, zero non-test callers) into the derive pipeline: solve once per body at rung-0 Global populate (measured ~24ms/body at 512x256; population survey: all 267 bodies ~0.86s), result held with the global tier (D-203-shaped, keep-always). HALF 2 — lake sourcing: MorphologyZone::Lake (discriminant 1 — ALREADY in the frozen D-239 17-zone vocabulary, no widening) becomes sourced from the settled solver: at derive time a gridunit is Lake when bilinear-sampled HydrologyResult.filled_scaled exceeds bilinear-sampled original elevation (the continuous filled-surface comparison — lake edges refine with rung like coastlines, per D-166; NEVER project basin-cell membership as a discrete lookup, which gives blocky non-refining edges), with today''s ocean_fraction_q>=60 heuristic as fallback where no solve exists. This is seed-chaining mechanism B (coarse continuous primitive sampled fresh per rung — D-255(f)). STATIC classification — distinct from the sim-state flooded plane; a lake''s existence must never flicker on a TTL. NO endorheic bit anywhere (ruled: the cue is outflow-course presence, delivered by the separate outlet-wiring ticket; until that lands the map shows lakes without the drains-vs-closed distinction — honest sequencing per D-227 amendment (4)). Byte cost: zero new wire bytes (existing field). Uniform moisture_q=55 scope limit from the survey noted: affects endorheic/overflow split only, never lake extent.', 'Two halves, one ticket (the D-227 lakes amendment''s implementation; converged in araminta-round2.md §(e) + dudley-interview2-response.md CORRECTED section). HALF 1 — productionize: wire server/src/atlas/hydrology_equilibrium.rs (currently an inert workshop prototype, zero non-test callers) into the derive pipeline: solve once per body at rung-0 Global populate (measured ~24ms/body at 512x256; population survey: all 267 bodies ~0.86s), result held with the global tier (D-203-shaped, keep-always). HALF 2 — lake sourcing: MorphologyZone::Lake (discriminant 1 — ALREADY in the frozen D-239 17-zone vocabulary, no widening) becomes sourced from the settled solver: at derive time a gridunit is Lake when bilinear-sampled HydrologyResult.filled_scaled exceeds bilinear-sampled original elevation (the continuous filled-surface comparison — lake edges refine with rung like coastlines, per D-166; NEVER project basin-cell membership as a discrete lookup, which gives blocky non-refining edges), with today''s ocean_fraction_q>=60 heuristic as fallback where no solve exists. This is seed-chaining mechanism B (coarse continuous primitive sampled fresh per rung — D-255(f)). STATIC classification — distinct from the sim-state flooded plane; a lake''s existence must never flicker on a TTL. NO endorheic bit anywhere (ruled: the cue is outflow-course presence, delivered by the separate outlet-wiring ticket; until that lands the map shows lakes without the drains-vs-closed distinction — honest sequencing per D-227 amendment (4)). Byte cost: zero new wire bytes (existing field). Uniform moisture_q=55 scope limit from the survey noted: affects endorheic/overflow split only, never lake extent.
|
||
|
||
IMPLEMENTATION NOTE (2026-07-25, lead-accepted deviation): the ticket''s ''result held with the global tier (D-203-shaped, keep-always)'' clause could not be satisfied literally — no keep-always rung-0 resident tier exists in the codebase yet (BodyWorldStateCache is the D-203 50-body LRU and drops TerrainAnalysis per T-1048). Implemented instead: hydrology solves once per TerrainAnalysis build inside run_layer1/run_layer1_with_moisture (~24ms, mirrors drainage::analyze), carried as TerrainAnalysis.hydrology: Option<HydrologySample> (~1MB), resident wherever TA is resident (TerrainAnalysisCache in gen_queue). When T-1181 builds the actual resident global tier, hydrology rides TA into it with no further wiring. Also: TerrainAnalysisCache::get_or_derive gained a body_params param to thread the real moisture ceiling — a known merge seam with the concurrent T-1181 branch (second-to-land rebases). Basin-id/outcome sampling deliberately NOT wired (T-1185 will need its own nearest-sample basin-id lookup if it needs identity beyond outlet-path presence); HydrologyResult.basins spill points computed but currently discarded after filled/elevation extraction — cheap to extend at the same call site.', NULL, '2026-07-25 00:16:29', '2026-07-25 00:16:29.760', '2026-07-25 00:16:29.760', NULL, '07732da7d3a5c8a9e5c17bbd4b743d54', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XXY5GNCQEXYAYQEQD0CHM', 'status', 'in_progress', 'review', NULL, '2026-07-25 00:28:44', '2026-07-25 00:28:44.132', '2026-07-25 00:28:44.132', NULL, '3044cf7ce15aeb72b4aff61313cc3e7e', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSCXX7E3BXT7WG0BYDB6PJA0', 'description', 'Found during the PR #199 (T-1174/D-256) review fix round, PRE-EXISTING on the window path since the region climate stack (T-1078/T-1113) was wired into derive_at_metres. region_profile::region_centre_latitude_deg (region_profile.rs ~270-280) maps region row 0 to the north pole (+90) with lat_frac clamped to [0,1] — a pole-anchored, non-negative row convention. But the derive core (derive_at_metres_with_riparian, district_profile.rs ~1788) keys regions by floor-dividing EQUATOR-anchored world metres (negative wy = north), producing signed region rows (Earth-class: -49..+49). Consequence: every northern-hemisphere region has negative row -> region_centre_y_m negative -> lat_frac clamps to 0 -> baseline latitude +90 (polar) regardless of true latitude; southern-hemisphere rows 0..~48 read as compressed NORTHERN latitudes ~89..~0.7 (south pole reads as equator). Affects the region temperature baseline (and glaciation/moisture components derived from it) for the window path at every rung, and post-D-256 the batch/survey path inherits the same keys (still an improvement over the pre-D-256 body-wide region-(0,0) baseline, which read ~+89 everywhere). NOT touched in PR #199 to keep the review round scoped; goldens currently pin the wrong-latitude values. FIX SHAPE: make region_centre_latitude_deg mirror the derive core''s inverse mapping (equator-anchored signed rows: lat = -((ry+0.5)*REGION_M/meridian_m clamped to [-0.5,0.5])*180), audit the OTHER convention''s callers (the D-255 rung-0 canvas row space and the collapsed LayerRegionOutput builder use non-negative pole-anchored rows - decide ONE convention per D-256''s one-inverse-mapping principle, likely at the T-1181 rung-0 rebuild), regen affected goldens, and re-run the believability direction check. Related: D-256, D-243, T-1181, T-1078.', 'Found during the PR #199 (T-1174/D-256) review fix round, PRE-EXISTING on the window path since the region climate stack (T-1078/T-1113) was wired into derive_at_metres. region_profile::region_centre_latitude_deg (region_profile.rs ~270-280) maps region row 0 to the north pole (+90) with lat_frac clamped to [0,1] — a pole-anchored, non-negative row convention. But the derive core (derive_at_metres_with_riparian, district_profile.rs ~1788) keys regions by floor-dividing EQUATOR-anchored world metres (negative wy = north), producing signed region rows (Earth-class: -49..+49). Consequence: every northern-hemisphere region has negative row -> region_centre_y_m negative -> lat_frac clamps to 0 -> baseline latitude +90 (polar) regardless of true latitude; southern-hemisphere rows 0..~48 read as compressed NORTHERN latitudes ~89..~0.7 (south pole reads as equator). Affects the region temperature baseline (and glaciation/moisture components derived from it) for the window path at every rung, and post-D-256 the batch/survey path inherits the same keys (still an improvement over the pre-D-256 body-wide region-(0,0) baseline, which read ~+89 everywhere). NOT touched in PR #199 to keep the review round scoped; goldens currently pin the wrong-latitude values. FIX SHAPE: make region_centre_latitude_deg mirror the derive core''s inverse mapping (equator-anchored signed rows: lat = -((ry+0.5)*REGION_M/meridian_m clamped to [-0.5,0.5])*180), audit the OTHER convention''s callers (the D-255 rung-0 canvas row space and the collapsed LayerRegionOutput builder use non-negative pole-anchored rows - decide ONE convention per D-256''s one-inverse-mapping principle, likely at the T-1181 rung-0 rebuild), regen affected goldens, and re-run the believability direction check. Related: D-256, D-243, T-1181, T-1078.
|
||
|
||
In-the-wild datapoint (2026-07-25, T-1184 eyeball session): GJ338Bd (Arbour, R=6711km) survey cell (42,29) — true position latitude -76.2S (wy=8,929,367m, region row 43) — derives with the pole-anchored baseline latitude +13.9N, producing an 18C temperate, glaciation-free lake district near the antarctic circle. Concrete demonstration of the southern-hemisphere-reads-as-northern-tropics half of the bug (the northern half clamps to +90). Conversion math used: scratchpad survey_to_district.py, the D-256 bridge formula.', NULL, '2026-07-25 01:01:37', '2026-07-25 01:01:37.348', '2026-07-25 01:01:37.348', NULL, '5aa76c70a4a81e6e66391bbfaea9b85e', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XXY5GNCQEXYAYQEQD0CHM', 'status', 'review', 'done', NULL, '2026-07-25 01:11:56', '2026-07-25 01:11:56.813', '2026-07-25 01:11:56.813', NULL, '16cb46543b844f102adbecb905977b41', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XQW73B1P8WKR2BCZBFXZW', 'description', 'The D-225-discharging migration per D-255(c): one new Inbound variant (StepCanvasRequest, required marker field step_canvas, extending the proven star_map/city_names/browse ShapeProbe pattern in server/src/bridge/mod.rs) + a dedicated StepCanvasResponse (NOT a field on AtlasLayerResponse — the D-226 §2 ceiling is re-scoped to the legacy carrier). Serves all six rungs of the D-255(a) ladder — rung-0 Global variable-extent is a field value, not a different shape; fixed rungs viewport-sized per D-255(b). Encoding: PNG-per-field dense (8 fields: 6 static + glaciation/flooded sim-state L8 planes) + MessagePack-native sparse (courses, cliffs) per the T-1179 measured table. SERVER CACHE TIERS ARE THIS TICKET''S SCOPE TOO (SI gap 3): the D-203-shaped resident global tier (~8.85MB population-wide, measured) + TTL(detail, time, distance) for finer rungs + SIM_STATE_TTL[field] = 1x the field''s own fastest driving clock-bucket per body class (flooded: tidal bucket moon-bearing / seasonal moonless; glaciation: seasonal — D-227 amendment (1), Dudley+Araminta joint formula). ACCEPTANCE GATE (SI gap 2, mandatory per D-227 amendment (3)): byte-identical output test — cache-hit derive path == cache-miss derive path for every rung; the seed-chaining cache-accelerated-pure-function correctness gate, same shape as T-1170''s window-independence invariant. Implementation note carried from measurement S2: courses cost +38-87% at chunk/block spacing (station count scales inversely with rung spacing — 1,732 vs 867 points/course measured); a station-spacing cap independent of rung spacing is a named candidate optimization, decision at implementation. Design sources: dudley-round2.md §(a), tyre-round2.md §(b), D-255(c)(d)(f). Legacy district_window survives byte-unchanged until its consumer is replaced.', 'The D-225-discharging migration per D-255(c): one new Inbound variant (StepCanvasRequest, required marker field step_canvas, extending the proven star_map/city_names/browse ShapeProbe pattern in server/src/bridge/mod.rs) + a dedicated StepCanvasResponse (NOT a field on AtlasLayerResponse — the D-226 §2 ceiling is re-scoped to the legacy carrier). Serves all six rungs of the D-255(a) ladder — rung-0 Global variable-extent is a field value, not a different shape; fixed rungs viewport-sized per D-255(b). Encoding: PNG-per-field dense (8 fields: 6 static + glaciation/flooded sim-state L8 planes) + MessagePack-native sparse (courses, cliffs) per the T-1179 measured table. SERVER CACHE TIERS ARE THIS TICKET''S SCOPE TOO (SI gap 3): the D-203-shaped resident global tier (~8.85MB population-wide, measured) + TTL(detail, time, distance) for finer rungs + SIM_STATE_TTL[field] = 1x the field''s own fastest driving clock-bucket per body class (flooded: tidal bucket moon-bearing / seasonal moonless; glaciation: seasonal — D-227 amendment (1), Dudley+Araminta joint formula). ACCEPTANCE GATE (SI gap 2, mandatory per D-227 amendment (3)): byte-identical output test — cache-hit derive path == cache-miss derive path for every rung; the seed-chaining cache-accelerated-pure-function correctness gate, same shape as T-1170''s window-independence invariant. Implementation note carried from measurement S2: courses cost +38-87% at chunk/block spacing (station count scales inversely with rung spacing — 1,732 vs 867 points/course measured); a station-spacing cap independent of rung spacing is a named candidate optimization, decision at implementation. Design sources: dudley-round2.md §(a), tyre-round2.md §(b), D-255(c)(d)(f). Legacy district_window survives byte-unchanged until its consumer is replaced.
|
||
|
||
IMPLEMENTATION REPORT — wire shapes for T-1182 (2026-07-25, PR #201): StepCanvasRung = Global (rung 0, variable, one gridunit per region, whole-body, always-kept) | Region 204.8km | District 2048m | Quarter 512m | Block 128m | Chunk 64m (deepest). Global/Region derive via derive_orbital_at_metres; District..Chunk via derive_at_metres. StepCanvasRequest { step_canvas: bool (marker), body_id, rung, center: (i64,i64), extent: (u32,u32), min_wl_m: u32 } — sixth Inbound variant. StepCanvasResponse { body_id, rung, center, min_wl_m, status: StepCanvasStatus, canvas: Option<EncodedStepCanvas> } — dedicated outbound, NOT on AtlasLayerResponse. EncodedStepCanvas: width, height + 6 static fields (morphology, elev_q, moisture_q, vegetation as PNG-per-field; temp_dc raw Vec<i16> msgpack, settlement_id raw Vec<u32> msgpack — too wide for 8-bit PNG) + 2 sim-state (glaciation PNG, flooded_q PNG always-0 stub) + 2 sparse (courses: Vec<RiverCourse>, cliffs: Vec<CliffSegment> — always empty today, zero carved cells in the population). settlement_id: 0=none else city_id, a 1500m proximity radius around the settlement anchor point (honest approximation — no footprint polygons exist; revisit when quarter-skeleton geometry lands); Global rung reports zero coverage. Rung-0 row space: SIGNED equator-anchored rows (wy=(row-rows/2)*REGION_M, negative=north) per the D-256 canonical core — T-1186 interaction documented at build_step_canvas. Caches: GlobalTierCache (BTreeMap by body_id, no eviction API — structurally keep-always, lazy D-206 populate) + StepCanvasCache keyed (body_id, rung, center, extent, min_wl_m), dual-axis eviction on get() (storage TTL per rung, Region ~1h..Chunk ~2min; SIM_STATE_TTL seasonal ~1h / tidal ~15min moon-bearing — note BodyDrivingClockClass::classify always returns Moonless today, no moon signal on BodyParams). Station-spacing cap adopted: course_station_spacing_m(rung) = rung.spacing_m().max(DISTRICT_M) (COURSE_STATION_SPACING_FLOOR_M). Known stubs: flooded_q always 0, glaciation static (D-253 not built); both wire-shape-ready.', NULL, '2026-07-25 01:21:11', '2026-07-25 01:21:11.774', '2026-07-25 01:21:11.774', NULL, '51c8c51fb6b6509b0ef3de5b63773161', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XQW73B1P8WKR2BCZBFXZW', 'status', 'in_progress', 'review', NULL, '2026-07-25 01:21:19', '2026-07-25 01:21:19.771', '2026-07-25 01:21:19.771', NULL, 'd1db4f86c70195def949676db0f78b20', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XQW73B1P8WKR2BCZBFXZW', 'description', 'The D-225-discharging migration per D-255(c): one new Inbound variant (StepCanvasRequest, required marker field step_canvas, extending the proven star_map/city_names/browse ShapeProbe pattern in server/src/bridge/mod.rs) + a dedicated StepCanvasResponse (NOT a field on AtlasLayerResponse — the D-226 §2 ceiling is re-scoped to the legacy carrier). Serves all six rungs of the D-255(a) ladder — rung-0 Global variable-extent is a field value, not a different shape; fixed rungs viewport-sized per D-255(b). Encoding: PNG-per-field dense (8 fields: 6 static + glaciation/flooded sim-state L8 planes) + MessagePack-native sparse (courses, cliffs) per the T-1179 measured table. SERVER CACHE TIERS ARE THIS TICKET''S SCOPE TOO (SI gap 3): the D-203-shaped resident global tier (~8.85MB population-wide, measured) + TTL(detail, time, distance) for finer rungs + SIM_STATE_TTL[field] = 1x the field''s own fastest driving clock-bucket per body class (flooded: tidal bucket moon-bearing / seasonal moonless; glaciation: seasonal — D-227 amendment (1), Dudley+Araminta joint formula). ACCEPTANCE GATE (SI gap 2, mandatory per D-227 amendment (3)): byte-identical output test — cache-hit derive path == cache-miss derive path for every rung; the seed-chaining cache-accelerated-pure-function correctness gate, same shape as T-1170''s window-independence invariant. Implementation note carried from measurement S2: courses cost +38-87% at chunk/block spacing (station count scales inversely with rung spacing — 1,732 vs 867 points/course measured); a station-spacing cap independent of rung spacing is a named candidate optimization, decision at implementation. Design sources: dudley-round2.md §(a), tyre-round2.md §(b), D-255(c)(d)(f). Legacy district_window survives byte-unchanged until its consumer is replaced.
|
||
|
||
IMPLEMENTATION REPORT — wire shapes for T-1182 (2026-07-25, PR #201): StepCanvasRung = Global (rung 0, variable, one gridunit per region, whole-body, always-kept) | Region 204.8km | District 2048m | Quarter 512m | Block 128m | Chunk 64m (deepest). Global/Region derive via derive_orbital_at_metres; District..Chunk via derive_at_metres. StepCanvasRequest { step_canvas: bool (marker), body_id, rung, center: (i64,i64), extent: (u32,u32), min_wl_m: u32 } — sixth Inbound variant. StepCanvasResponse { body_id, rung, center, min_wl_m, status: StepCanvasStatus, canvas: Option<EncodedStepCanvas> } — dedicated outbound, NOT on AtlasLayerResponse. EncodedStepCanvas: width, height + 6 static fields (morphology, elev_q, moisture_q, vegetation as PNG-per-field; temp_dc raw Vec<i16> msgpack, settlement_id raw Vec<u32> msgpack — too wide for 8-bit PNG) + 2 sim-state (glaciation PNG, flooded_q PNG always-0 stub) + 2 sparse (courses: Vec<RiverCourse>, cliffs: Vec<CliffSegment> — always empty today, zero carved cells in the population). settlement_id: 0=none else city_id, a 1500m proximity radius around the settlement anchor point (honest approximation — no footprint polygons exist; revisit when quarter-skeleton geometry lands); Global rung reports zero coverage. Rung-0 row space: SIGNED equator-anchored rows (wy=(row-rows/2)*REGION_M, negative=north) per the D-256 canonical core — T-1186 interaction documented at build_step_canvas. Caches: GlobalTierCache (BTreeMap by body_id, no eviction API — structurally keep-always, lazy D-206 populate) + StepCanvasCache keyed (body_id, rung, center, extent, min_wl_m), dual-axis eviction on get() (storage TTL per rung, Region ~1h..Chunk ~2min; SIM_STATE_TTL seasonal ~1h / tidal ~15min moon-bearing — note BodyDrivingClockClass::classify always returns Moonless today, no moon signal on BodyParams). Station-spacing cap adopted: course_station_spacing_m(rung) = rung.spacing_m().max(DISTRICT_M) (COURSE_STATION_SPACING_FLOOR_M). Known stubs: flooded_q always 0, glaciation static (D-253 not built); both wire-shape-ready.', 'The D-225-discharging migration per D-255(c): one new Inbound variant (StepCanvasRequest, required marker field step_canvas, extending the proven star_map/city_names/browse ShapeProbe pattern in server/src/bridge/mod.rs) + a dedicated StepCanvasResponse (NOT a field on AtlasLayerResponse — the D-226 §2 ceiling is re-scoped to the legacy carrier). Serves all six rungs of the D-255(a) ladder — rung-0 Global variable-extent is a field value, not a different shape; fixed rungs viewport-sized per D-255(b). Encoding: PNG-per-field dense (8 fields: 6 static + glaciation/flooded sim-state L8 planes) + MessagePack-native sparse (courses, cliffs) per the T-1179 measured table. SERVER CACHE TIERS ARE THIS TICKET''S SCOPE TOO (SI gap 3): the D-203-shaped resident global tier (~8.85MB population-wide, measured) + TTL(detail, time, distance) for finer rungs + SIM_STATE_TTL[field] = 1x the field''s own fastest driving clock-bucket per body class (flooded: tidal bucket moon-bearing / seasonal moonless; glaciation: seasonal — D-227 amendment (1), Dudley+Araminta joint formula). ACCEPTANCE GATE (SI gap 2, mandatory per D-227 amendment (3)): byte-identical output test — cache-hit derive path == cache-miss derive path for every rung; the seed-chaining cache-accelerated-pure-function correctness gate, same shape as T-1170''s window-independence invariant. Implementation note carried from measurement S2: courses cost +38-87% at chunk/block spacing (station count scales inversely with rung spacing — 1,732 vs 867 points/course measured); a station-spacing cap independent of rung spacing is a named candidate optimization, decision at implementation. Design sources: dudley-round2.md §(a), tyre-round2.md §(b), D-255(c)(d)(f). Legacy district_window survives byte-unchanged until its consumer is replaced.
|
||
|
||
IMPLEMENTATION REPORT — wire shapes for T-1182 (2026-07-25, PR #201): StepCanvasRung = Global (rung 0, variable, one gridunit per region, whole-body, always-kept) | Region 204.8km | District 2048m | Quarter 512m | Block 128m | Chunk 64m (deepest). Global/Region derive via derive_orbital_at_metres; District..Chunk via derive_at_metres. StepCanvasRequest { step_canvas: bool (marker), body_id, rung, center: (i64,i64), extent: (u32,u32), min_wl_m: u32 } — sixth Inbound variant. StepCanvasResponse { body_id, rung, center, min_wl_m, status: StepCanvasStatus, canvas: Option<EncodedStepCanvas> } — dedicated outbound, NOT on AtlasLayerResponse. EncodedStepCanvas: width, height + 6 static fields (morphology, elev_q, moisture_q, vegetation as PNG-per-field; temp_dc raw Vec<i16> msgpack, settlement_id raw Vec<u32> msgpack — too wide for 8-bit PNG) + 2 sim-state (glaciation PNG, flooded_q PNG always-0 stub) + 2 sparse (courses: Vec<RiverCourse>, cliffs: Vec<CliffSegment> — always empty today, zero carved cells in the population). settlement_id: 0=none else city_id, a 1500m proximity radius around the settlement anchor point (honest approximation — no footprint polygons exist; revisit when quarter-skeleton geometry lands); Global rung reports zero coverage. Rung-0 row space: SIGNED equator-anchored rows (wy=(row-rows/2)*REGION_M, negative=north) per the D-256 canonical core — T-1186 interaction documented at build_step_canvas. Caches: GlobalTierCache (BTreeMap by body_id, no eviction API — structurally keep-always, lazy D-206 populate) + StepCanvasCache keyed (body_id, rung, center, extent, min_wl_m), dual-axis eviction on get() (storage TTL per rung, Region ~1h..Chunk ~2min; SIM_STATE_TTL seasonal ~1h / tidal ~15min moon-bearing — note BodyDrivingClockClass::classify always returns Moonless today, no moon signal on BodyParams). Station-spacing cap adopted: course_station_spacing_m(rung) = rung.spacing_m().max(DISTRICT_M) (COURSE_STATION_SPACING_FLOOR_M). Known stubs: flooded_q always 0, glaciation static (D-253 not built); both wire-shape-ready.
|
||
|
||
WIRE SHAPE ADDENDUM (PR #201 review round): StepCanvasResponse gained an extent: (u32,u32) ECHO field — the server-clamped canvas extent, so the client can detect a clamp (mirrors DistrictWindowLayer.n precedent). Wire extent is clamped server-side per D-255(b): STEP_CANVAS_MAX_EXTENT_AXIS=3840 per axis, STEP_CANVAS_MAX_EXTENT_CELLS=8294400 total (aspect-preserving scale-down); Global rung ignores wire extent entirely. T-1182 client must read the echoed extent, never assume its requested one.', NULL, '2026-07-25 01:33:48', '2026-07-25 01:33:48.224', '2026-07-25 01:33:48.224', NULL, '38229b5ea0a6985ce97bc8ce697063b4', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XQW73B1P8WKR2BCZBFXZW', 'status', 'review', 'done', NULL, '2026-07-25 01:37:38', '2026-07-25 01:37:38.819', '2026-07-25 01:37:38.819', NULL, '3a05142969cc0817dde8259dd7f1efb7', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XT949C8D2JZRWDX2CRZN8', 'status', 'backlog', 'in_progress', NULL, '2026-07-25 06:10:59', '2026-07-25 06:10:59.088', '2026-07-25 06:10:59.088', NULL, '6536626cafe883d6ac1e918391d6a679', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XZF4A978WS1J66Q2JBK8C', 'status', 'backlog', 'in_progress', NULL, '2026-07-25 06:10:59', '2026-07-25 06:10:59.091', '2026-07-25 06:10:59.091', NULL, 'e087a67f5cb6ee578d8151c7c38c7eb7', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XZF4A978WS1J66Q2JBK8C', 'status', 'in_progress', 'review', NULL, '2026-07-25 06:46:29', '2026-07-25 06:46:29.803', '2026-07-25 06:46:29.803', NULL, '002dbfd7b3c984b3e0eefe5b27261eb6', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XT949C8D2JZRWDX2CRZN8', 'status', 'in_progress', 'review', NULL, '2026-07-25 06:57:31', '2026-07-25 06:57:31.456', '2026-07-25 06:57:31.456', NULL, '67ff0e6480acfd4cc5897b7262e28d02', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRJD6EKPBQE08NA8VHP692W8', 'description', 'T-1153 broke the T-1120/T-1121 golden capture harness: client/tests/visual_scenarios.gd and visual_capture.gd call app._regional_screen._viewer.get_heightmap_texture()/show_body() — both crash against AtlasWindowViewer (regional_screen now wraps the ladder viewer; AtlasViewer is unreachable from nav). Confirmed NOT wired into tests/run-godot or the pre-push hook (no reference in either), so nothing blocks, but the 12 curated atlas_* goldens and the --atlas-matrix capture path are dead until redesigned for the ladder (capture at defined rungs/zooms instead of the fixed heightmap frame; the new canonical orbital frame is the natural replacement for the old whole-body shot). Also decide the fate of the retired AtlasViewer code these harnesses were the last live consumers of — likely deletable once T-1156 (overlay port) settles what carries forward.
|
||
|
||
Live round 4 addendum: client/tests/test_atlas_window_overlay_draw_smoke.gd (3 scenarios -> now 2 after removing a flaky harness-sanity check: single-window draw + tile-mosaic draw, both asserting real composited pixels via SubViewport render) is a standalone gdUnit file with its own headless-skip guard, added because this redesign hadn''t landed yet. When this ticket lands, migrate its 2 scenarios into the redesigned tests/visual.json harness (folding the standalone file away) for consistency with the rest of the real-rendering test suite — see docs/DEVOPS.md''s ''Real-rendering test exception'' note for the interim rationale.
|
||
|
||
RE-SCOPED by D-255 (2026-07-24, body-map-viewer workshop): this becomes the capture harness for the STEPPED render architecture — goldens key on (body, step) canvases, not the retired continuous-zoom frames. The T-1152/T-1153 test suites (coverage-walk, continuous-zoom seams, compute_tile_grid mosaic) retire with their code in T-1182''s change; this re-scoped harness is their replacement and the eyeball-check substrate for every step canvas. More needed than ever — keep, don''t cancel.', 'T-1153 broke the T-1120/T-1121 golden capture harness: client/tests/visual_scenarios.gd and visual_capture.gd call app._regional_screen._viewer.get_heightmap_texture()/show_body() — both crash against AtlasWindowViewer (regional_screen now wraps the ladder viewer; AtlasViewer is unreachable from nav). Confirmed NOT wired into tests/run-godot or the pre-push hook (no reference in either), so nothing blocks, but the 12 curated atlas_* goldens and the --atlas-matrix capture path are dead until redesigned for the ladder (capture at defined rungs/zooms instead of the fixed heightmap frame; the new canonical orbital frame is the natural replacement for the old whole-body shot). Also decide the fate of the retired AtlasViewer code these harnesses were the last live consumers of — likely deletable once T-1156 (overlay port) settles what carries forward.
|
||
|
||
Live round 4 addendum: client/tests/test_atlas_window_overlay_draw_smoke.gd (3 scenarios -> now 2 after removing a flaky harness-sanity check: single-window draw + tile-mosaic draw, both asserting real composited pixels via SubViewport render) is a standalone gdUnit file with its own headless-skip guard, added because this redesign hadn''t landed yet. When this ticket lands, migrate its 2 scenarios into the redesigned tests/visual.json harness (folding the standalone file away) for consistency with the rest of the real-rendering test suite — see docs/DEVOPS.md''s ''Real-rendering test exception'' note for the interim rationale.
|
||
|
||
RE-SCOPED by D-255 (2026-07-24, body-map-viewer workshop): this becomes the capture harness for the STEPPED render architecture — goldens key on (body, step) canvases, not the retired continuous-zoom frames. The T-1152/T-1153 test suites (coverage-walk, continuous-zoom seams, compute_tile_grid mosaic) retire with their code in T-1182''s change; this re-scoped harness is their replacement and the eyeball-check substrate for every step canvas. More needed than ever — keep, don''t cancel.
|
||
|
||
PR #203 fix-round inventory (2026-07-25): the retirement is now TOTAL — AtlasViewer and its whole cluster (atlas_viewer, atlas_marker_overlay, atlas_descend_geometry, atlas_legend_panel, atlas_generation_proxy, atlas_generation_state) are deleted. visual_scenarios.gd (_setup_atlas_golden_shot, 6 of 12 atlas_GJ* z2_0/z4_0 non-fit scenarios) and visual_capture.gd (_run_atlas_matrix) now call StepCanvasViewer methods that do not exist: get_heightmap_texture(), set_view(zoom, offset), get_view_offset() — the fit-zoom shots early-return before hitting them. Ruled in PR #203: NO shim (would resurrect the retired continuous-zoom API D-255 kills); the redesign here keys captures on (body, rung) via StepCanvasViewer''s real surface (enter/_scroll_rung/rung state + the echoed extent). get_overlay_defs()/set_overlay_visible() duck-type fine and survive. Until this lands, those 6 goldens + atlas_matrix are knowingly dead (manual make targets only, gate-invisible — confirmed again).', NULL, '2026-07-25 07:32:19', '2026-07-25 07:32:19.974', '2026-07-25 07:32:19.974', NULL, '85a62f8545b4e710acc57db0781b73b7', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XT949C8D2JZRWDX2CRZN8', 'status', 'review', 'done', NULL, '2026-07-25 08:39:14', '2026-07-25 08:39:14.794', '2026-07-25 08:39:14.794', NULL, 'f30bdf6e60a9ca04d4b6ecca94d2f6f8', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XZF4A978WS1J66Q2JBK8C', 'status', 'review', 'done', NULL, '2026-07-25 08:39:14', '2026-07-25 08:39:14.797', '2026-07-25 08:39:14.797', NULL, 'e766df18190ba474631380d40af1d295', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XW0ZMPVYA2CPBBTP88TQC', 'status', 'backlog', 'in_progress', NULL, '2026-07-25 08:40:03', '2026-07-25 08:40:03.632', '2026-07-25 08:40:03.632', NULL, '52b02d51cae9a585e561b1354529b50a', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XW0ZMPVYA2CPBBTP88TQC', 'status', 'in_progress', 'review', NULL, '2026-07-25 09:11:50', '2026-07-25 09:11:50.463', '2026-07-25 09:11:50.463', NULL, '6373f0431b384b13ca6bb8fbc88d92ff', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRJD6EKPBQE08NA8VHP692W8', 'description', 'T-1153 broke the T-1120/T-1121 golden capture harness: client/tests/visual_scenarios.gd and visual_capture.gd call app._regional_screen._viewer.get_heightmap_texture()/show_body() — both crash against AtlasWindowViewer (regional_screen now wraps the ladder viewer; AtlasViewer is unreachable from nav). Confirmed NOT wired into tests/run-godot or the pre-push hook (no reference in either), so nothing blocks, but the 12 curated atlas_* goldens and the --atlas-matrix capture path are dead until redesigned for the ladder (capture at defined rungs/zooms instead of the fixed heightmap frame; the new canonical orbital frame is the natural replacement for the old whole-body shot). Also decide the fate of the retired AtlasViewer code these harnesses were the last live consumers of — likely deletable once T-1156 (overlay port) settles what carries forward.
|
||
|
||
Live round 4 addendum: client/tests/test_atlas_window_overlay_draw_smoke.gd (3 scenarios -> now 2 after removing a flaky harness-sanity check: single-window draw + tile-mosaic draw, both asserting real composited pixels via SubViewport render) is a standalone gdUnit file with its own headless-skip guard, added because this redesign hadn''t landed yet. When this ticket lands, migrate its 2 scenarios into the redesigned tests/visual.json harness (folding the standalone file away) for consistency with the rest of the real-rendering test suite — see docs/DEVOPS.md''s ''Real-rendering test exception'' note for the interim rationale.
|
||
|
||
RE-SCOPED by D-255 (2026-07-24, body-map-viewer workshop): this becomes the capture harness for the STEPPED render architecture — goldens key on (body, step) canvases, not the retired continuous-zoom frames. The T-1152/T-1153 test suites (coverage-walk, continuous-zoom seams, compute_tile_grid mosaic) retire with their code in T-1182''s change; this re-scoped harness is their replacement and the eyeball-check substrate for every step canvas. More needed than ever — keep, don''t cancel.
|
||
|
||
PR #203 fix-round inventory (2026-07-25): the retirement is now TOTAL — AtlasViewer and its whole cluster (atlas_viewer, atlas_marker_overlay, atlas_descend_geometry, atlas_legend_panel, atlas_generation_proxy, atlas_generation_state) are deleted. visual_scenarios.gd (_setup_atlas_golden_shot, 6 of 12 atlas_GJ* z2_0/z4_0 non-fit scenarios) and visual_capture.gd (_run_atlas_matrix) now call StepCanvasViewer methods that do not exist: get_heightmap_texture(), set_view(zoom, offset), get_view_offset() — the fit-zoom shots early-return before hitting them. Ruled in PR #203: NO shim (would resurrect the retired continuous-zoom API D-255 kills); the redesign here keys captures on (body, rung) via StepCanvasViewer''s real surface (enter/_scroll_rung/rung state + the echoed extent). get_overlay_defs()/set_overlay_visible() duck-type fine and survive. Until this lands, those 6 goldens + atlas_matrix are knowingly dead (manual make targets only, gate-invisible — confirmed again).', 'T-1153 broke the T-1120/T-1121 golden capture harness: client/tests/visual_scenarios.gd and visual_capture.gd call app._regional_screen._viewer.get_heightmap_texture()/show_body() — both crash against AtlasWindowViewer (regional_screen now wraps the ladder viewer; AtlasViewer is unreachable from nav). Confirmed NOT wired into tests/run-godot or the pre-push hook (no reference in either), so nothing blocks, but the 12 curated atlas_* goldens and the --atlas-matrix capture path are dead until redesigned for the ladder (capture at defined rungs/zooms instead of the fixed heightmap frame; the new canonical orbital frame is the natural replacement for the old whole-body shot). Also decide the fate of the retired AtlasViewer code these harnesses were the last live consumers of — likely deletable once T-1156 (overlay port) settles what carries forward.
|
||
|
||
Live round 4 addendum: client/tests/test_atlas_window_overlay_draw_smoke.gd (3 scenarios -> now 2 after removing a flaky harness-sanity check: single-window draw + tile-mosaic draw, both asserting real composited pixels via SubViewport render) is a standalone gdUnit file with its own headless-skip guard, added because this redesign hadn''t landed yet. When this ticket lands, migrate its 2 scenarios into the redesigned tests/visual.json harness (folding the standalone file away) for consistency with the rest of the real-rendering test suite — see docs/DEVOPS.md''s ''Real-rendering test exception'' note for the interim rationale.
|
||
|
||
RE-SCOPED by D-255 (2026-07-24, body-map-viewer workshop): this becomes the capture harness for the STEPPED render architecture — goldens key on (body, step) canvases, not the retired continuous-zoom frames. The T-1152/T-1153 test suites (coverage-walk, continuous-zoom seams, compute_tile_grid mosaic) retire with their code in T-1182''s change; this re-scoped harness is their replacement and the eyeball-check substrate for every step canvas. More needed than ever — keep, don''t cancel.
|
||
|
||
PR #203 fix-round inventory (2026-07-25): the retirement is now TOTAL — AtlasViewer and its whole cluster (atlas_viewer, atlas_marker_overlay, atlas_descend_geometry, atlas_legend_panel, atlas_generation_proxy, atlas_generation_state) are deleted. visual_scenarios.gd (_setup_atlas_golden_shot, 6 of 12 atlas_GJ* z2_0/z4_0 non-fit scenarios) and visual_capture.gd (_run_atlas_matrix) now call StepCanvasViewer methods that do not exist: get_heightmap_texture(), set_view(zoom, offset), get_view_offset() — the fit-zoom shots early-return before hitting them. Ruled in PR #203: NO shim (would resurrect the retired continuous-zoom API D-255 kills); the redesign here keys captures on (body, rung) via StepCanvasViewer''s real surface (enter/_scroll_rung/rung state + the echoed extent). get_overlay_defs()/set_overlay_visible() duck-type fine and survive. Until this lands, those 6 goldens + atlas_matrix are knowingly dead (manual make targets only, gate-invisible — confirmed again).
|
||
|
||
Harness techniques inventory addition (from the PR #204 / T-1183 restart-persistence eyeball, 2026-07-25) — proven live-rendering eyeball patterns for shared-desktop sessions:
|
||
|
||
1. InputSwallower pattern: root-level Node (added first, low process_priority), _input()+_unhandled_input() both call get_viewport().set_input_as_handled() unconditionally — neutralizes real desktop input reaching a `-s` SceneTree driver''s real window (X11/XWayland delivers pointer events to unfocused windows under the cursor). Verify via a per-capture-window intercept counter: N>0 intercepted AND zero resulting view drift is proof; 0 intercepted proves nothing.
|
||
2. In-process navigation via viewer methods, not OS input: call the same methods the app''s own gdUnit suite exercises (StepCanvasViewer.enter()/_scroll_rung(); RegionalScreen.enter() atlas-matrix precedent in visual_capture.gd) — identical production code path, no OS injection needed (Wayland/KWin blocks synthetic X11 injection for XWayland clients entirely).
|
||
3. View-transform logging at every capture: world_center, view_offset, the drawing Node2D''s canvas position, footprint_px alongside every screenshot — turns "pixels don''t match" into a root-causable mechanism (PR #204: drift matched PAN_SPEED_PX_S*frame_time*held-frames to 0.02px, identifying unfocused edge-scroll bleed, now T-1191).
|
||
4. Full-run-restart-on-anomaly, never partial retry: any mid-sequence assertion failure discards the whole run (cold-wipe for a cold-role attempt; fresh-process-only for a revisit-role attempt) — partial retries silently corrupt the state the comparison depends on.
|
||
5. Fixed-center revisit mode: record a prior run''s actual derived centers and re-request them literally on the comparison run, bypassing cursor-anchored re-derivation — required when run 2 must land on run 1''s exact cache keys, not merely repeat the gesture.', NULL, '2026-07-25 10:11:48', '2026-07-25 10:11:48.141', '2026-07-25 10:11:48.141', NULL, '83de23f3aa4c3087e6147b768a0646de', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSG8PRRFJQ3Y2V3R348DDRRM', 'description', 'Found in the T-1182 eyeball (2026-07-25): on Arbour (R=6711km, circumference ~42,166km), the Region rung''s viewport-fit canvas (~200x210 cells x 204.8km) slightly exceeds the body circumference, so derive_orbital_at_metres'' deliberate longitude wrap (rem_euclid) makes the continent visibly repeat side-by-side. Not a math bug — the world legitimately wraps in view. UX question: clamp the Region-rung viewport extent to the body circumference (extent is already server-clamped per D-255(b) — a per-body circumference cap on the requested extent would be a client-side transport refinement), or draw a wrap seam indicator. Smaller bodies make it worse. Captures: .cache/screenshots/t1182-eyeball/rung-ladder/02-region.png. Related: D-243 elastic seam, D-255(a).', 'Found in the T-1182 eyeball (2026-07-25): on Arbour (R=6711km, circumference ~42,166km), the Region rung''s viewport-fit canvas (~200x210 cells x 204.8km) slightly exceeds the body circumference, so derive_orbital_at_metres'' deliberate longitude wrap (rem_euclid) makes the continent visibly repeat side-by-side. Not a math bug — the world legitimately wraps in view. UX question: clamp the Region-rung viewport extent to the body circumference (extent is already server-clamped per D-255(b) — a per-body circumference cap on the requested extent would be a client-side transport refinement), or draw a wrap seam indicator. Smaller bodies make it worse. Captures: .cache/screenshots/t1182-eyeball/rung-ladder/02-region.png. Related: D-243 elastic seam, D-255(a).
|
||
|
||
ESCALATION from the T-1183 eyeball captures (2026-07-25, GJ1c, .cache/screenshots/t1183-eyeball-run2/02-region.png): this is NOT a small-body edge case and it is TWO axes, not one. At a 1920x1080 viewport the Region rung requested extent 384x216 cells x 204.8 km = 78,643 x 44,237 km — exceeding even an Earth-class circumference (~40,000 km) roughly 2x horizontally, so the continents repeat side-by-side on EVERY body at Region rung, and the vertical span overruns both poles: rows past the pole clamp to the last row and render as smeared vertical stripes filling the bottom ~40% of the frame (much uglier than the longitude repeat — looks like corrupted data, not a wrapped map). Jeroen flagged the frame as looking broken. Fix shape: cap the Region-rung request extent to the body''s region grid (circumference in the x axis, pole-to-pole in the y axis — both already known client-side from the Global canvas extent echo), letterbox the remainder, and consider the same guard for any rung whose footprint can exceed the body. Priority raised low->high: this makes the Region rung look broken on every body at standard viewports.', NULL, '2026-07-25 10:17:29', '2026-07-25 10:17:29.416', '2026-07-25 10:17:29.416', NULL, '85ba92e8f7082cc30b1a60f86556b714', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSG8PRRFJQ3Y2V3R348DDRRM', 'priority', 'low', 'high', NULL, '2026-07-25 10:17:39', '2026-07-25 10:17:39.835', '2026-07-25 10:17:39.835', NULL, 'f9ed56ae2da9e57b3a1179fb72112226', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FS5XW0ZMPVYA2CPBBTP88TQC', 'status', 'review', 'done', NULL, '2026-07-25 10:17:42', '2026-07-25 10:17:42.701', '2026-07-25 10:17:42.701', NULL, '4f651c137c2744d831d8b13a786fca08', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSCXX7E3BXT7WG0BYDB6PJA0', 'status', 'backlog', 'in_progress', NULL, '2026-07-25 10:20:01', '2026-07-25 10:20:01.865', '2026-07-25 10:20:01.865', NULL, '6e2c110ed6a2169857c75f628b71ffda', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSHHXXTS56ZBB78N2W43DD2G', 'status', 'backlog', 'in_progress', NULL, '2026-07-25 10:20:01', '2026-07-25 10:20:01.872', '2026-07-25 10:20:01.872', NULL, '108166dfcee0fee7fbb24a50fb5edd0c', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSG8PRRFJQ3Y2V3R348DDRRM', 'status', 'backlog', 'in_progress', NULL, '2026-07-25 10:20:01', '2026-07-25 10:20:01.872', '2026-07-25 10:20:01.872', NULL, '5d75d4565abe1778b7d3abae4f5f1b18', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSG8P6C6WXEG3X81PVCQ833M', 'status', 'backlog', 'in_progress', NULL, '2026-07-25 10:20:01', '2026-07-25 10:20:01.872', '2026-07-25 10:20:01.872', NULL, '9e773a4cc2b7b5759f5a994ede489d11', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSCXX7E3BXT7WG0BYDB6PJA0', 'assigned_to', NULL, 'dudley', NULL, '2026-07-25 10:21:12', '2026-07-25 10:21:12.179', '2026-07-25 10:21:12.179', NULL, '1b598b7dd17d56f8b367163dd03555dc', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSG8P6C6WXEG3X81PVCQ833M', 'assigned_to', NULL, 'dudley', NULL, '2026-07-25 10:21:12', '2026-07-25 10:21:12.182', '2026-07-25 10:21:12.182', NULL, 'f50eca9df80ee1dcef3e403523192bd1', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSG8PRRFJQ3Y2V3R348DDRRM', 'assigned_to', NULL, 'stig', NULL, '2026-07-25 10:21:12', '2026-07-25 10:21:12.361', '2026-07-25 10:21:12.361', NULL, '99c802490ada7749a3e4279c512733b4', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSHHXXTS56ZBB78N2W43DD2G', 'assigned_to', NULL, 'stig', NULL, '2026-07-25 10:21:12', '2026-07-25 10:21:12.368', '2026-07-25 10:21:12.368', NULL, 'c43a8a611451457c25f6ccefaaecd1a1', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSG8PRRFJQ3Y2V3R348DDRRM', 'status', 'in_progress', 'review', NULL, '2026-07-25 10:58:29', '2026-07-25 10:58:29.490', '2026-07-25 10:58:29.490', NULL, '0a6a26d03c6502fc627e2ae6d34798ee', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSHHXXTS56ZBB78N2W43DD2G', 'status', 'in_progress', 'review', NULL, '2026-07-25 10:58:29', '2026-07-25 10:58:29.495', '2026-07-25 10:58:29.495', NULL, 'a1f13038a99f41899712c56db261386a', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSG8PRRFJQ3Y2V3R348DDRRM', 'status', 'review', 'done', NULL, '2026-07-25 11:29:11', '2026-07-25 11:29:11.343', '2026-07-25 11:29:11.343', NULL, '852d91352b7f2e850f848dbf0ea5f36a', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSHHXXTS56ZBB78N2W43DD2G', 'status', 'review', 'done', NULL, '2026-07-25 11:29:11', '2026-07-25 11:29:11.346', '2026-07-25 11:29:11.346', NULL, '8e0ae72ea1a4f4f308ca402009c0b3e5', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSCXX7E3BXT7WG0BYDB6PJA0', 'status', 'in_progress', 'review', NULL, '2026-07-25 11:38:28', '2026-07-25 11:38:28.088', '2026-07-25 11:38:28.088', NULL, '6931fd55bb80213b2e4c0e0df53f7d63', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSG8P6C6WXEG3X81PVCQ833M', 'status', 'in_progress', 'review', NULL, '2026-07-25 11:38:28', '2026-07-25 11:38:28.093', '2026-07-25 11:38:28.093', NULL, '05dfe844068b316cbde4f4ba7175221f', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSCXX7E3BXT7WG0BYDB6PJA0', 'status', 'review', 'done', NULL, '2026-07-25 12:45:32', '2026-07-25 12:45:32.483', '2026-07-25 12:45:32.483', NULL, '9e2509493e56289b581edb395437e29b', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSG8P6C6WXEG3X81PVCQ833M', 'status', 'review', 'done', NULL, '2026-07-25 12:45:32', '2026-07-25 12:45:32.487', '2026-07-25 12:45:32.487', NULL, '0543405565d8175739276aa3b0fc9ffb', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRPEGNSG7VVR602MTT4VDCEW', 'description', 'PR #193 review (Tyre, finding 2): after MAX_RETRIES(30)/~110s of genuine unbroken Pending in the tiled orbital rest state, the player is permanently stuck at DERIVING TERRAIN: pan is a no-op while tiled (_maybe_refloat_window early-returns), zoom-out is floored at the canonical frame (edge-triggered reset never re-fires), and regional_screen.enter() no-ops same-body re-entry — recovery only via zooming IN across the Region boundary or visiting a different body. Pathological trigger (110s of continuous Pending) and the release-server make-atlas change makes it near-impossible on the sanctioned path, but it is a real dead-end. Fix options per the review: a manual retry affordance on the DERIVING state, or same-body re-entry re-issues tile requests when has_pending_tiles() and every tile request is exhausted-non-pending. Single-window is already fully recoverable (any pan/zoom resets the retry state) — this is tile-mode only.', 'PR #193 review (Tyre, finding 2): after MAX_RETRIES(30)/~110s of genuine unbroken Pending in the tiled orbital rest state, the player is permanently stuck at DERIVING TERRAIN: pan is a no-op while tiled (_maybe_refloat_window early-returns), zoom-out is floored at the canonical frame (edge-triggered reset never re-fires), and regional_screen.enter() no-ops same-body re-entry — recovery only via zooming IN across the Region boundary or visiting a different body. Pathological trigger (110s of continuous Pending) and the release-server make-atlas change makes it near-impossible on the sanctioned path, but it is a real dead-end. Fix options per the review: a manual retry affordance on the DERIVING state, or same-body re-entry re-issues tile requests when has_pending_tiles() and every tile request is exhausted-non-pending. Single-window is already fully recoverable (any pan/zoom resets the retry state) — this is tile-mode only.
|
||
|
||
Refinement review (2026-07-25, post-D-255 batch): GAPS — do not implement as written. The root-cause description targets retired tiled-orbital machinery (atlas_window_tile_set.gd, has_pending_tiles()) that no longer exists; Region/Global under D-255(a) is a single flat per-rung canvas. HOWEVER the dead-end symptom plausibly survives in the new architecture: step_canvas_request.gd:47 MAX_RETRIES=30, step_canvas_viewer.gd:544 "DERIVING TERRAIN..." label, _maybe_refloat() (viewer:498) early-returns for Global, and regional_screen.enter() (screens/regional_screen.gd:38-43) no-ops on same-body re-entry guarded on body_id alone — the same-body-reentry trap the ticket cites. Re-scope: reproduce the exhausted-retry dead-end against StepCanvasRequest/StepCanvasViewer''s single-canvas retry model first, then fix what actually reproduces. Investigate-then-fix, not fix-as-described.', NULL, '2026-07-25 12:50:50', '2026-07-25 12:50:50.726', '2026-07-25 12:50:50.726', NULL, '26e8ac982e2cbe6dced1adf5c4b069a6', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRVMZYG7Z5YCKHCBS7XWJPM4', 'description', 'Observed during T-1156 wave-1 acceptance drives (2026-07-23, lead): calling AtlasWindowViewer._enter_at_rung(body, system, district_center, 32, ''District'') at a pole-edge center (Lendel district (10466,-4784), the meridian edge) produced a REGION window in one run (header ''region window - 204.800 km/cell'', center canonicalized to (10461,-4773)) while an earlier run at the same nominal center rendered the requested district window (2.048 km/cell, center uncanonicalized (10466,-4784) exactly). Suspected interplay: pole-wall clamp / canonicalize_district_center vs the entry auto-fit and _maybe_reselect_rung''s coverage walk (a pole-clamped degenerate window''s computed extent may trip is_fully_zoomed_out or the coverage ceiling). Also on file: one drive process computed a sign-flipped latitude mapping (row 0 -> +wy) unreproducible afterward — suspected stale compiled-script cache serving a revert-verification''s temporarily-flipped state (godot-cold-parse wipes exactly this class of cache). Reproduce both at the pole edge, pin with tests. Extreme-edge case: normal navigation rarely enters District directly at a pole.', 'Observed during T-1156 wave-1 acceptance drives (2026-07-23, lead): calling AtlasWindowViewer._enter_at_rung(body, system, district_center, 32, ''District'') at a pole-edge center (Lendel district (10466,-4784), the meridian edge) produced a REGION window in one run (header ''region window - 204.800 km/cell'', center canonicalized to (10461,-4773)) while an earlier run at the same nominal center rendered the requested district window (2.048 km/cell, center uncanonicalized (10466,-4784) exactly). Suspected interplay: pole-wall clamp / canonicalize_district_center vs the entry auto-fit and _maybe_reselect_rung''s coverage walk (a pole-clamped degenerate window''s computed extent may trip is_fully_zoomed_out or the coverage ceiling). Also on file: one drive process computed a sign-flipped latitude mapping (row 0 -> +wy) unreproducible afterward — suspected stale compiled-script cache serving a revert-verification''s temporarily-flipped state (godot-cold-parse wipes exactly this class of cache). Reproduce both at the pole edge, pin with tests. Extreme-edge case: normal navigation rarely enters District directly at a pole.
|
||
|
||
Refinement review (2026-07-25, post-D-255 batch): GAPS — entirely stale as written. Every cited function (AtlasWindowViewer._enter_at_rung, canonicalize_district_center, _maybe_reselect_rung, is_fully_zoomed_out) is retired with the T-1182 rework; regional_screen.gd''s own doc confirms the orbital-mosaic-vs-window split this bug lived in is gone (one StepCanvasViewer, one path, D-255(a)). Whether a pole-edge canonicalization defect exists in the unified single-path model is an open question with no current reproduction. Do not route to an implementer as-is: needs a fresh reproduction attempt against StepCanvasViewer/regional_screen.gd near a pole-adjacent District entry; close as moot if it does not reproduce, refile with new specifics if it does.', NULL, '2026-07-25 12:50:53', '2026-07-25 12:50:53.776', '2026-07-25 12:50:53.776', NULL, 'bd0d7b4162c72fb9346ca91dcde8e79b', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRV2EV5QK4BCZ1P9H85JH2YM', 'status', 'backlog', 'in_progress', NULL, '2026-07-25 12:51:01', '2026-07-25 12:51:01.110', '2026-07-25 12:51:01.110', NULL, '6cd71d2af50ff19b6274cf567537a591', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRMPWFRCD3M8282XJ01YWGX0', 'status', 'backlog', 'in_progress', NULL, '2026-07-25 12:51:01', '2026-07-25 12:51:01.116', '2026-07-25 12:51:01.116', NULL, '3016f301da704caa8a0542bd38fdd010', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRMPTY517G7ZBMPAPMMCCMK8', 'status', 'backlog', 'in_progress', NULL, '2026-07-25 12:51:01', '2026-07-25 12:51:01.117', '2026-07-25 12:51:01.117', NULL, '13d18776a2c86370f6cc8224ae7cd941', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRXKFEJMDEPQ0PZ5Q862DHKG', 'status', 'backlog', 'in_progress', NULL, '2026-07-25 12:51:01', '2026-07-25 12:51:01.117', '2026-07-25 12:51:01.117', NULL, '53da4420c4dc1ce87be57476a921bf4c', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRV2EV5QK4BCZ1P9H85JH2YM', 'assigned_to', NULL, 'dudley', NULL, '2026-07-25 12:51:02', '2026-07-25 12:51:02.101', '2026-07-25 12:51:02.101', NULL, '622e6bd2199e976afe70fe6d49bbbec8', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRMPWFRCD3M8282XJ01YWGX0', 'assigned_to', NULL, 'dudley', NULL, '2026-07-25 12:51:02', '2026-07-25 12:51:02.107', '2026-07-25 12:51:02.107', NULL, '67e7ce155f021be709f36d5ce85b584b', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRMPTY517G7ZBMPAPMMCCMK8', 'assigned_to', NULL, 'dudley', NULL, '2026-07-25 12:51:02', '2026-07-25 12:51:02.110', '2026-07-25 12:51:02.110', NULL, '2e10cf171e26bbd5d97c51ab123d4931', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRXKFEJMDEPQ0PZ5Q862DHKG', 'assigned_to', NULL, 'stig', NULL, '2026-07-25 12:51:02', '2026-07-25 12:51:02.516', '2026-07-25 12:51:02.516', NULL, 'a86d711182f0b2548469cfd2f7e31e5e', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRXKFEJMDEPQ0PZ5Q862DHKG', 'status', 'in_progress', 'review', NULL, '2026-07-25 13:28:36', '2026-07-25 13:28:36.337', '2026-07-25 13:28:36.337', NULL, '36b5205acebfd8d1c75221b2e68513e7', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRV2EV5QK4BCZ1P9H85JH2YM', 'description', 'T-1156 wave 1''s ''labels if cheap'' clause, split out after Si''s audit (2026-07-23): cheap but not free — three dormant pieces exist and nothing connects them. (1) layer1::attach_feature_names (layer1.rs:213-262) is unit-tested with zero production callers — wire it into run_layer1''s call path with name pools; (2) atlas_feature_names (systems-schema.sql:537-544) is created-but-never-populated — add the INSERT step at regen time from the D-223 names-only markers.json pools, mirroring populate_atlas_city_names (generator change: import_economics/atlas.py — watchlist/regen-db implications); (3) add a feature-names read proxy mirroring atlas_data_proxy.rs handle_city_names_request (D-236 pattern — its own message type, outside the AtlasLayerResponse ceilings) + client label draw on the ladder (the retired _draw_named_features at atlas_marker_overlay.gd:239-264 reads the pre-D-223 dict shape and would silently no-op — rewrite, don''t reactivate).', 'T-1156 wave 1''s ''labels if cheap'' clause, split out after Si''s audit (2026-07-23): cheap but not free — three dormant pieces exist and nothing connects them. (1) layer1::attach_feature_names (layer1.rs:213-262) is unit-tested with zero production callers — wire it into run_layer1''s call path with name pools; (2) atlas_feature_names (systems-schema.sql:537-544) is created-but-never-populated — add the INSERT step at regen time from the D-223 names-only markers.json pools, mirroring populate_atlas_city_names (generator change: import_economics/atlas.py — watchlist/regen-db implications); (3) add a feature-names read proxy mirroring atlas_data_proxy.rs handle_city_names_request (D-236 pattern — its own message type, outside the AtlasLayerResponse ceilings) + client label draw on the ladder (the retired _draw_named_features at atlas_marker_overlay.gd:239-264 reads the pre-D-223 dict shape and would silently no-op — rewrite, don''t reactivate).
|
||
|
||
Scope adjudication (2026-07-25, PR round, lead ruling): the "client label draw" clause is RE-SCOPED OUT of this ticket into T-1195, for rivers as well as mountains. Implementation found the ticket''s cheap-anchor premise false: the FeatureNamesRequest pool proxy is position-free (correctly mirroring CityNamesRequest per this ticket''s own instruction), and the client''s course polylines (river_course::InventedCourse) are not correlated with layer1::GeographicAttractor positions by construction — so anchoring a pool name at a mouth ring has no matching basis without a wire-carried position, the identical dependency mountains have. Rather than two ad-hoc wire changes, the one design decision (name rides the course array vs a separate sparse feature-position list mirroring courses/cliffs) lands once in T-1195 for both feature types. This ticket''s delivered scope: atlas_feature_names populated at regen (17,891 rows), the FeatureNamesRequest/Response proxy end-to-end, attach_feature_names wired into the cascade with assignments stored on Layer1Output/BodyWorldState — the three dormant pieces connected.', NULL, '2026-07-25 13:40:57', '2026-07-25 13:40:57.886', '2026-07-25 13:40:57.886', NULL, 'bf5005a2ca802d5c8c486017843a6723', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSJXFJEBK5EW5WDGN6FTS4KG', 'description', 'Split from T-1169 (2026-07-25, dudley''s scope finding): river labels shipped end-to-end in T-1169 (names via the FeatureNamesRequest proxy, anchored at the course mouth ring positions already on the wire), and attach_feature_names is wired into the cascade with assignments stored server-side — but ALPINE PEAK positions are not on the canvas wire anywhere, so mountain labels cannot draw. This ticket: add peak positions to the StepCanvasResponse contract (likely shape: a sparse feature list mirroring courses/cliffs per D-255(c) — positions + name-pool keys, NOT a dense plane; decide which rungs carry it — probably Global/Region/District only, labels are noise deeper), thread server encode → client protocol decode → an additive label-draw anchor in step_canvas_annotation_layer.gd reusing T-1169''s label-draw function. Wire-shape change → project.yaml version bump for the disk-cache tag (D-192/T-1183 mechanism). The server-side data already exists after T-1169 (attach_feature_names assignments on the cascade output); this is transport + presentation only. Related: T-1169, D-255(c), D-236.', 'Split from T-1169 (2026-07-25, dudley''s scope finding): river labels shipped end-to-end in T-1169 (names via the FeatureNamesRequest proxy, anchored at the course mouth ring positions already on the wire), and attach_feature_names is wired into the cascade with assignments stored server-side — but ALPINE PEAK positions are not on the canvas wire anywhere, so mountain labels cannot draw. This ticket: add peak positions to the StepCanvasResponse contract (likely shape: a sparse feature list mirroring courses/cliffs per D-255(c) — positions + name-pool keys, NOT a dense plane; decide which rungs carry it — probably Global/Region/District only, labels are noise deeper), thread server encode → client protocol decode → an additive label-draw anchor in step_canvas_annotation_layer.gd reusing T-1169''s label-draw function. Wire-shape change → project.yaml version bump for the disk-cache tag (D-192/T-1183 mechanism). The server-side data already exists after T-1169 (attach_feature_names assignments on the cascade output); this is transport + presentation only. Related: T-1169, D-255(c), D-236.
|
||
|
||
EXPANDED (2026-07-25, lead ruling on dudley''s second scope finding): this ticket now covers RIVER labels as well as mountain-peak labels — T-1169''s implementation proved rivers have the identical missing link (the names pool is position-free, and client course polylines aren''t correlated with the server-side named attractors by construction; anchoring at the mouth ring has no matching basis). The single design decision to make FIRST, once, for both: does the name ride ON the course entry in the existing courses array (river-natural, but leaves mountains needing a second mechanism), or does a separate sparse feature-position list (positions + name-pool keys, mirroring courses/cliffs per D-255(c)) carry BOTH feature types uniformly? Preliminary lead lean: the uniform sparse list — one mechanism, one wire addition, mountains and rivers together, and course geometry stays name-free (names are annotation data, not hydrology). Decide at pickup with tyre/araminta input if contested. Server-side data all exists post-T-1169 (assignments on Layer1Output/BodyWorldState.feature_names; pool + proxy shipped). Transport + client draw + project.yaml bump remain.', NULL, '2026-07-25 13:41:04', '2026-07-25 13:41:04.273', '2026-07-25 13:41:04.273', NULL, 'be565d2ca8370ec0a49be05ce626284c', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRJD6EKPBQE08NA8VHP692W8', 'description', 'T-1153 broke the T-1120/T-1121 golden capture harness: client/tests/visual_scenarios.gd and visual_capture.gd call app._regional_screen._viewer.get_heightmap_texture()/show_body() — both crash against AtlasWindowViewer (regional_screen now wraps the ladder viewer; AtlasViewer is unreachable from nav). Confirmed NOT wired into tests/run-godot or the pre-push hook (no reference in either), so nothing blocks, but the 12 curated atlas_* goldens and the --atlas-matrix capture path are dead until redesigned for the ladder (capture at defined rungs/zooms instead of the fixed heightmap frame; the new canonical orbital frame is the natural replacement for the old whole-body shot). Also decide the fate of the retired AtlasViewer code these harnesses were the last live consumers of — likely deletable once T-1156 (overlay port) settles what carries forward.
|
||
|
||
Live round 4 addendum: client/tests/test_atlas_window_overlay_draw_smoke.gd (3 scenarios -> now 2 after removing a flaky harness-sanity check: single-window draw + tile-mosaic draw, both asserting real composited pixels via SubViewport render) is a standalone gdUnit file with its own headless-skip guard, added because this redesign hadn''t landed yet. When this ticket lands, migrate its 2 scenarios into the redesigned tests/visual.json harness (folding the standalone file away) for consistency with the rest of the real-rendering test suite — see docs/DEVOPS.md''s ''Real-rendering test exception'' note for the interim rationale.
|
||
|
||
RE-SCOPED by D-255 (2026-07-24, body-map-viewer workshop): this becomes the capture harness for the STEPPED render architecture — goldens key on (body, step) canvases, not the retired continuous-zoom frames. The T-1152/T-1153 test suites (coverage-walk, continuous-zoom seams, compute_tile_grid mosaic) retire with their code in T-1182''s change; this re-scoped harness is their replacement and the eyeball-check substrate for every step canvas. More needed than ever — keep, don''t cancel.
|
||
|
||
PR #203 fix-round inventory (2026-07-25): the retirement is now TOTAL — AtlasViewer and its whole cluster (atlas_viewer, atlas_marker_overlay, atlas_descend_geometry, atlas_legend_panel, atlas_generation_proxy, atlas_generation_state) are deleted. visual_scenarios.gd (_setup_atlas_golden_shot, 6 of 12 atlas_GJ* z2_0/z4_0 non-fit scenarios) and visual_capture.gd (_run_atlas_matrix) now call StepCanvasViewer methods that do not exist: get_heightmap_texture(), set_view(zoom, offset), get_view_offset() — the fit-zoom shots early-return before hitting them. Ruled in PR #203: NO shim (would resurrect the retired continuous-zoom API D-255 kills); the redesign here keys captures on (body, rung) via StepCanvasViewer''s real surface (enter/_scroll_rung/rung state + the echoed extent). get_overlay_defs()/set_overlay_visible() duck-type fine and survive. Until this lands, those 6 goldens + atlas_matrix are knowingly dead (manual make targets only, gate-invisible — confirmed again).
|
||
|
||
Harness techniques inventory addition (from the PR #204 / T-1183 restart-persistence eyeball, 2026-07-25) — proven live-rendering eyeball patterns for shared-desktop sessions:
|
||
|
||
1. InputSwallower pattern: root-level Node (added first, low process_priority), _input()+_unhandled_input() both call get_viewport().set_input_as_handled() unconditionally — neutralizes real desktop input reaching a `-s` SceneTree driver''s real window (X11/XWayland delivers pointer events to unfocused windows under the cursor). Verify via a per-capture-window intercept counter: N>0 intercepted AND zero resulting view drift is proof; 0 intercepted proves nothing.
|
||
2. In-process navigation via viewer methods, not OS input: call the same methods the app''s own gdUnit suite exercises (StepCanvasViewer.enter()/_scroll_rung(); RegionalScreen.enter() atlas-matrix precedent in visual_capture.gd) — identical production code path, no OS injection needed (Wayland/KWin blocks synthetic X11 injection for XWayland clients entirely).
|
||
3. View-transform logging at every capture: world_center, view_offset, the drawing Node2D''s canvas position, footprint_px alongside every screenshot — turns "pixels don''t match" into a root-causable mechanism (PR #204: drift matched PAN_SPEED_PX_S*frame_time*held-frames to 0.02px, identifying unfocused edge-scroll bleed, now T-1191).
|
||
4. Full-run-restart-on-anomaly, never partial retry: any mid-sequence assertion failure discards the whole run (cold-wipe for a cold-role attempt; fresh-process-only for a revisit-role attempt) — partial retries silently corrupt the state the comparison depends on.
|
||
5. Fixed-center revisit mode: record a prior run''s actual derived centers and re-request them literally on the comparison run, bypassing cursor-anchored re-derivation — required when run 2 must land on run 1''s exact cache keys, not merely repeat the gesture.', 'T-1153 broke the T-1120/T-1121 golden capture harness: client/tests/visual_scenarios.gd and visual_capture.gd call app._regional_screen._viewer.get_heightmap_texture()/show_body() — both crash against AtlasWindowViewer (regional_screen now wraps the ladder viewer; AtlasViewer is unreachable from nav). Confirmed NOT wired into tests/run-godot or the pre-push hook (no reference in either), so nothing blocks, but the 12 curated atlas_* goldens and the --atlas-matrix capture path are dead until redesigned for the ladder (capture at defined rungs/zooms instead of the fixed heightmap frame; the new canonical orbital frame is the natural replacement for the old whole-body shot). Also decide the fate of the retired AtlasViewer code these harnesses were the last live consumers of — likely deletable once T-1156 (overlay port) settles what carries forward.
|
||
|
||
Live round 4 addendum: client/tests/test_atlas_window_overlay_draw_smoke.gd (3 scenarios -> now 2 after removing a flaky harness-sanity check: single-window draw + tile-mosaic draw, both asserting real composited pixels via SubViewport render) is a standalone gdUnit file with its own headless-skip guard, added because this redesign hadn''t landed yet. When this ticket lands, migrate its 2 scenarios into the redesigned tests/visual.json harness (folding the standalone file away) for consistency with the rest of the real-rendering test suite — see docs/DEVOPS.md''s ''Real-rendering test exception'' note for the interim rationale.
|
||
|
||
RE-SCOPED by D-255 (2026-07-24, body-map-viewer workshop): this becomes the capture harness for the STEPPED render architecture — goldens key on (body, step) canvases, not the retired continuous-zoom frames. The T-1152/T-1153 test suites (coverage-walk, continuous-zoom seams, compute_tile_grid mosaic) retire with their code in T-1182''s change; this re-scoped harness is their replacement and the eyeball-check substrate for every step canvas. More needed than ever — keep, don''t cancel.
|
||
|
||
PR #203 fix-round inventory (2026-07-25): the retirement is now TOTAL — AtlasViewer and its whole cluster (atlas_viewer, atlas_marker_overlay, atlas_descend_geometry, atlas_legend_panel, atlas_generation_proxy, atlas_generation_state) are deleted. visual_scenarios.gd (_setup_atlas_golden_shot, 6 of 12 atlas_GJ* z2_0/z4_0 non-fit scenarios) and visual_capture.gd (_run_atlas_matrix) now call StepCanvasViewer methods that do not exist: get_heightmap_texture(), set_view(zoom, offset), get_view_offset() — the fit-zoom shots early-return before hitting them. Ruled in PR #203: NO shim (would resurrect the retired continuous-zoom API D-255 kills); the redesign here keys captures on (body, rung) via StepCanvasViewer''s real surface (enter/_scroll_rung/rung state + the echoed extent). get_overlay_defs()/set_overlay_visible() duck-type fine and survive. Until this lands, those 6 goldens + atlas_matrix are knowingly dead (manual make targets only, gate-invisible — confirmed again).
|
||
|
||
Harness techniques inventory addition (from the PR #204 / T-1183 restart-persistence eyeball, 2026-07-25) — proven live-rendering eyeball patterns for shared-desktop sessions:
|
||
|
||
1. InputSwallower pattern: root-level Node (added first, low process_priority), _input()+_unhandled_input() both call get_viewport().set_input_as_handled() unconditionally — neutralizes real desktop input reaching a `-s` SceneTree driver''s real window (X11/XWayland delivers pointer events to unfocused windows under the cursor). Verify via a per-capture-window intercept counter: N>0 intercepted AND zero resulting view drift is proof; 0 intercepted proves nothing.
|
||
2. In-process navigation via viewer methods, not OS input: call the same methods the app''s own gdUnit suite exercises (StepCanvasViewer.enter()/_scroll_rung(); RegionalScreen.enter() atlas-matrix precedent in visual_capture.gd) — identical production code path, no OS injection needed (Wayland/KWin blocks synthetic X11 injection for XWayland clients entirely).
|
||
3. View-transform logging at every capture: world_center, view_offset, the drawing Node2D''s canvas position, footprint_px alongside every screenshot — turns "pixels don''t match" into a root-causable mechanism (PR #204: drift matched PAN_SPEED_PX_S*frame_time*held-frames to 0.02px, identifying unfocused edge-scroll bleed, now T-1191).
|
||
4. Full-run-restart-on-anomaly, never partial retry: any mid-sequence assertion failure discards the whole run (cold-wipe for a cold-role attempt; fresh-process-only for a revisit-role attempt) — partial retries silently corrupt the state the comparison depends on.
|
||
5. Fixed-center revisit mode: record a prior run''s actual derived centers and re-request them literally on the comparison run, bypassing cursor-anchored re-derivation — required when run 2 must land on run 1''s exact cache keys, not merely repeat the gesture.
|
||
|
||
Harness-discipline gap found 2026-07-25 (Jeroen spotted a live orphan): agent-side kill-on-completion does not cover an agent CRASHING mid-capture (API error killed a session between server spawn and its own cleanup step — the server ran on unnoticed for ~25 min on the shared machine). Inventory addition: (6) the LEAD runs an explicit orphan sweep (ps for godot4 + settled-reach-server) at every cycle checkpoint — commit, merge, and after any agent dies abnormally — not only inside agent protocols; pr-process step 1a''s >5-min gdUnit grep does not match live-capture servers, so the sweep needs the server binary name too.', NULL, '2026-07-25 14:04:02', '2026-07-25 14:04:02.818', '2026-07-25 14:04:02.818', NULL, '3b7f3537280bab2c9e9ad2d09d5e0201', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRXKFEJMDEPQ0PZ5Q862DHKG', 'status', 'review', 'done', NULL, '2026-07-25 14:43:55', '2026-07-25 14:43:55.732', '2026-07-25 14:43:55.732', NULL, '01cf21ba37cb15ff5e77e376a2f94e36', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRMPWFRCD3M8282XJ01YWGX0', 'status', 'in_progress', 'review', NULL, '2026-07-25 14:59:12', '2026-07-25 14:59:12.756', '2026-07-25 14:59:12.756', NULL, 'db23cff3b1e1ddc92c8bcf4f87e63912', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRV2EV5QK4BCZ1P9H85JH2YM', 'status', 'in_progress', 'review', NULL, '2026-07-25 14:59:12', '2026-07-25 14:59:12.758', '2026-07-25 14:59:12.758', NULL, '577ffe7bb2bc83c13629064601d57cbc', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRMPTY517G7ZBMPAPMMCCMK8', 'status', 'in_progress', 'review', NULL, '2026-07-25 14:59:12', '2026-07-25 14:59:12.759', '2026-07-25 14:59:12.759', NULL, '9e0db874732ef3f049bed71b6d16e0b0', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRMPWFRCD3M8282XJ01YWGX0', 'status', 'review', 'done', NULL, '2026-07-25 16:20:22', '2026-07-25 16:20:22.122', '2026-07-25 16:20:22.122', NULL, '8535ec9c01bcf0887849790d05bab399', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRV2EV5QK4BCZ1P9H85JH2YM', 'status', 'review', 'done', NULL, '2026-07-25 16:20:22', '2026-07-25 16:20:22.129', '2026-07-25 16:20:22.129', NULL, '8ed7643be68460f63e0d3555d9502718', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRMPTY517G7ZBMPAPMMCCMK8', 'status', 'review', 'done', NULL, '2026-07-25 16:20:22', '2026-07-25 16:20:22.131', '2026-07-25 16:20:22.131', NULL, 'cd5e54f6e1f1066e344ca2ab6740fade', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ9Q7NHVDRT6ARMCWW', 'description', '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.', '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.
|
||
|
||
Refinement review (2026-07-25, Si): OBSOLETE — D-210''s design was fully implemented and merged in PR #953/#963 (commit d418eba8b, 2026-06-03), a month after this ticket was filed, and the ticket was never closed out. Evidence: server/src/atlas/subbiome.rs (classify/classify_variant/base_cost, all 11 variants + terrain_modification_cost from the four D-210 signals, unit-tested); SubBiomeVariant enum + GeographicAttractor.sub_biome (generator.rs:539/:567); wired into the Layer-1 orchestrator (layer1.rs:209-215, Alpine branch tested); consumed downstream (attractor_matching.rs, cascade.rs); client overlay live (atlas_overlay_colors.gd:203 sub_biome_color). The only literal residue — SettingType::Wilderness carrying the cosmetic `Biome = String` alias — is unrelated to D-210''s classification/cost system; tighten it via a separate small ticket if ever wanted. Closing as delivered-by-#953.', NULL, '2026-07-25 16:25:46', '2026-07-25 16:25:46.604', '2026-07-25 16:25:46.604', NULL, '93092399b4a74d80678fc0b0d3d82bd7', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ9Q7NHVDRT6ARMCWW', 'status', 'backlog', 'done', NULL, '2026-07-25 16:25:46', '2026-07-25 16:25:46.760', '2026-07-25 16:25:46.760', NULL, 'c269eb7751dfb286413b3a4d826889e4', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZZ5XKET93HPHKQHKW', 'description', 'Follow-ups from the Hoshe/Tyre pre-bake review (the BLOCKER/MAJOR items were fixed inline; these are the deferred MINOR/coverage items):
|
||
|
||
TESTS:
|
||
- features.rs: full per-type attractor reachability fixtures — craft heightmaps that guarantee LakeShore (enclosed depression), PassEntrance (saddle), PlainCenter (flat), RiverCrossing (confluence). Currently only RiverMouth/CoastalAccess/ValleyFloor are exercised on the slope/sine fixtures.
|
||
- heightmap.rs: 8-bit grayscale decode path; sea_level passthrough assertion; downsample identity/upsample early-return.
|
||
- drainage.rs: basin area_pct bit-for-bit determinism (only river_cells + basin count checked today).
|
||
- layer1.rs: attach_feature_names mountain branch with a non-empty mountain pool + ≥1 Alpine attractor.
|
||
- features.rs: thin_by_spacing behavior (spacing collisions, equirectangular column wrap).
|
||
- import_economics.py: automated idempotency test — two runs on a scratch DB yield identical atlas_city_names count (not doubled), and 0 rows for system ''GJ 0'' (Sol exemption). Wire alongside check-systems-db / pre-push.
|
||
- Wire test_sim_determinism.py into pre-push or a make target.
|
||
|
||
MINOR CODE NITS:
|
||
- drainage.rs ~480-488: comment the intentional isolated-basin fallback divergence from the old merge-to-basin-0 behavior (Tyre N1).
|
||
- planet_simulation.py ~787-788: oasis_water binary_dilation iterations are fixed-pixel — scale by GRID_W/512 for biome-display consistency at 1024 (cosmetic, Atlas only, not cascade; Tyre N2).
|
||
|
||
D-256/T-1174 finding (2026-07-25): the believability harness golden is INSENSITIVE to a total basin_direction regression — an all-North basin collapse (every survey cell defaulting) produced a byte-identical believability.json at current sample density (64/2048 districts; basin only reaches voxel meander phase/channel width, too localized for the coarse aggregate stats). The cross-namespace keying seam is now covered by the restored derive_all_districts_threads_supplied_basin_directions test (production-shaped survey keys), but the harness itself has no basin-sensitive metric. Candidate hardening: a basin-direction distribution stat (distinct directions >= 2 on a drained body) or a voxel-transect metric that moves with meander phase.', 'Follow-ups from the Hoshe/Tyre pre-bake review (the BLOCKER/MAJOR items were fixed inline; these are the deferred MINOR/coverage items):
|
||
|
||
TESTS:
|
||
- features.rs: full per-type attractor reachability fixtures — craft heightmaps that guarantee LakeShore (enclosed depression), PassEntrance (saddle), PlainCenter (flat), RiverCrossing (confluence). Currently only RiverMouth/CoastalAccess/ValleyFloor are exercised on the slope/sine fixtures.
|
||
- heightmap.rs: 8-bit grayscale decode path; sea_level passthrough assertion; downsample identity/upsample early-return.
|
||
- drainage.rs: basin area_pct bit-for-bit determinism (only river_cells + basin count checked today).
|
||
- layer1.rs: attach_feature_names mountain branch with a non-empty mountain pool + ≥1 Alpine attractor.
|
||
- features.rs: thin_by_spacing behavior (spacing collisions, equirectangular column wrap).
|
||
- import_economics.py: automated idempotency test — two runs on a scratch DB yield identical atlas_city_names count (not doubled), and 0 rows for system ''GJ 0'' (Sol exemption). Wire alongside check-systems-db / pre-push.
|
||
- Wire test_sim_determinism.py into pre-push or a make target.
|
||
|
||
MINOR CODE NITS:
|
||
- drainage.rs ~480-488: comment the intentional isolated-basin fallback divergence from the old merge-to-basin-0 behavior (Tyre N1).
|
||
- planet_simulation.py ~787-788: oasis_water binary_dilation iterations are fixed-pixel — scale by GRID_W/512 for biome-display consistency at 1024 (cosmetic, Atlas only, not cascade; Tyre N2).
|
||
|
||
D-256/T-1174 finding (2026-07-25): the believability harness golden is INSENSITIVE to a total basin_direction regression — an all-North basin collapse (every survey cell defaulting) produced a byte-identical believability.json at current sample density (64/2048 districts; basin only reaches voxel meander phase/channel width, too localized for the coarse aggregate stats). The cross-namespace keying seam is now covered by the restored derive_all_districts_threads_supplied_basin_directions test (production-shaped survey keys), but the harness itself has no basin-sensitive metric. Candidate hardening: a basin-direction distribution stat (distinct directions >= 2 on a drained body) or a voxel-transect metric that moves with meander phase.
|
||
|
||
Refinement trim (2026-07-25, Si — every listed gap re-verified against current code before this batch): (1) DROP the test_sim_determinism.py wiring item — already done, Makefile:256 wires it into make test-tooling which the push gate runs on tooling changes. (2) The drainage.rs isolated-basin comment nit moved to ~line 654 (file grew; the old ~480-488 cite is stale) — still open, just relocate. (3) The layer1.rs attach_feature_names mountain-branch item: implicit coverage may already exist via run_layer1_* tests — check before adding a redundant test. (4) The D-256/T-1174 addendum''s "basin-direction distribution stat" candidate hardening is a genuine open design question (which stat, what threshold) — PROPOSE the stat to the lead before coding it, don''t invent silently. All other items (features.rs per-type reachability fixtures + thin_by_spacing, heightmap.rs 8-bit/sea-level-passthrough/upsample-identity, drainage.rs area_pct bit-determinism, import_economics.py idempotency test, oasis_water binary_dilation nit at planet_simulation.py:784-788) verified still open as written.', NULL, '2026-07-25 16:25:56', '2026-07-25 16:25:56.990', '2026-07-25 16:25:56.990', NULL, '99464deb0f973bb04ffdc943badd4d10', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWTP633SM8XB302MBM', 'description', 'D-226 layer 4 (apex). A client-side AtlasAgentInterface exposing a JSON control channel so an automated agent (terminal/curl, headless Godot) can navigate the REAL Atlas UI: observe -> JSON of (a) current data state shown and (b) a walkable UI affordance tree (toggle controls: id/label/state/locked); act -> named SEMANTIC intents (select_system/open_system/select_body/open_regional/select_city/set_overlay/reset_view/back/close_atlas) backed by the same handlers a click calls (the map uses _gui_input, NOT pixel-clicks), plus get_layer_data_summary (attractor/river/basin counts as JSON without rendering). Single AtlasAgentInterface autoload/static class for a stable contract; generic Control-tree walk so economics/saves plug in later. Turns human-eyeball review into an agent QA sweep. Depends on #960 (the viewer) + the auto-pause substrate. Screenshot capture is a separate ticket (kept off the critical path).', 'D-226 layer 4 (apex). A client-side AtlasAgentInterface exposing a JSON control channel so an automated agent (terminal/curl, headless Godot) can navigate the REAL Atlas UI: observe -> JSON of (a) current data state shown and (b) a walkable UI affordance tree (toggle controls: id/label/state/locked); act -> named SEMANTIC intents (select_system/open_system/select_body/open_regional/select_city/set_overlay/reset_view/back/close_atlas) backed by the same handlers a click calls (the map uses _gui_input, NOT pixel-clicks), plus get_layer_data_summary (attractor/river/basin counts as JSON without rendering). Single AtlasAgentInterface autoload/static class for a stable contract; generic Control-tree walk so economics/saves plug in later. Turns human-eyeball review into an agent QA sweep. Depends on #960 (the viewer) + the auto-pause substrate. Screenshot capture is a separate ticket (kept off the critical path).
|
||
|
||
Re-scope (2026-07-25, Si refinement + lead ruling): both cited blockers are satisfied (T-960, T-970 done) and the D-255(d) deep-rung cache cap is already built defensively for this exact consumer (step_canvas_disk_cache.gd:61 names the AtlasAgentInterface QA sweep). But D-226''s named-intent list was designed against the retired pre-D-255 continuous-zoom Atlas — the ticket''s intent surface is STALE. Implementer instruction: derive the actual intent list from the CURRENT stepped-rung API before building the wrapper, and post the derived list to the team lead for confirmation before implementation. Known mapping start (verify, don''t trust): select_system → atlas_app._on_system_selected(system_id); select_body → _on_body_selected(body); reset_view → StepCanvasViewer._reset_to_global(); set_overlay → set_overlay_visible(); back → _on_regional_back(); zoom step → _scroll_rung(direction, cursor_local); open_regional/select_city/open_system need tracing through screens/regional_screen.gd, district_screen.gd, system_screen.gd. SEQUENCING: T-1157 (stepped capture-harness redesign) needs the same walk-the-Atlas-headlessly primitive — its harness-techniques inventory (appended 2026-07-25) documents five proven eyeball-driver patterns (InputSwallower, in-process viewer-method navigation, fixed-center revisit, view-transform logging) that are the PROTOTYPE for this channel; build the T-971 intent layer as the productionization of that pattern so T-1157''s harness can consume it rather than the two designing overlapping scaffolding independently.', NULL, '2026-07-25 16:26:05', '2026-07-25 16:26:05.492', '2026-07-25 16:26:05.492', NULL, 'f7eb781029e013fcecfceffbf28932d8', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZZ5XKET93HPHKQHKW', 'status', 'backlog', 'in_progress', NULL, '2026-07-25 16:26:10', '2026-07-25 16:26:10.181', '2026-07-25 16:26:10.181', NULL, 'f352b98435a6a00018e45a8e2dd46675', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWTP633SM8XB302MBM', 'status', 'backlog', 'in_progress', NULL, '2026-07-25 16:26:10', '2026-07-25 16:26:10.188', '2026-07-25 16:26:10.188', NULL, '27e775276ffa828ab316d2f4e3034c1e', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZZ5XKET93HPHKQHKW', 'assigned_to', NULL, 'dudley', NULL, '2026-07-25 16:26:11', '2026-07-25 16:26:11.164', '2026-07-25 16:26:11.164', NULL, '63073f8ecec393e1eefde9b98ea63e1c', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWTP633SM8XB302MBM', 'assigned_to', NULL, 'stig', NULL, '2026-07-25 16:26:11', '2026-07-25 16:26:11.308', '2026-07-25 16:26:11.308', NULL, 'd0016aa197af14b8daab5e496d884b9b', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWTP633SM8XB302MBM', 'description', 'D-226 layer 4 (apex). A client-side AtlasAgentInterface exposing a JSON control channel so an automated agent (terminal/curl, headless Godot) can navigate the REAL Atlas UI: observe -> JSON of (a) current data state shown and (b) a walkable UI affordance tree (toggle controls: id/label/state/locked); act -> named SEMANTIC intents (select_system/open_system/select_body/open_regional/select_city/set_overlay/reset_view/back/close_atlas) backed by the same handlers a click calls (the map uses _gui_input, NOT pixel-clicks), plus get_layer_data_summary (attractor/river/basin counts as JSON without rendering). Single AtlasAgentInterface autoload/static class for a stable contract; generic Control-tree walk so economics/saves plug in later. Turns human-eyeball review into an agent QA sweep. Depends on #960 (the viewer) + the auto-pause substrate. Screenshot capture is a separate ticket (kept off the critical path).
|
||
|
||
Re-scope (2026-07-25, Si refinement + lead ruling): both cited blockers are satisfied (T-960, T-970 done) and the D-255(d) deep-rung cache cap is already built defensively for this exact consumer (step_canvas_disk_cache.gd:61 names the AtlasAgentInterface QA sweep). But D-226''s named-intent list was designed against the retired pre-D-255 continuous-zoom Atlas — the ticket''s intent surface is STALE. Implementer instruction: derive the actual intent list from the CURRENT stepped-rung API before building the wrapper, and post the derived list to the team lead for confirmation before implementation. Known mapping start (verify, don''t trust): select_system → atlas_app._on_system_selected(system_id); select_body → _on_body_selected(body); reset_view → StepCanvasViewer._reset_to_global(); set_overlay → set_overlay_visible(); back → _on_regional_back(); zoom step → _scroll_rung(direction, cursor_local); open_regional/select_city/open_system need tracing through screens/regional_screen.gd, district_screen.gd, system_screen.gd. SEQUENCING: T-1157 (stepped capture-harness redesign) needs the same walk-the-Atlas-headlessly primitive — its harness-techniques inventory (appended 2026-07-25) documents five proven eyeball-driver patterns (InputSwallower, in-process viewer-method navigation, fixed-center revisit, view-transform logging) that are the PROTOTYPE for this channel; build the T-971 intent layer as the productionization of that pattern so T-1157''s harness can consume it rather than the two designing overlapping scaffolding independently.', 'D-226 layer 4 (apex). A client-side AtlasAgentInterface exposing a JSON control channel so an automated agent (terminal/curl, headless Godot) can navigate the REAL Atlas UI: observe -> JSON of (a) current data state shown and (b) a walkable UI affordance tree (toggle controls: id/label/state/locked); act -> named SEMANTIC intents (select_system/open_system/select_body/open_regional/select_city/set_overlay/reset_view/back/close_atlas) backed by the same handlers a click calls (the map uses _gui_input, NOT pixel-clicks), plus get_layer_data_summary (attractor/river/basin counts as JSON without rendering). Single AtlasAgentInterface autoload/static class for a stable contract; generic Control-tree walk so economics/saves plug in later. Turns human-eyeball review into an agent QA sweep. Depends on #960 (the viewer) + the auto-pause substrate. Screenshot capture is a separate ticket (kept off the critical path).
|
||
|
||
Re-scope (2026-07-25, Si refinement + lead ruling): both cited blockers are satisfied (T-960, T-970 done) and the D-255(d) deep-rung cache cap is already built defensively for this exact consumer (step_canvas_disk_cache.gd:61 names the AtlasAgentInterface QA sweep). But D-226''s named-intent list was designed against the retired pre-D-255 continuous-zoom Atlas — the ticket''s intent surface is STALE. Implementer instruction: derive the actual intent list from the CURRENT stepped-rung API before building the wrapper, and post the derived list to the team lead for confirmation before implementation. Known mapping start (verify, don''t trust): select_system → atlas_app._on_system_selected(system_id); select_body → _on_body_selected(body); reset_view → StepCanvasViewer._reset_to_global(); set_overlay → set_overlay_visible(); back → _on_regional_back(); zoom step → _scroll_rung(direction, cursor_local); open_regional/select_city/open_system need tracing through screens/regional_screen.gd, district_screen.gd, system_screen.gd. SEQUENCING: T-1157 (stepped capture-harness redesign) needs the same walk-the-Atlas-headlessly primitive — its harness-techniques inventory (appended 2026-07-25) documents five proven eyeball-driver patterns (InputSwallower, in-process viewer-method navigation, fixed-center revisit, view-transform logging) that are the PROTOTYPE for this channel; build the T-971 intent layer as the productionization of that pattern so T-1157''s harness can consume it rather than the two designing overlapping scaffolding independently.
|
||
|
||
Intent-vocabulary diff vs D-226''s original list (recorded at implementation, 2026-07-25): select_city and open_regional DROPPED — post-D-255, settlements are settlement_id canvas cell values with no hit-test affordance (StepCanvasAnnotationLayer._draw_settlements() draws markers from cell data; no server get-settlement-by-id affordance, no client hit-test). A settlement-hit-test intent becomes its own ticket when a real consumer needs it — not filed speculatively. ADDED beyond D-226: open_atlas (a driver must be able to start a session), jump_to_center (the fixed-center revisit pattern proven by five T-1157-inventory eyeball drivers, now first-class via the new StepCanvasViewer.jump_to seam), and open_body replacing open_regional (Region..Chunk is one screen; descent is scroll_rung, not screen pushes). get_layer_data_summary reports the real EncodedStepCanvas fields (courses/cliffs/settlements) — D-226''s attractor/river/basin-count phrasing was retired-AtlasViewer vocabulary. Transport: in-process only this ticket; remote JSON transport is a follow-up when a remote consumer exists.', NULL, '2026-07-25 16:50:40', '2026-07-25 16:50:40.290', '2026-07-25 16:50:40.290', NULL, 'e6dfa5f5986853952eef1eac98269926', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWTP633SM8XB302MBM', 'status', 'in_progress', 'review', NULL, '2026-07-25 16:57:34', '2026-07-25 16:57:34.623', '2026-07-25 16:57:34.623', NULL, '7b2b60bf4e2ba234c7fbf9fc2fafecc9', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZZ5XKET93HPHKQHKW', 'status', 'in_progress', 'review', NULL, '2026-07-25 17:07:16', '2026-07-25 17:07:16.386', '2026-07-25 17:07:16.386', NULL, 'b4f2db9ed2405b30dc88fa45c1867506', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRWTP633SM8XB302MBM', 'status', 'review', 'done', NULL, '2026-07-25 17:36:09', '2026-07-25 17:36:09.274', '2026-07-25 17:36:09.274', NULL, 'a5c67308dab3a08d8aee193a79861f9b', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZZ5XKET93HPHKQHKW', 'status', 'review', 'done', NULL, '2026-07-25 17:56:13', '2026-07-25 17:56:13.098', '2026-07-25 17:56:13.098', NULL, 'b7fc240144b45db830e9ea0b68b21ba6', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRZ8Z6NN74YKCCRCPMR', 'description', '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.', '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.
|
||
|
||
Si refinement pass (2026-07-25, batch-5 candidate review): NEEDS-JEROEN before activation. The ticket''s own text is internally consistent (D-166 2026-06-12 trigger folded in; listed blockers T-952/T-959 both done), but "walkable exteriors" predates D-255 and the believability workstream, and three gate-criteria questions are unresolved:
|
||
|
||
(1) Is Q-123''s threshold calibration (sampling power, non-stationarity thresholds, relief/coherence floors, and the advisory->strict ratchet trigger for the D-245 gate) a prerequisite for this validation pass, or does the pass only need "mechanism exists and demonstrably fires" (T-1079''s six mechanism children T-1080..T-1085 are all done)?
|
||
|
||
(2) Do T-1116 (0 routable road edges on water-heavy bodies) and T-1098 (interstitial fill between building footprints incomplete) block "walkable" as this ticket defines it, or are they Phase-4 polish that continues in parallel per the D-166 amendment''s explicit allowance?
|
||
|
||
(3) Post-D-255, should the validation pass probe cascade output directly (aliveness_probe.rs / T-1083 harness) rather than an Atlas-eyeball check — the Atlas being presentation, not the generation under validation?
|
||
|
||
Graph note: this ticket currently has NO blocker edges to T-1079/Q-123, T-1116, or T-1098 — deliberately left unwired pending the ruling above; wire whichever the ruling designates as gating.', NULL, '2026-07-25 18:03:56', '2026-07-25 18:03:56.875', '2026-07-25 18:03:56.875', NULL, '0ffc7340a6762d24ee66afba25b268ba', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPJ910NNR5T2R9F9NWQR', 'description', '(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).', '(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).
|
||
|
||
Batch-5 Si pass correction (2026-07-25): the 2026-06-16 refinement block above is INVALIDATED by the HELD note that follows it — the sprite-centric scope (SPR/FUR prefixes, sprite catalog, /sprite-gen) contradicts the recorded direction (Trellis produces 3D .glb models; only flattened 2D content is textures). Do not implement as written. A re-scope pass (3D-model + texture catalog, manifest mirroring character-asset-organization, D-241 promotion, D-235-keyed texture naming) is running as part of batch 5; T-1052 (style bible) and T-1051 (title-only) get refinement passes in the same sweep. Sequencing per T-1049''s own note stands: this ticket''s conventions land first, T-1049/T-1053 consume them.', NULL, '2026-07-25 18:04:03', '2026-07-25 18:04:03.964', '2026-07-25 18:04:03.964', NULL, '83c179232554808ac27dc7bd7f680ff5', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRJD6EKPBQE08NA8VHP692W8', 'status', 'backlog', 'in_progress', NULL, '2026-07-25 18:04:06', '2026-07-25 18:04:06.736', '2026-07-25 18:04:06.736', NULL, '581321f1ce2faaef8636c8b2f5182716', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSM3MQ5GFSPKKFJF6GGZN8CM', 'status', 'backlog', 'ready', NULL, '2026-07-25 18:04:07', '2026-07-25 18:04:07.273', '2026-07-25 18:04:07.273', NULL, '56f337047d088a7547c30ce3f4186497', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRJD6EKPBQE08NA8VHP692W8', 'assigned_to', NULL, 'hoshe', NULL, '2026-07-25 18:04:09', '2026-07-25 18:04:09.374', '2026-07-25 18:04:09.374', NULL, '91edbb31a5c8128989e1fb19f2eedc70', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPJ910NNR5T2R9F9NWQR', 'description', '(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).
|
||
|
||
Batch-5 Si pass correction (2026-07-25): the 2026-06-16 refinement block above is INVALIDATED by the HELD note that follows it — the sprite-centric scope (SPR/FUR prefixes, sprite catalog, /sprite-gen) contradicts the recorded direction (Trellis produces 3D .glb models; only flattened 2D content is textures). Do not implement as written. A re-scope pass (3D-model + texture catalog, manifest mirroring character-asset-organization, D-241 promotion, D-235-keyed texture naming) is running as part of batch 5; T-1052 (style bible) and T-1051 (title-only) get refinement passes in the same sweep. Sequencing per T-1049''s own note stands: this ticket''s conventions land first, T-1049/T-1053 consume them.', '(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).
|
||
|
||
Batch-5 Si pass correction (2026-07-25): the 2026-06-16 refinement block above is INVALIDATED by the HELD note that follows it — the sprite-centric scope (SPR/FUR prefixes, sprite catalog, /sprite-gen) contradicts the recorded direction (Trellis produces 3D .glb models; only flattened 2D content is textures). Do not implement as written. A re-scope pass (3D-model + texture catalog, manifest mirroring character-asset-organization, D-241 promotion, D-235-keyed texture naming) is running as part of batch 5; T-1052 (style bible) and T-1051 (title-only) get refinement passes in the same sweep. Sequencing per T-1049''s own note stands: this ticket''s conventions land first, T-1049/T-1053 consume them.
|
||
|
||
Refinement (batch-5 Si pass, 2026-07-25) — SUPERSEDES the 2026-06-16 block above (sprite-centric, invalidated by D-244). READY.
|
||
|
||
CONTEXT: D-244 (confirmed, 2026-06-16) already re-scoped the catalog structure and repointed
|
||
renderer/README.md, sprite-gen SKILL.md, docs/assets/README.md, docs/assets/visual/{README,palette}.md,
|
||
and docs/assets/_templates/sprite.md (marked legacy) at the 3D-model reality. This ticket is now
|
||
narrower than its original draft: instantiate what D-244 named but did not fill in, plus author
|
||
conventions.md (net-new — no D-244 amendment touched it).
|
||
|
||
DELIVERABLE (a) — Category catalog files, per docs/assets/README.md''s already-updated structure:
|
||
- docs/assets/visual/models.md — 3D objects/props (.glb via /glb-gen). Row template TBD (see
|
||
conventions.md below) since _templates/sprite.md is explicitly legacy/retired for this use.
|
||
- docs/assets/visual/textures.md — PBR surface maps (BaseColor/Normal/Roughness) for 3D models.
|
||
- docs/assets/visual/artwork.md — flat 2D art (paintings/flags/billboards/signage) via /sprite-gen''s
|
||
repurposed 2D-artwork role.
|
||
- docs/assets/visual/icons.md — UI icons (13 SVGs already exist in client/assets/icons/ — this file
|
||
should reflect that as-built inventory, not start at zero).
|
||
- docs/assets/visual/effects.md — shaders/particles/overlays.
|
||
Each file follows docs/assets/audio/README.md''s model: per-category status table (planned/in-progress/
|
||
placeholder/final per docs/assets/README.md''s vocab), current counts. Update docs/assets/visual/README.md''s
|
||
category table counts once files exist (currently all show 0, which will stay accurate at initial creation
|
||
— do not invent placeholder rows).
|
||
ACCEPTANCE: 5 files exist, cross-linked from visual/README.md (already has the links — verify they resolve),
|
||
each with a real (possibly empty) status table matching the audio/README.md pattern.
|
||
|
||
DELIVERABLE (b) — glb-gen production path:
|
||
- Create client/assets/models/ with furniture/ and props/ subdirectories (mirroring the proven
|
||
spike layout at spikes/3dpipeline/models/{furniture,props}/) + .gitkeep in each.
|
||
- Define client/assets/models/manifest.json, schema mirroring docs/architecture/character-asset-organization.md''s
|
||
per-asset-entry pattern (that doc''s clothing/accessory entries are the closest precedent — a flat
|
||
per-item record, not per-body-type variants since environment props aren''t body-fitted). Minimum
|
||
fields: name, category (furniture|props), source_model (path under client/assets/models/), subdirectory,
|
||
status (planned/in-progress/placeholder/final — reuse the docs/assets/README.md vocab so catalog and
|
||
manifest never disagree). Promotion = repo-canonical per D-241 — an asset entering manifest.json AND
|
||
client/assets/models/ IS the promotion act; nothing stays "promoted" in spikes/.
|
||
- Update .claude/skills/glb-gen/SKILL.md — replace the "client/assets/models/ does not exist... that''s
|
||
a Phase-5 concern" paragraph (lines ~96-102) with the new path + a pointer to the manifest. NOTE:
|
||
this contradicts nothing already in D-244/T-750 — T-750''s own epic description lists furniture/props
|
||
production as Phase-4 parallel work, so populating the production path (not populating the world with
|
||
them — that''s Phase 5 per T-961) is in-scope now.
|
||
ACCEPTANCE: client/assets/models/{furniture,props}/.gitkeep exist; manifest.json schema documented
|
||
(either inline in SKILL.md or as a comment/example in the file itself, following the character
|
||
manifest''s convention); SKILL.md''s stale "does not exist" paragraph is corrected.
|
||
|
||
DELIVERABLE (c) — docs/assets/visual/conventions.md (NEW FILE — no prior art to amend):
|
||
- Model naming: <category>_<descriptor>.glb (e.g. table_baroque.glb, chair_modernist.glb) —
|
||
mirrors the spike''s existing baroque_table.glb/modernist_chair.glb pattern loosely; pick one
|
||
order and state it (category-first matches the character-asset clothing convention
|
||
<category>_<descriptor>; the spike used descriptor-first — this is a naming decision to make,
|
||
not silently pick — see lead note below on who rules it).
|
||
- Mask sidecar: <model>_mask.png, single-channel per the character-asset convention (Section 3
|
||
of character-asset-organization.md) UNLESS the item needs multi-region tinting, in which case follow
|
||
the RGBA channel-routed convention from that doc''s Section 11 (T-1089) rather than reinventing one.
|
||
- Texture naming keyed to D-235 tokens: PBR maps for building-exterior surfaces should name by
|
||
the ratified ObjectTag vocabulary (D-235 amendment, wiki/economics/object_tag_vocabulary.toml) —
|
||
e.g. concrete_wall_basecolor.png, pitched_roof_normal.png — NOT the old renderer/README.md
|
||
<model>_<direction>_<resolution>.png scheme, which is direction-indexed for the retired 4-direction
|
||
sprite render and does not apply to PBR texture maps at all (there is no "direction" for a texture,
|
||
only map type: basecolor/normal/roughness).
|
||
- Door state handling — DO NOT port a state-frame suffix convention. The 2026-06-16 draft proposed
|
||
<model>_open/<model>_closed GLB variants; this is sprite-era thinking (baked state = baked frame).
|
||
For a 3D object the door''s open/closed/locked/sealed state (T-979/T-998''s DoorSpec: Open/Closed/
|
||
TemporalWindow/Locked/Sealed) is a RUNTIME transform/animation on one door .glb, not separate baked
|
||
models — but the actual mechanism (AnimationPlayer swing vs. procedural hinge rotation vs. a
|
||
door-model convention with a named "open" bone) is a Phase-5 rendering decision (player control +
|
||
in-world rendering, per the cascade), not a Phase-4 asset-catalog concern. This ticket
|
||
should record ONLY the negative constraint (no state-frame suffix files) and defer the positive
|
||
mechanism to whichever Phase-5 ticket handles door rendering. Do not invent a runtime convention here.
|
||
- Godot TileSet resource organization — OUT OF SCOPE, removed from ticket. client/scripts/rendering/
|
||
tile_renderer.gd''s TileSet is an explicitly-labeled placeholder ("programmatic TileSet with placeholder
|
||
colored rectangles," D-014) and the cascade rule states current in-world rendering code is
|
||
"left as-is until Phase 5 — do not build on it or rip it out before then." A <tileset>/<tile_id>.tres
|
||
convention would be building on Phase-5-owned code from Phase 4. Do not author this section.
|
||
- Multi-tile footprint metadata: still relevant (a table/couch spans multiple sim tiles regardless
|
||
of sprite vs 3D) — keep this item, express as a manifest.json field (e.g. footprint_tiles: [w, h])
|
||
rather than a filename convention.
|
||
ACCEPTANCE: conventions.md exists, covers model naming / mask sidecars / D-235-keyed texture naming /
|
||
multi-tile footprint metadata; explicitly states the door-state and TileSet items are deferred (with
|
||
reasons) rather than silently omitted, so a future refinement pass doesn''t have to re-derive why.
|
||
|
||
SEQUENCING (unchanged from 2026-06-16 note): T-1053 (araminta briefing rewrite) softly depends on this
|
||
catalog. T-1049''s per-class stories reference these conventions — this ticket lands first / concurrently.
|
||
|
||
Lead note (batch-5 activation): the model-naming-order call (category-first vs descriptor-first) is
|
||
delegated to araminta (art seat) this batch — her ruling lands in conventions.md with a one-line
|
||
rationale; surfaced to Jeroen in the batch report for cheap veto. VERDICT: READY.', NULL, '2026-07-25 18:11:31', '2026-07-25 18:11:31.588', '2026-07-25 18:11:31.588', NULL, '538f0887a4125773b49a88dcdd0b99ff', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPV39JX54HYP83RZJFDM', 'description', '(description follows in first append)', '(description follows in first append)
|
||
|
||
Refinement (batch-5 Si pass, 2026-07-25) — READY.
|
||
|
||
CURRENT STATE: docs/assets/visual/palette.md exists as a STUB (correctly re-scoped by D-244 — no
|
||
sprite-era content survives in it) — 4 bullets: camera angle (D-019, now superseded by D-148 for
|
||
gameplay — palette.md''s bullet is stale and must be corrected), entity colors (D-033), environmental
|
||
neutrality (D-045), "functional warmth." It explicitly defers to "art direction workshop synthesis and
|
||
first visual sprint" — this ticket IS that synthesis pass for Phase 4.
|
||
|
||
WHAT D-235 ALREADY FIXES (do not re-litigate): the building-exterior material/roof/facade/street
|
||
vocabulary (WallMaterial/RoofForm/FacadeRhythm/StreetSurface, ratified as the 28-template
|
||
architecture_trait_catalog.toml / wiki/economics/object_tag_vocabulary.toml) and the fallback-to-generic
|
||
mechanism. D-235 is the LOGICAL token layer ("what material is this wall") — Phase 4+ scope per its own
|
||
Implementation note ("textured render + the bulk of the theme library are Phase 5+"). T-1052 is the
|
||
RENDERED-LOOK layer on top: given a WallMaterial token, what does concrete_wall actually look like
|
||
(hue range, texture grain, weathering baseline) when art is eventually produced against it.
|
||
|
||
WHAT T-1052 MUST STILL AUTHOR (net-new, no existing decision covers this):
|
||
- Correct the camera-angle bullet: D-148 (30 deg low-angle Camera3D, supersedes D-019) is the GAMEPLAY
|
||
camera; D-019''s -72.5 deg survives only for the offline renderer (2D-artwork / retired sprite mode,
|
||
per renderer/README.md). palette.md''s current bullet conflates these — fix it to name both and
|
||
which applies where.
|
||
- A concrete color/material register for the D-235 token vocabulary: not new tokens, but the RANGE
|
||
each token maps to (e.g. "stone_wall reads as warm grey-tan, not cool grey" / "corrugated_metal
|
||
weathers to rust-orange, not staying silver") — the thing D-235 explicitly parked for Phase 5+ art
|
||
production but which a style bible can pre-specify so future asset generation has a target.
|
||
- Reconcile with docs/design/visual-grammar-v01.md and docs/workshops/art-direction-mood-board/
|
||
workshop-outcomes.md (both pre-cascade, v0.1-era, sprite-framed) — extract what survives (color
|
||
relationships, "functional warmth" identity, D-033 palette) vs what''s superseded by D-235/D-244
|
||
(era-based material ladder — explicitly retired by D-235''s own text: "Era is NOT a material filter
|
||
here"). Do not leave two contradictory style documents live without a note in one pointing at the
|
||
other''s supersession.
|
||
- Texture "grain"/rendering treatment for the D-244 3D-object reality: since objects are lit 3D meshes
|
||
now (not flat sprite fills), the style bible should say something about the toon/PBR balance —
|
||
precedent exists in client/assets/characters/shaders/ (toon.gdshader, toon_masked.gdshader,
|
||
outline.gdshader) and the glb-gen postprocess convention (roughness=1.0/specular=0.0 "for toon
|
||
compatibility" per .claude/skills/glb-gen/SKILL.md''s setup_materials() note). Confirm whether
|
||
environment props share this toon treatment with characters, or diverge — this is a real open
|
||
question the style bible should answer, not assume.
|
||
|
||
ACCEPTANCE: docs/assets/visual/palette.md is no longer a stub; camera-angle bullet corrected;
|
||
color/material register for D-235 tokens documented; toon-vs-PBR treatment for props stated;
|
||
supersession relationship to visual-grammar-v01.md / workshop-outcomes.md is explicit (either by
|
||
archiving/marking those superseded, or by palette.md stating exactly what it inherits from each).
|
||
|
||
Lead note (batch-5 activation): the toon-vs-PBR treatment call for environment props is delegated to
|
||
araminta (art seat) this batch — her ruling lands in palette.md with rationale; surfaced to Jeroen in
|
||
the batch report for cheap veto. VERDICT: READY.', NULL, '2026-07-25 18:11:34', '2026-07-25 18:11:34.859', '2026-07-25 18:11:34.859', NULL, '3a08af26c8f04bdd4ecef0b4a2fcd115', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPPHC9FZ4T0GNKR615PR', 'description', '(description follows in first append)', '(description follows in first append)
|
||
|
||
Refinement (batch-5 Si pass, 2026-07-25) — GAPS. Formally deferred rather than refined into an
|
||
actionable brief-writing task now.
|
||
|
||
WHY: T-1051 was filed as a child of T-1049''s per-class breakdown (the fable-ous.md audit T-1049 cites,
|
||
2026-06-12). T-1049 itself is HELD pending the same sprite-to-3D re-scope as T-1050 (its "Refinement
|
||
2026-06-16 — READY" block still frames the per-class stories, briefs, and catalog files in sprite-era
|
||
language, and its own text says "sequence T-1049 to consume T-1050''s conventions where they overlap" —
|
||
so T-1049 cannot be un-held before T-1050 lands). T-1051 is one layer further down that same
|
||
dependency: it cannot be meaningfully scoped (what does a "one-page brief" even template against?)
|
||
until (1) T-1050 lands conventions.md + the catalog structure a brief would reference, AND (2) T-1049
|
||
is re-scoped and un-held (it owns the per-class story breakdown T-1051 is part of).
|
||
|
||
Zero repo hits exist for lamp posts, barns, TVs, or billboards beyond the T-750 epic description text
|
||
(confirmed by T-1049''s own audit matrix) — there is no existing partial work this ticket would be
|
||
resuming, so there is no cost to deferring it cleanly.
|
||
|
||
DISPOSITION: blocker edge wired (T-1051 blocked-by T-1049). When T-1049 is re-scoped (a future Si
|
||
pass, after T-1050 lands), that re-scope explicitly decides whether lamp posts/barns/TVs/billboards
|
||
get real briefs or a formal deferral note (T-1049''s existing block already leaned toward "explicitly
|
||
record which classes are deferred" for cars via Q-067 — the same treatment likely applies to these
|
||
four, but that is T-1049''s call when re-scoped, not this ticket''s in isolation).', NULL, '2026-07-25 18:11:38', '2026-07-25 18:11:38.173', '2026-07-25 18:11:38.173', NULL, '8567ca57e67996983e28229cb470dbd4', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPJ910NNR5T2R9F9NWQR', 'status', 'backlog', 'in_progress', NULL, '2026-07-25 18:11:42', '2026-07-25 18:11:42.942', '2026-07-25 18:11:42.942', NULL, '97221c4a7a5aa2ff6e522b450335292d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPV39JX54HYP83RZJFDM', 'status', 'backlog', 'in_progress', NULL, '2026-07-25 18:11:42', '2026-07-25 18:11:42.948', '2026-07-25 18:11:42.948', NULL, '613156e91577043373205250f21a72cd', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPJ910NNR5T2R9F9NWQR', 'assigned_to', NULL, 'justine', NULL, '2026-07-25 18:11:45', '2026-07-25 18:11:45.571', '2026-07-25 18:11:45.571', NULL, '7fe3851d234f1cafb2b4fc70c1f5eed8', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPV39JX54HYP83RZJFDM', 'assigned_to', NULL, 'araminta', NULL, '2026-07-25 18:11:46', '2026-07-25 18:11:46.095', '2026-07-25 18:11:46.095', NULL, '0d1336d72b0807fe85c054696e914350', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPV39JX54HYP83RZJFDM', 'status', 'in_progress', 'review', NULL, '2026-07-25 18:17:34', '2026-07-25 18:17:34.364', '2026-07-25 18:17:34.364', NULL, 'a903761710732a5f62b742cc7ca4acac', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPJ910NNR5T2R9F9NWQR', 'status', 'in_progress', 'review', NULL, '2026-07-25 18:19:48', '2026-07-25 18:19:48.053', '2026-07-25 18:19:48.053', NULL, '2fa6ce22c32b396a2ea7ac1dd6f64dc0', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSHSYM96N2M9GJTQMF58E4WC', 'description', 'Flagged by stig during the T-1189/T-1192 round (2026-07-25): test_step_canvas_viewer.gd has no injected disk-cache-root seam (unlike test_step_canvas_request.gd, which injects a disposable root), so viewer tests that exercise the disk-cache path against a real-looking body_id (e.g. GJ1c) read/write the REAL user://atlas_cache/ shared across runs — a stale real entry from earlier manual sessions can leak into test behavior. Current mitigation (used by the new T-1189/T-1192 tests and the existing sweep smoke test): distinctive synthetic body_ids. Proper fix: give the viewer suite the same injectable cache-root seam the request suite has (constructor/setter injection through StepCanvasRequest), and migrate the synthetic-body_id tests onto it. Small, test-only.', 'Flagged by stig during the T-1189/T-1192 round (2026-07-25): test_step_canvas_viewer.gd has no injected disk-cache-root seam (unlike test_step_canvas_request.gd, which injects a disposable root), so viewer tests that exercise the disk-cache path against a real-looking body_id (e.g. GJ1c) read/write the REAL user://atlas_cache/ shared across runs — a stale real entry from earlier manual sessions can leak into test behavior. Current mitigation (used by the new T-1189/T-1192 tests and the existing sweep smoke test): distinctive synthetic body_ids. Proper fix: give the viewer suite the same injectable cache-root seam the request suite has (constructor/setter injection through StepCanvasRequest), and migrate the synthetic-body_id tests onto it. Small, test-only.
|
||
|
||
First slice landed 2026-07-25 (main, 9ac98542d) via a live incident: PR #211''s gate failed on test_step_canvas_viewer''s two before-any-canvas tests because user://atlas_cache/ is machine-shared (every worktree gate, live capture driver, and play session write the same directory) and the T-1183 disk lookup short-circuits before test_mode''s no-op IPC — a concurrent GJ380c Global live capture (T-1157 eyeball work) warmed the exact key the tests assume cold. Fix: StepCanvasViewer.disk_cache_root_override threading into StepCanvasRequest''s existing test-injection seam; viewer + legend suites route construction through _make_viewer() helpers pinning isolated roots. REMAINING for this ticket: screen-constructed viewers (RegionalScreen builds its viewer internally — no override path), and any future suite constructing viewers directly should use the helper pattern; consider a gdUnit-wide guard (e.g. a shared test base or a lint) so new suites cannot silently ride the shared root.', NULL, '2026-07-25 18:45:59', '2026-07-25 18:45:59.847', '2026-07-25 18:45:59.847', NULL, 'dd331004eee53f809c993e6845b52cbd', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPJ910NNR5T2R9F9NWQR', 'status', 'review', 'done', NULL, '2026-07-25 18:55:08', '2026-07-25 18:55:08.780', '2026-07-25 18:55:08.780', NULL, '544c6b5e89dafda431434ef0a9525881', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPV39JX54HYP83RZJFDM', 'status', 'review', 'done', NULL, '2026-07-25 18:55:08', '2026-07-25 18:55:08.787', '2026-07-25 18:55:08.787', NULL, '1ee2a69f3be3f8cc551a4d9c725b18f5', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPE8FR7TGEM7X6QVPV4M', 'description', '(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).', '(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).
|
||
|
||
Refinement (batch-6 Si pass, 2026-07-25) — SUPERSEDES the 2026-06-16 READY block
|
||
(sprite-era, invalidated by D-244) and the 2026-06-16 HELD note. T-1050 (catalog +
|
||
conventions.md + manifest.json) and T-1052 (palette.md style bible) are both DONE
|
||
(PR #211, merged 2026-07-25) — the conventions this ticket needed to consume now
|
||
exist and are read, not hypothetical.
|
||
|
||
SCOPE, 3D REALITY: T-961 breaks into per-asset-class stories, each gated on a
|
||
one-page brief. A "written brief" is now a short doc that states, per class:
|
||
(1) scope — which manifest category (furniture|props) and which D-235 ObjectTag
|
||
axis if any; (2) visual reference — cites palette.md §3''s hue/grain/weathering
|
||
register for the relevant token(s), or palette.md §2 toon/PBR default for classes
|
||
with no D-235 token; (3) naming — conventions.md §1 model naming
|
||
(<category>_<descriptor>.glb), §2 mask sidecar if tintable, §4 footprint_tiles if
|
||
multi-tile; (4) generation path — /image-gen concept → /glb-gen (Trellis) →
|
||
postprocess → promotion into client/assets/models/{furniture,props}/ +
|
||
manifest.json entry (conventions.md, models.md); (5) acceptance — N assets at
|
||
"planned" status registered in the manifest with a real manifest.json entry,
|
||
status flips as production proceeds (models.md''s shared status vocab).
|
||
|
||
BRIEF TEMPLATE (create docs/assets/_templates/asset-brief.md): the five headers
|
||
above (scope / visual reference / naming / gen path / acceptance), one page,
|
||
adopting docs/_templates/design.md frontmatter. Do NOT reuse _templates/sprite.md
|
||
(SPR/FUR/TILE/ICO/FX prefixes) — explicitly retired by D-244/T-1050.
|
||
|
||
CLASS LIST — station walls, rural walls, doors, floors, furniture/props already
|
||
have partial prior art (station walls: wall_structural GLB exists unrendered per
|
||
the 2026-06-12 audit matrix; doors: DoorSpec logical model exists, T-979/T-998;
|
||
floors: D-228 FloorMaterial axis exists) — each gets a real story + brief, citing
|
||
its relevant D-235 axis (wall/roof/facade/street) or, for doors/floors/furniture,
|
||
the non-ObjectTag conventions (mask sidecars, footprint_tiles).
|
||
|
||
STREET FURNITURE / SIGNAGE-SCREENS / RURAL STRUCTURES (lamp posts, barns,
|
||
TVs, billboards — T-1051''s four classes): RECOMMEND FORMAL DEFERRAL, not real
|
||
briefs, this batch. Rationale: Phase 4''s deliverable is "deterministic
|
||
walkable-world data + per-layer Atlas maps + asset catalog" (cascade table) —
|
||
outside-in generation (D-166) needs building EXTERIOR templates
|
||
(D-235 wall/roof/facade/street axes) to make districts/blocks walkable and
|
||
Atlas-legible. Lamp posts (street furniture), TVs/billboards (signage/screens
|
||
placed as interior or exterior set-dressing), and barns (a rural building
|
||
*type*, not a wall/roof/facade axis token) are furniture-tier detail objects
|
||
that populate a walkable exterior once it exists — they read as Phase 6
|
||
"detail coloring / room-level population" (cascade table) or, at best, late
|
||
Phase 4 polish, not blocking asset classes for getting the world walkable.
|
||
Zero repo hits exist for any of the four beyond epic text (T-1049''s own 2026-06-12
|
||
audit matrix, unchanged) — there is no partial work to protect by deferring.
|
||
Treat identically to Q-067''s car deferral: file a deferral note on the story
|
||
(or fold into one placeholder story "T-1051 classes — deferred pending Phase 4
|
||
exterior-generation completion"), do not write real briefs now. Distinguish from
|
||
cars only in degree, not in kind — Q-067 is a still-open decision question
|
||
(vehicle simulation is a bigger unresolved design surface); the T-1051 four are
|
||
simpler set-dressing whose deferral needs no open question, just a scope note,
|
||
because nothing about their eventual brief depends on an undecided mechanic.
|
||
|
||
Q-119 (generic-parent placeholder set as milestone-0) is STILL OPEN (unresolved
|
||
as of this pass) — unchanged from the prior block: not a blocker, sequencing-only.
|
||
Each relevant story notes the generic_wall/roof/facade/street (+ generic
|
||
door/floor/furniture) parents as milestone-0 IF Q-119 resolves yes.
|
||
|
||
READ before filing: docs/assets/visual/{conventions,palette,models,textures,
|
||
artwork}.md (T-1050/T-1052, merged), D-244, D-257, D-235 (ratified token list),
|
||
D-243 (footprint unit), docs/architecture/character-asset-organization.md
|
||
(mask/manifest precedent).
|
||
|
||
VERDICT: READY (activation = batch 6; the T-1051 deferral recommendation above is
|
||
ratified at activation, then T-1051 is updated to match the ruling this ticket records).', NULL, '2026-07-25 19:00:33', '2026-07-25 19:00:33.469', '2026-07-25 19:00:33.469', NULL, 'f74a4367cd0a4eb2664f4d575e7d31c2', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPZ0ZTM1QQXD5K972CMM', 'description', '(description follows in first append)', '(description follows in first append)
|
||
|
||
Refinement (batch-6 Si pass, 2026-07-25) — READY.
|
||
|
||
WHAT''S WRONG WITH THE CURRENT BRIEFING: frozen at the 2026-03-13 v0.2 pivot.
|
||
(1) Frames the role around "v0.2 Pivot — Key Changes" — v0.2 is formally dropped
|
||
("No scoping negotiations. Build the base systems fully"), so the framing section
|
||
is obsolete, not just outdated. (2) Assumes the sprite-era pipeline throughout
|
||
("Phase 1-3 placeholder art pipeline," "sprite replacements" in Phase 4) —
|
||
contradicted by D-244 (3D objects in-world, no per-object sprite layer) and D-149
|
||
(live 3D characters). (3) Cites D-019 as simply "top-down art style" with no note
|
||
that D-148 superseded it for gameplay (palette.md §1 had to correct exactly this
|
||
conflation in its own stub — the briefing repeats the same error). (4) Zone visual
|
||
grammar / tile palette framing predates D-235''s ObjectTag vocabulary and D-232''s
|
||
trait-template catalog entirely. (5) Character customisation section (D-126,
|
||
Q-WTF-039/040) predates the shipped D-159–D-164 body-type + slot-compositing
|
||
system and the wardrobe/garment-token pipeline — describes a design question that
|
||
has since been built. (6) No mention of the Atlas at all (D-255 stepped ladder,
|
||
D-169/D-170 implant UI) despite araminta being a named co-designer of D-255''s
|
||
named-feature encoding/payload schema/lakes work.
|
||
|
||
WHAT THE REWRITE MUST CONTAIN:
|
||
- Role framing: visual art direction for the Phase-4 asset pipeline + Atlas
|
||
map-art rendering (not "generator spike prerequisites").
|
||
- palette.md (T-1052, merged) as the SINGLE LIVE STYLE AUTHORITY — point to it,
|
||
do not restate camera/color/material content (avoids a second drifting copy;
|
||
visual-grammar-v01.md / workshop-outcomes.md supersession is palette.md §5''s
|
||
to state, the briefing defers).
|
||
- conventions.md (T-1050, merged) for naming/mask/manifest mechanics — note the
|
||
category-first naming ruling (conventions.md §1) and the D-257 toon/PBR ruling
|
||
with glazing carve-out as HER standing rulings she''ll be asked to extend.
|
||
- D-235 ObjectTag vocabulary as the logical layer she renders a look on top of —
|
||
co-maintained with Miri per D-235''s own text.
|
||
- The character wardrobe pipeline (character-asset-organization.md) as the proven
|
||
reference model conventions.md imitates (mask sidecars, manifest schema).
|
||
- D-255 stepped Atlas as active/ongoing work she co-designed.
|
||
- Current open items: T-1049 (per-class asset stories, re-scoped this batch), the
|
||
D-257 glazing shader implementation (unassigned per palette.md §2.3), Q-119
|
||
(generic-parent milestone question, hers to weigh in on per D-235
|
||
co-maintenance).
|
||
- Drop: v0.2 pivot section, Q-WTF-039/040, tycoon-bookmark/apartment-wakeup
|
||
framing, and the v0.2-era decision list (D-114/D-117/D-119/D-122/D-128/D-131/
|
||
D-135) — verify each against current decision status before dropping outright;
|
||
a few (D-033 entity color, D-126 customisation dimensions) may still have live
|
||
sub-parts even though the surrounding section is obsolete.
|
||
|
||
ACCEPTANCE: rewritten briefing reflects the current Phase-4 landscape (D-235,
|
||
D-244, D-257, D-255), points to palette.md/conventions.md as live authorities
|
||
rather than duplicating content, drops v0.2-pivot and superseded-question
|
||
framing, lists araminta''s actual current/open tickets.
|
||
|
||
SEQUENCING: independent of T-1049 (different files, no shared input) — both can
|
||
run in the same batch.', NULL, '2026-07-25 19:00:36', '2026-07-25 19:00:36.464', '2026-07-25 19:00:36.464', NULL, 'ebe504fa1213997aad9ae74f82212f6f', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSM3MQ5GFSPKKFJF6GGZN8CM', 'description', 'Araminta''s PR #192 companion note, kept open by her PR #208 ruling (option b): the Quarter-vs-District relief-differentiation check was accepted for the T-1160 merge on a plains/river substitution (GJ380c world center -17723392,-10532864 — Quarter clearly shows finer higher-frequency texture than District), but plains texture and jagged tectonic relief are different visual regimes and the sharper case still needs its own capture. Task: identify the body pool with tectonics:high (or planet_class values mapping to TectonicClass::Volcanic/Active) and RECORD the pool in this ticket first — the PR #208 eyeball proved GJ380c/GJ820Bc are both tectonics:low via exhaustive two-Global color scans, don''t re-run that search blind — then capture quarter-relief vs district-relief at a true Alpine/MountainPass crop (MorphologyZone 13/14) at the same world center, matched crop, and have Araminta judge the differentiation. Reuse the pr208_driver fixed-center --step protocol (T-1157 harness inventory). Related: T-1160, PR #192, PR #208.', 'Araminta''s PR #192 companion note, kept open by her PR #208 ruling (option b): the Quarter-vs-District relief-differentiation check was accepted for the T-1160 merge on a plains/river substitution (GJ380c world center -17723392,-10532864 — Quarter clearly shows finer higher-frequency texture than District), but plains texture and jagged tectonic relief are different visual regimes and the sharper case still needs its own capture. Task: identify the body pool with tectonics:high (or planet_class values mapping to TectonicClass::Volcanic/Active) and RECORD the pool in this ticket first — the PR #208 eyeball proved GJ380c/GJ820Bc are both tectonics:low via exhaustive two-Global color scans, don''t re-run that search blind — then capture quarter-relief vs district-relief at a true Alpine/MountainPass crop (MorphologyZone 13/14) at the same world center, matched crop, and have Araminta judge the differentiation. Reuse the pr208_driver fixed-center --step protocol (T-1157 harness inventory). Related: T-1160, PR #192, PR #208.
|
||
|
||
POOL RECORDED (2026-07-25, read-only survey per this ticket''s own first step —
|
||
do not re-run the search blind).
|
||
|
||
MAPPING MECHANISM: server/src/atlas/district_profile.rs:296-312
|
||
derive_tectonic_class(): BodyParams::tectonic_activity authored override first
|
||
("volcanic"/"active"/"tidally_forced", NO column in current systems.db schema and
|
||
no authored overrides in the wiki TOMLs — so today the override path is dead),
|
||
else planet_class fallback: "volcanic" → Volcanic; "oceanic"/"ocean_world" →
|
||
Active; everything else → Stable. Sanity anchors agree with the PR #208 eyeball:
|
||
GJ380c (arid) and GJ820Bc (arid) both → Stable.
|
||
|
||
THE FULL POOL (7 bodies):
|
||
- Volcanic: GJ0c (Venus, no heightmap), GJ0f-1 (Io, no heightmap), GJ4056b
|
||
(heightmap, airless, relief_energy_q=1.0), GJ660Ad (Seongho Prime, heightmap,
|
||
thin atmosphere, relief_energy_q=1.0)
|
||
- Active: GJ1002b (Caparica, heightmap, island world, standard atmosphere),
|
||
GJ103c (Vlieland, heightmap, island world, standard atmosphere), GJ447c
|
||
(Marevna, heightmap, ocean world) — all relief_energy_q=0.70 per D-239 §5.
|
||
|
||
CAPTURE RECOMMENDATION (lead): for the true Alpine/MountainPass (MorphologyZone
|
||
13/14) crop this ticket wants, the Active terrestrial island worlds GJ1002b and
|
||
GJ103c are the primary candidates (coastal orogeny, standard climate — closest
|
||
analogue to the GJ380c plains/river substitution being replaced). The Volcanic
|
||
pair (GJ4056b, GJ660Ad) are alternates with maximum relief energy but
|
||
airless/thin atmospheres — shield/lava-field morphology, likely NOT
|
||
Alpine-classed; use only if the Active pair fails to produce MorphologyZone
|
||
13/14 crops. GJ0c/GJ0f-1 lack terrain_reference and cannot open in the Atlas.', NULL, '2026-07-25 19:00:39', '2026-07-25 19:00:39.731', '2026-07-25 19:00:39.731', NULL, '194ab5efa1ff3b059c0296830334f801', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRJD6EKPBQE08NA8VHP692W8', 'status', 'in_progress', 'review', NULL, '2026-07-25 20:13:40', '2026-07-25 20:13:40.919', '2026-07-25 20:13:40.919', NULL, '01a486c57de6c9de11129fde26a19a2f', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FRJD6EKPBQE08NA8VHP692W8', 'status', 'review', 'done', NULL, '2026-07-25 20:38:51', '2026-07-25 20:38:51.996', '2026-07-25 20:38:51.996', NULL, 'd57c37ca9e91c2c6c18d711dc2d65ec7', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSM3MQ5GFSPKKFJF6GGZN8CM', 'status', 'ready', 'in_progress', NULL, '2026-07-25 20:42:13', '2026-07-25 20:42:13.772', '2026-07-25 20:42:13.772', NULL, '906a8611cbd707cc2eea1c5a9d5dff2e', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSM3MQ5GFSPKKFJF6GGZN8CM', 'assigned_to', NULL, 'hoshe', NULL, '2026-07-25 20:42:14', '2026-07-25 20:42:14.404', '2026-07-25 20:42:14.404', NULL, '92d2b9c79a4dc2f8b43b2ad25b6a8464', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSM3MQ5GFSPKKFJF6GGZN8CM', 'description', 'Araminta''s PR #192 companion note, kept open by her PR #208 ruling (option b): the Quarter-vs-District relief-differentiation check was accepted for the T-1160 merge on a plains/river substitution (GJ380c world center -17723392,-10532864 — Quarter clearly shows finer higher-frequency texture than District), but plains texture and jagged tectonic relief are different visual regimes and the sharper case still needs its own capture. Task: identify the body pool with tectonics:high (or planet_class values mapping to TectonicClass::Volcanic/Active) and RECORD the pool in this ticket first — the PR #208 eyeball proved GJ380c/GJ820Bc are both tectonics:low via exhaustive two-Global color scans, don''t re-run that search blind — then capture quarter-relief vs district-relief at a true Alpine/MountainPass crop (MorphologyZone 13/14) at the same world center, matched crop, and have Araminta judge the differentiation. Reuse the pr208_driver fixed-center --step protocol (T-1157 harness inventory). Related: T-1160, PR #192, PR #208.
|
||
|
||
POOL RECORDED (2026-07-25, read-only survey per this ticket''s own first step —
|
||
do not re-run the search blind).
|
||
|
||
MAPPING MECHANISM: server/src/atlas/district_profile.rs:296-312
|
||
derive_tectonic_class(): BodyParams::tectonic_activity authored override first
|
||
("volcanic"/"active"/"tidally_forced", NO column in current systems.db schema and
|
||
no authored overrides in the wiki TOMLs — so today the override path is dead),
|
||
else planet_class fallback: "volcanic" → Volcanic; "oceanic"/"ocean_world" →
|
||
Active; everything else → Stable. Sanity anchors agree with the PR #208 eyeball:
|
||
GJ380c (arid) and GJ820Bc (arid) both → Stable.
|
||
|
||
THE FULL POOL (7 bodies):
|
||
- Volcanic: GJ0c (Venus, no heightmap), GJ0f-1 (Io, no heightmap), GJ4056b
|
||
(heightmap, airless, relief_energy_q=1.0), GJ660Ad (Seongho Prime, heightmap,
|
||
thin atmosphere, relief_energy_q=1.0)
|
||
- Active: GJ1002b (Caparica, heightmap, island world, standard atmosphere),
|
||
GJ103c (Vlieland, heightmap, island world, standard atmosphere), GJ447c
|
||
(Marevna, heightmap, ocean world) — all relief_energy_q=0.70 per D-239 §5.
|
||
|
||
CAPTURE RECOMMENDATION (lead): for the true Alpine/MountainPass (MorphologyZone
|
||
13/14) crop this ticket wants, the Active terrestrial island worlds GJ1002b and
|
||
GJ103c are the primary candidates (coastal orogeny, standard climate — closest
|
||
analogue to the GJ380c plains/river substitution being replaced). The Volcanic
|
||
pair (GJ4056b, GJ660Ad) are alternates with maximum relief energy but
|
||
airless/thin atmospheres — shield/lava-field morphology, likely NOT
|
||
Alpine-classed; use only if the Active pair fails to produce MorphologyZone
|
||
13/14 crops. GJ0c/GJ0f-1 lack terrain_reference and cannot open in the Atlas.', 'Araminta''s PR #192 companion note, kept open by her PR #208 ruling (option b): the Quarter-vs-District relief-differentiation check was accepted for the T-1160 merge on a plains/river substitution (GJ380c world center -17723392,-10532864 — Quarter clearly shows finer higher-frequency texture than District), but plains texture and jagged tectonic relief are different visual regimes and the sharper case still needs its own capture. Task: identify the body pool with tectonics:high (or planet_class values mapping to TectonicClass::Volcanic/Active) and RECORD the pool in this ticket first — the PR #208 eyeball proved GJ380c/GJ820Bc are both tectonics:low via exhaustive two-Global color scans, don''t re-run that search blind — then capture quarter-relief vs district-relief at a true Alpine/MountainPass crop (MorphologyZone 13/14) at the same world center, matched crop, and have Araminta judge the differentiation. Reuse the pr208_driver fixed-center --step protocol (T-1157 harness inventory). Related: T-1160, PR #192, PR #208.
|
||
|
||
POOL RECORDED (2026-07-25, read-only survey per this ticket''s own first step —
|
||
do not re-run the search blind).
|
||
|
||
MAPPING MECHANISM: server/src/atlas/district_profile.rs:296-312
|
||
derive_tectonic_class(): BodyParams::tectonic_activity authored override first
|
||
("volcanic"/"active"/"tidally_forced", NO column in current systems.db schema and
|
||
no authored overrides in the wiki TOMLs — so today the override path is dead),
|
||
else planet_class fallback: "volcanic" → Volcanic; "oceanic"/"ocean_world" →
|
||
Active; everything else → Stable. Sanity anchors agree with the PR #208 eyeball:
|
||
GJ380c (arid) and GJ820Bc (arid) both → Stable.
|
||
|
||
THE FULL POOL (7 bodies):
|
||
- Volcanic: GJ0c (Venus, no heightmap), GJ0f-1 (Io, no heightmap), GJ4056b
|
||
(heightmap, airless, relief_energy_q=1.0), GJ660Ad (Seongho Prime, heightmap,
|
||
thin atmosphere, relief_energy_q=1.0)
|
||
- Active: GJ1002b (Caparica, heightmap, island world, standard atmosphere),
|
||
GJ103c (Vlieland, heightmap, island world, standard atmosphere), GJ447c
|
||
(Marevna, heightmap, ocean world) — all relief_energy_q=0.70 per D-239 §5.
|
||
|
||
CAPTURE RECOMMENDATION (lead): for the true Alpine/MountainPass (MorphologyZone
|
||
13/14) crop this ticket wants, the Active terrestrial island worlds GJ1002b and
|
||
GJ103c are the primary candidates (coastal orogeny, standard climate — closest
|
||
analogue to the GJ380c plains/river substitution being replaced). The Volcanic
|
||
pair (GJ4056b, GJ660Ad) are alternates with maximum relief energy but
|
||
airless/thin atmospheres — shield/lava-field morphology, likely NOT
|
||
Alpine-classed; use only if the Active pair fails to produce MorphologyZone
|
||
13/14 crops. GJ0c/GJ0f-1 lack terrain_reference and cannot open in the Atlas.
|
||
|
||
CAPTURE CENTER PROBED (2026-07-25, server-side scan; scratch bins deleted, tree
|
||
verified clean). CHOSEN BODY: GJ1002b (Caparica). GJ103c is a NEGATIVE finding —
|
||
a full-body stride-8 scan (2,246,140 districts sampled) found only 4 isolated
|
||
MorphologyZone-13/14 cells, none clustering; it is not a viable capture body.
|
||
No Volcanic-pair fallback needed.
|
||
|
||
PRIMARY CENTER (feed to StepCanvasViewer.jump_to, world metres):
|
||
(385024, -598016) [district grid (188, -292) x DISTRICT_M=2048]
|
||
5x5-district neighborhood 25/25 Alpine/MountainPass; +/-40 km box 452/1681
|
||
(26.9%) hits; elev_q 50-100 — reads as a range, not speckle.
|
||
|
||
ALTERNATES on GJ1002b: (6973440, 1361920) 23/25 dense, 18.9% box;
|
||
(2488320, 129024) 24/25, 7.9%; (35919872, -6862848) 23/25, 16.2%;
|
||
(29184000, -4837376) 19/25, 18.6%.
|
||
|
||
METHOD (reproducible): derive_district() per district (district_profile.rs:1769)
|
||
over cascade_snapshot_for_body(world_seed=42) + run_layer1 TerrainAnalysis —
|
||
identical to aliveness_probe''s --render path (aliveness_probe.rs:72-85). Gate
|
||
verified at district_profile.rs:594-712: Alpine(14) = slope_q>=40 && elev_q>=75
|
||
&& ocean_fraction_q<20; MountainPass(13) same family, 50<=elev_q<75. Coarse
|
||
stride-8 full-body scan -> union-find clustering -> dense stride-1 5x5-window
|
||
refine. Both bodies confirmed planet_class=''oceanic'' -> TectonicClass::Active.', NULL, '2026-07-25 20:47:03', '2026-07-25 20:47:03.484', '2026-07-25 20:47:03.484', NULL, '5fe51061ab85360f1ab429e104beec8d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSM3MQ5GFSPKKFJF6GGZN8CM', 'description', 'Araminta''s PR #192 companion note, kept open by her PR #208 ruling (option b): the Quarter-vs-District relief-differentiation check was accepted for the T-1160 merge on a plains/river substitution (GJ380c world center -17723392,-10532864 — Quarter clearly shows finer higher-frequency texture than District), but plains texture and jagged tectonic relief are different visual regimes and the sharper case still needs its own capture. Task: identify the body pool with tectonics:high (or planet_class values mapping to TectonicClass::Volcanic/Active) and RECORD the pool in this ticket first — the PR #208 eyeball proved GJ380c/GJ820Bc are both tectonics:low via exhaustive two-Global color scans, don''t re-run that search blind — then capture quarter-relief vs district-relief at a true Alpine/MountainPass crop (MorphologyZone 13/14) at the same world center, matched crop, and have Araminta judge the differentiation. Reuse the pr208_driver fixed-center --step protocol (T-1157 harness inventory). Related: T-1160, PR #192, PR #208.
|
||
|
||
POOL RECORDED (2026-07-25, read-only survey per this ticket''s own first step —
|
||
do not re-run the search blind).
|
||
|
||
MAPPING MECHANISM: server/src/atlas/district_profile.rs:296-312
|
||
derive_tectonic_class(): BodyParams::tectonic_activity authored override first
|
||
("volcanic"/"active"/"tidally_forced", NO column in current systems.db schema and
|
||
no authored overrides in the wiki TOMLs — so today the override path is dead),
|
||
else planet_class fallback: "volcanic" → Volcanic; "oceanic"/"ocean_world" →
|
||
Active; everything else → Stable. Sanity anchors agree with the PR #208 eyeball:
|
||
GJ380c (arid) and GJ820Bc (arid) both → Stable.
|
||
|
||
THE FULL POOL (7 bodies):
|
||
- Volcanic: GJ0c (Venus, no heightmap), GJ0f-1 (Io, no heightmap), GJ4056b
|
||
(heightmap, airless, relief_energy_q=1.0), GJ660Ad (Seongho Prime, heightmap,
|
||
thin atmosphere, relief_energy_q=1.0)
|
||
- Active: GJ1002b (Caparica, heightmap, island world, standard atmosphere),
|
||
GJ103c (Vlieland, heightmap, island world, standard atmosphere), GJ447c
|
||
(Marevna, heightmap, ocean world) — all relief_energy_q=0.70 per D-239 §5.
|
||
|
||
CAPTURE RECOMMENDATION (lead): for the true Alpine/MountainPass (MorphologyZone
|
||
13/14) crop this ticket wants, the Active terrestrial island worlds GJ1002b and
|
||
GJ103c are the primary candidates (coastal orogeny, standard climate — closest
|
||
analogue to the GJ380c plains/river substitution being replaced). The Volcanic
|
||
pair (GJ4056b, GJ660Ad) are alternates with maximum relief energy but
|
||
airless/thin atmospheres — shield/lava-field morphology, likely NOT
|
||
Alpine-classed; use only if the Active pair fails to produce MorphologyZone
|
||
13/14 crops. GJ0c/GJ0f-1 lack terrain_reference and cannot open in the Atlas.
|
||
|
||
CAPTURE CENTER PROBED (2026-07-25, server-side scan; scratch bins deleted, tree
|
||
verified clean). CHOSEN BODY: GJ1002b (Caparica). GJ103c is a NEGATIVE finding —
|
||
a full-body stride-8 scan (2,246,140 districts sampled) found only 4 isolated
|
||
MorphologyZone-13/14 cells, none clustering; it is not a viable capture body.
|
||
No Volcanic-pair fallback needed.
|
||
|
||
PRIMARY CENTER (feed to StepCanvasViewer.jump_to, world metres):
|
||
(385024, -598016) [district grid (188, -292) x DISTRICT_M=2048]
|
||
5x5-district neighborhood 25/25 Alpine/MountainPass; +/-40 km box 452/1681
|
||
(26.9%) hits; elev_q 50-100 — reads as a range, not speckle.
|
||
|
||
ALTERNATES on GJ1002b: (6973440, 1361920) 23/25 dense, 18.9% box;
|
||
(2488320, 129024) 24/25, 7.9%; (35919872, -6862848) 23/25, 16.2%;
|
||
(29184000, -4837376) 19/25, 18.6%.
|
||
|
||
METHOD (reproducible): derive_district() per district (district_profile.rs:1769)
|
||
over cascade_snapshot_for_body(world_seed=42) + run_layer1 TerrainAnalysis —
|
||
identical to aliveness_probe''s --render path (aliveness_probe.rs:72-85). Gate
|
||
verified at district_profile.rs:594-712: Alpine(14) = slope_q>=40 && elev_q>=75
|
||
&& ocean_fraction_q<20; MountainPass(13) same family, 50<=elev_q<75. Coarse
|
||
stride-8 full-body scan -> union-find clustering -> dense stride-1 5x5-window
|
||
refine. Both bodies confirmed planet_class=''oceanic'' -> TectonicClass::Active.', 'Araminta''s PR #192 companion note, kept open by her PR #208 ruling (option b): the Quarter-vs-District relief-differentiation check was accepted for the T-1160 merge on a plains/river substitution (GJ380c world center -17723392,-10532864 — Quarter clearly shows finer higher-frequency texture than District), but plains texture and jagged tectonic relief are different visual regimes and the sharper case still needs its own capture. Task: identify the body pool with tectonics:high (or planet_class values mapping to TectonicClass::Volcanic/Active) and RECORD the pool in this ticket first — the PR #208 eyeball proved GJ380c/GJ820Bc are both tectonics:low via exhaustive two-Global color scans, don''t re-run that search blind — then capture quarter-relief vs district-relief at a true Alpine/MountainPass crop (MorphologyZone 13/14) at the same world center, matched crop, and have Araminta judge the differentiation. Reuse the pr208_driver fixed-center --step protocol (T-1157 harness inventory). Related: T-1160, PR #192, PR #208.
|
||
|
||
POOL RECORDED (2026-07-25, read-only survey per this ticket''s own first step —
|
||
do not re-run the search blind).
|
||
|
||
MAPPING MECHANISM: server/src/atlas/district_profile.rs:296-312
|
||
derive_tectonic_class(): BodyParams::tectonic_activity authored override first
|
||
("volcanic"/"active"/"tidally_forced", NO column in current systems.db schema and
|
||
no authored overrides in the wiki TOMLs — so today the override path is dead),
|
||
else planet_class fallback: "volcanic" → Volcanic; "oceanic"/"ocean_world" →
|
||
Active; everything else → Stable. Sanity anchors agree with the PR #208 eyeball:
|
||
GJ380c (arid) and GJ820Bc (arid) both → Stable.
|
||
|
||
THE FULL POOL (7 bodies):
|
||
- Volcanic: GJ0c (Venus, no heightmap), GJ0f-1 (Io, no heightmap), GJ4056b
|
||
(heightmap, airless, relief_energy_q=1.0), GJ660Ad (Seongho Prime, heightmap,
|
||
thin atmosphere, relief_energy_q=1.0)
|
||
- Active: GJ1002b (Caparica, heightmap, island world, standard atmosphere),
|
||
GJ103c (Vlieland, heightmap, island world, standard atmosphere), GJ447c
|
||
(Marevna, heightmap, ocean world) — all relief_energy_q=0.70 per D-239 §5.
|
||
|
||
CAPTURE RECOMMENDATION (lead): for the true Alpine/MountainPass (MorphologyZone
|
||
13/14) crop this ticket wants, the Active terrestrial island worlds GJ1002b and
|
||
GJ103c are the primary candidates (coastal orogeny, standard climate — closest
|
||
analogue to the GJ380c plains/river substitution being replaced). The Volcanic
|
||
pair (GJ4056b, GJ660Ad) are alternates with maximum relief energy but
|
||
airless/thin atmospheres — shield/lava-field morphology, likely NOT
|
||
Alpine-classed; use only if the Active pair fails to produce MorphologyZone
|
||
13/14 crops. GJ0c/GJ0f-1 lack terrain_reference and cannot open in the Atlas.
|
||
|
||
CAPTURE CENTER PROBED (2026-07-25, server-side scan; scratch bins deleted, tree
|
||
verified clean). CHOSEN BODY: GJ1002b (Caparica). GJ103c is a NEGATIVE finding —
|
||
a full-body stride-8 scan (2,246,140 districts sampled) found only 4 isolated
|
||
MorphologyZone-13/14 cells, none clustering; it is not a viable capture body.
|
||
No Volcanic-pair fallback needed.
|
||
|
||
PRIMARY CENTER (feed to StepCanvasViewer.jump_to, world metres):
|
||
(385024, -598016) [district grid (188, -292) x DISTRICT_M=2048]
|
||
5x5-district neighborhood 25/25 Alpine/MountainPass; +/-40 km box 452/1681
|
||
(26.9%) hits; elev_q 50-100 — reads as a range, not speckle.
|
||
|
||
ALTERNATES on GJ1002b: (6973440, 1361920) 23/25 dense, 18.9% box;
|
||
(2488320, 129024) 24/25, 7.9%; (35919872, -6862848) 23/25, 16.2%;
|
||
(29184000, -4837376) 19/25, 18.6%.
|
||
|
||
METHOD (reproducible): derive_district() per district (district_profile.rs:1769)
|
||
over cascade_snapshot_for_body(world_seed=42) + run_layer1 TerrainAnalysis —
|
||
identical to aliveness_probe''s --render path (aliveness_probe.rs:72-85). Gate
|
||
verified at district_profile.rs:594-712: Alpine(14) = slope_q>=40 && elev_q>=75
|
||
&& ocean_fraction_q<20; MountainPass(13) same family, 50<=elev_q<75. Coarse
|
||
stride-8 full-body scan -> union-find clustering -> dense stride-1 5x5-window
|
||
refine. Both bodies confirmed planet_class=''oceanic'' -> TectonicClass::Active.
|
||
|
||
VERDICT (araminta, 2026-07-25): PASS — closes the PR #192 companion concern. District shows the massif as soft formless high-elevation blobs; Quarter at the identical center resolves an elongated NW-SE ridge spine with perpendicular lobate spurs, slope stipple, and a localized feature District has no resolution to show — organized directional structure absent at District, not a rescale. Judged the harder test than the accepted GJ380c plains case and a cleaner pass. Region frame correctly shows no relief signature (a ~10km massif is near-sub-pixel at 204.8km/gridunit; Region''s job is context, no claim staked there). Evidence: scratchpad t1196/gj1002b_{quarter,district,region}.png, matched world_center (385024,-598016) proven by view-transform logs. Secondary observations ticketed separately: header-ghosting artifact (client) and elevation-white vs ice-white grammar split (visual); the dark-red speckle inside the massif is explicitly NOT actioned off one frame — re-examine only if it recurs at other Alpine sites.', NULL, '2026-07-25 20:53:29', '2026-07-25 20:53:29.301', '2026-07-25 20:53:29.301', NULL, '71380c1e173d5397ee5d61c3a740a151', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSM3MQ5GFSPKKFJF6GGZN8CM', 'status', 'in_progress', 'done', NULL, '2026-07-25 20:53:47', '2026-07-25 20:53:47.773', '2026-07-25 20:53:47.773', NULL, '9937b3a9176ac2add998310b7bedbad6', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPE8FR7TGEM7X6QVPV4M', 'description', '(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).
|
||
|
||
Refinement (batch-6 Si pass, 2026-07-25) — SUPERSEDES the 2026-06-16 READY block
|
||
(sprite-era, invalidated by D-244) and the 2026-06-16 HELD note. T-1050 (catalog +
|
||
conventions.md + manifest.json) and T-1052 (palette.md style bible) are both DONE
|
||
(PR #211, merged 2026-07-25) — the conventions this ticket needed to consume now
|
||
exist and are read, not hypothetical.
|
||
|
||
SCOPE, 3D REALITY: T-961 breaks into per-asset-class stories, each gated on a
|
||
one-page brief. A "written brief" is now a short doc that states, per class:
|
||
(1) scope — which manifest category (furniture|props) and which D-235 ObjectTag
|
||
axis if any; (2) visual reference — cites palette.md §3''s hue/grain/weathering
|
||
register for the relevant token(s), or palette.md §2 toon/PBR default for classes
|
||
with no D-235 token; (3) naming — conventions.md §1 model naming
|
||
(<category>_<descriptor>.glb), §2 mask sidecar if tintable, §4 footprint_tiles if
|
||
multi-tile; (4) generation path — /image-gen concept → /glb-gen (Trellis) →
|
||
postprocess → promotion into client/assets/models/{furniture,props}/ +
|
||
manifest.json entry (conventions.md, models.md); (5) acceptance — N assets at
|
||
"planned" status registered in the manifest with a real manifest.json entry,
|
||
status flips as production proceeds (models.md''s shared status vocab).
|
||
|
||
BRIEF TEMPLATE (create docs/assets/_templates/asset-brief.md): the five headers
|
||
above (scope / visual reference / naming / gen path / acceptance), one page,
|
||
adopting docs/_templates/design.md frontmatter. Do NOT reuse _templates/sprite.md
|
||
(SPR/FUR/TILE/ICO/FX prefixes) — explicitly retired by D-244/T-1050.
|
||
|
||
CLASS LIST — station walls, rural walls, doors, floors, furniture/props already
|
||
have partial prior art (station walls: wall_structural GLB exists unrendered per
|
||
the 2026-06-12 audit matrix; doors: DoorSpec logical model exists, T-979/T-998;
|
||
floors: D-228 FloorMaterial axis exists) — each gets a real story + brief, citing
|
||
its relevant D-235 axis (wall/roof/facade/street) or, for doors/floors/furniture,
|
||
the non-ObjectTag conventions (mask sidecars, footprint_tiles).
|
||
|
||
STREET FURNITURE / SIGNAGE-SCREENS / RURAL STRUCTURES (lamp posts, barns,
|
||
TVs, billboards — T-1051''s four classes): RECOMMEND FORMAL DEFERRAL, not real
|
||
briefs, this batch. Rationale: Phase 4''s deliverable is "deterministic
|
||
walkable-world data + per-layer Atlas maps + asset catalog" (cascade table) —
|
||
outside-in generation (D-166) needs building EXTERIOR templates
|
||
(D-235 wall/roof/facade/street axes) to make districts/blocks walkable and
|
||
Atlas-legible. Lamp posts (street furniture), TVs/billboards (signage/screens
|
||
placed as interior or exterior set-dressing), and barns (a rural building
|
||
*type*, not a wall/roof/facade axis token) are furniture-tier detail objects
|
||
that populate a walkable exterior once it exists — they read as Phase 6
|
||
"detail coloring / room-level population" (cascade table) or, at best, late
|
||
Phase 4 polish, not blocking asset classes for getting the world walkable.
|
||
Zero repo hits exist for any of the four beyond epic text (T-1049''s own 2026-06-12
|
||
audit matrix, unchanged) — there is no partial work to protect by deferring.
|
||
Treat identically to Q-067''s car deferral: file a deferral note on the story
|
||
(or fold into one placeholder story "T-1051 classes — deferred pending Phase 4
|
||
exterior-generation completion"), do not write real briefs now. Distinguish from
|
||
cars only in degree, not in kind — Q-067 is a still-open decision question
|
||
(vehicle simulation is a bigger unresolved design surface); the T-1051 four are
|
||
simpler set-dressing whose deferral needs no open question, just a scope note,
|
||
because nothing about their eventual brief depends on an undecided mechanic.
|
||
|
||
Q-119 (generic-parent placeholder set as milestone-0) is STILL OPEN (unresolved
|
||
as of this pass) — unchanged from the prior block: not a blocker, sequencing-only.
|
||
Each relevant story notes the generic_wall/roof/facade/street (+ generic
|
||
door/floor/furniture) parents as milestone-0 IF Q-119 resolves yes.
|
||
|
||
READ before filing: docs/assets/visual/{conventions,palette,models,textures,
|
||
artwork}.md (T-1050/T-1052, merged), D-244, D-257, D-235 (ratified token list),
|
||
D-243 (footprint unit), docs/architecture/character-asset-organization.md
|
||
(mask/manifest precedent).
|
||
|
||
VERDICT: READY (activation = batch 6; the T-1051 deferral recommendation above is
|
||
ratified at activation, then T-1051 is updated to match the ruling this ticket records).', '(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).
|
||
|
||
Refinement (batch-6 Si pass, 2026-07-25) — SUPERSEDES the 2026-06-16 READY block
|
||
(sprite-era, invalidated by D-244) and the 2026-06-16 HELD note. T-1050 (catalog +
|
||
conventions.md + manifest.json) and T-1052 (palette.md style bible) are both DONE
|
||
(PR #211, merged 2026-07-25) — the conventions this ticket needed to consume now
|
||
exist and are read, not hypothetical.
|
||
|
||
SCOPE, 3D REALITY: T-961 breaks into per-asset-class stories, each gated on a
|
||
one-page brief. A "written brief" is now a short doc that states, per class:
|
||
(1) scope — which manifest category (furniture|props) and which D-235 ObjectTag
|
||
axis if any; (2) visual reference — cites palette.md §3''s hue/grain/weathering
|
||
register for the relevant token(s), or palette.md §2 toon/PBR default for classes
|
||
with no D-235 token; (3) naming — conventions.md §1 model naming
|
||
(<category>_<descriptor>.glb), §2 mask sidecar if tintable, §4 footprint_tiles if
|
||
multi-tile; (4) generation path — /image-gen concept → /glb-gen (Trellis) →
|
||
postprocess → promotion into client/assets/models/{furniture,props}/ +
|
||
manifest.json entry (conventions.md, models.md); (5) acceptance — N assets at
|
||
"planned" status registered in the manifest with a real manifest.json entry,
|
||
status flips as production proceeds (models.md''s shared status vocab).
|
||
|
||
BRIEF TEMPLATE (create docs/assets/_templates/asset-brief.md): the five headers
|
||
above (scope / visual reference / naming / gen path / acceptance), one page,
|
||
adopting docs/_templates/design.md frontmatter. Do NOT reuse _templates/sprite.md
|
||
(SPR/FUR/TILE/ICO/FX prefixes) — explicitly retired by D-244/T-1050.
|
||
|
||
CLASS LIST — station walls, rural walls, doors, floors, furniture/props already
|
||
have partial prior art (station walls: wall_structural GLB exists unrendered per
|
||
the 2026-06-12 audit matrix; doors: DoorSpec logical model exists, T-979/T-998;
|
||
floors: D-228 FloorMaterial axis exists) — each gets a real story + brief, citing
|
||
its relevant D-235 axis (wall/roof/facade/street) or, for doors/floors/furniture,
|
||
the non-ObjectTag conventions (mask sidecars, footprint_tiles).
|
||
|
||
STREET FURNITURE / SIGNAGE-SCREENS / RURAL STRUCTURES (lamp posts, barns,
|
||
TVs, billboards — T-1051''s four classes): RECOMMEND FORMAL DEFERRAL, not real
|
||
briefs, this batch. Rationale: Phase 4''s deliverable is "deterministic
|
||
walkable-world data + per-layer Atlas maps + asset catalog" (cascade table) —
|
||
outside-in generation (D-166) needs building EXTERIOR templates
|
||
(D-235 wall/roof/facade/street axes) to make districts/blocks walkable and
|
||
Atlas-legible. Lamp posts (street furniture), TVs/billboards (signage/screens
|
||
placed as interior or exterior set-dressing), and barns (a rural building
|
||
*type*, not a wall/roof/facade axis token) are furniture-tier detail objects
|
||
that populate a walkable exterior once it exists — they read as Phase 6
|
||
"detail coloring / room-level population" (cascade table) or, at best, late
|
||
Phase 4 polish, not blocking asset classes for getting the world walkable.
|
||
Zero repo hits exist for any of the four beyond epic text (T-1049''s own 2026-06-12
|
||
audit matrix, unchanged) — there is no partial work to protect by deferring.
|
||
Treat identically to Q-067''s car deferral: file a deferral note on the story
|
||
(or fold into one placeholder story "T-1051 classes — deferred pending Phase 4
|
||
exterior-generation completion"), do not write real briefs now. Distinguish from
|
||
cars only in degree, not in kind — Q-067 is a still-open decision question
|
||
(vehicle simulation is a bigger unresolved design surface); the T-1051 four are
|
||
simpler set-dressing whose deferral needs no open question, just a scope note,
|
||
because nothing about their eventual brief depends on an undecided mechanic.
|
||
|
||
Q-119 (generic-parent placeholder set as milestone-0) is STILL OPEN (unresolved
|
||
as of this pass) — unchanged from the prior block: not a blocker, sequencing-only.
|
||
Each relevant story notes the generic_wall/roof/facade/street (+ generic
|
||
door/floor/furniture) parents as milestone-0 IF Q-119 resolves yes.
|
||
|
||
READ before filing: docs/assets/visual/{conventions,palette,models,textures,
|
||
artwork}.md (T-1050/T-1052, merged), D-244, D-257, D-235 (ratified token list),
|
||
D-243 (footprint unit), docs/architecture/character-asset-organization.md
|
||
(mask/manifest precedent).
|
||
|
||
VERDICT: READY (activation = batch 6; the T-1051 deferral recommendation above is
|
||
ratified at activation, then T-1051 is updated to match the ruling this ticket records).
|
||
|
||
Lead ratification (batch-6 activation, 2026-07-25): the refinement block''s T-1051 recommendation is RATIFIED — lamp posts, barns, TVs, billboards get a formal Q-067-style deferral, not briefs. Implementation of this ticket authors the deferral note (four classes, rationale, Q-067 precedent, ''revisit when Phase-4 exterior generation completes'') alongside the real briefs; T-1051''s own deliverable (''or record formal deferral'') is satisfied by that note and T-1051 closes when it lands. Child story tickets under T-961: the implementing agent DRAFTS the story list (title + one-line scope + brief path per class) in its report; the lead creates them on main at merge (avoids cross-vault worktree pql writes, FR-4). Surfaced to Jeroen in the batch report for cheap veto.', NULL, '2026-07-25 20:54:28', '2026-07-25 20:54:28.647', '2026-07-25 20:54:28.647', NULL, '4187fc690799214fd6d8e8ba02188396', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPE8FR7TGEM7X6QVPV4M', 'status', 'backlog', 'in_progress', NULL, '2026-07-25 20:54:32', '2026-07-25 20:54:32.387', '2026-07-25 20:54:32.387', NULL, '120f745556e6aeb64c5a37639588b30e', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPZ0ZTM1QQXD5K972CMM', 'status', 'backlog', 'in_progress', NULL, '2026-07-25 20:54:32', '2026-07-25 20:54:32.393', '2026-07-25 20:54:32.393', NULL, 'ed387adc6da3e7bae2b2314473e1fe7f', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPE8FR7TGEM7X6QVPV4M', 'assigned_to', NULL, 'araminta', NULL, '2026-07-25 20:54:32', '2026-07-25 20:54:32.547', '2026-07-25 20:54:32.547', NULL, '595f59f8b831ba9192ec4ab6312900a4', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPZ0ZTM1QQXD5K972CMM', 'assigned_to', NULL, 'qatux', NULL, '2026-07-25 20:54:36', '2026-07-25 20:54:36.535', '2026-07-25 20:54:36.535', NULL, '8d500e97152680a0b4b83d45e614cff9', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPE8FR7TGEM7X6QVPV4M', 'status', 'in_progress', 'review', NULL, '2026-07-25 21:01:13', '2026-07-25 21:01:13.522', '2026-07-25 21:01:13.522', NULL, 'c1c914bd42a1bbce8315aecb9f722d40', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPZ0ZTM1QQXD5K972CMM', 'status', 'in_progress', 'review', NULL, '2026-07-25 21:01:13', '2026-07-25 21:01:13.529', '2026-07-25 21:01:13.529', NULL, '01322543711363e4d353f07a045a5255', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPPHC9FZ4T0GNKR615PR', 'description', '(description follows in first append)
|
||
|
||
Refinement (batch-5 Si pass, 2026-07-25) — GAPS. Formally deferred rather than refined into an
|
||
actionable brief-writing task now.
|
||
|
||
WHY: T-1051 was filed as a child of T-1049''s per-class breakdown (the fable-ous.md audit T-1049 cites,
|
||
2026-06-12). T-1049 itself is HELD pending the same sprite-to-3D re-scope as T-1050 (its "Refinement
|
||
2026-06-16 — READY" block still frames the per-class stories, briefs, and catalog files in sprite-era
|
||
language, and its own text says "sequence T-1049 to consume T-1050''s conventions where they overlap" —
|
||
so T-1049 cannot be un-held before T-1050 lands). T-1051 is one layer further down that same
|
||
dependency: it cannot be meaningfully scoped (what does a "one-page brief" even template against?)
|
||
until (1) T-1050 lands conventions.md + the catalog structure a brief would reference, AND (2) T-1049
|
||
is re-scoped and un-held (it owns the per-class story breakdown T-1051 is part of).
|
||
|
||
Zero repo hits exist for lamp posts, barns, TVs, or billboards beyond the T-750 epic description text
|
||
(confirmed by T-1049''s own audit matrix) — there is no existing partial work this ticket would be
|
||
resuming, so there is no cost to deferring it cleanly.
|
||
|
||
DISPOSITION: blocker edge wired (T-1051 blocked-by T-1049). When T-1049 is re-scoped (a future Si
|
||
pass, after T-1050 lands), that re-scope explicitly decides whether lamp posts/barns/TVs/billboards
|
||
get real briefs or a formal deferral note (T-1049''s existing block already leaned toward "explicitly
|
||
record which classes are deferred" for cars via Q-067 — the same treatment likely applies to these
|
||
four, but that is T-1049''s call when re-scoped, not this ticket''s in isolation).', '(description follows in first append)
|
||
|
||
Refinement (batch-5 Si pass, 2026-07-25) — GAPS. Formally deferred rather than refined into an
|
||
actionable brief-writing task now.
|
||
|
||
WHY: T-1051 was filed as a child of T-1049''s per-class breakdown (the fable-ous.md audit T-1049 cites,
|
||
2026-06-12). T-1049 itself is HELD pending the same sprite-to-3D re-scope as T-1050 (its "Refinement
|
||
2026-06-16 — READY" block still frames the per-class stories, briefs, and catalog files in sprite-era
|
||
language, and its own text says "sequence T-1049 to consume T-1050''s conventions where they overlap" —
|
||
so T-1049 cannot be un-held before T-1050 lands). T-1051 is one layer further down that same
|
||
dependency: it cannot be meaningfully scoped (what does a "one-page brief" even template against?)
|
||
until (1) T-1050 lands conventions.md + the catalog structure a brief would reference, AND (2) T-1049
|
||
is re-scoped and un-held (it owns the per-class story breakdown T-1051 is part of).
|
||
|
||
Zero repo hits exist for lamp posts, barns, TVs, or billboards beyond the T-750 epic description text
|
||
(confirmed by T-1049''s own audit matrix) — there is no existing partial work this ticket would be
|
||
resuming, so there is no cost to deferring it cleanly.
|
||
|
||
DISPOSITION: blocker edge wired (T-1051 blocked-by T-1049). When T-1049 is re-scoped (a future Si
|
||
pass, after T-1050 lands), that re-scope explicitly decides whether lamp posts/barns/TVs/billboards
|
||
get real briefs or a formal deferral note (T-1049''s existing block already leaned toward "explicitly
|
||
record which classes are deferred" for cars via Q-067 — the same treatment likely applies to these
|
||
four, but that is T-1049''s call when re-scoped, not this ticket''s in isolation).
|
||
|
||
DELIVERED BY DEFERRAL (2026-07-25, PR #213): docs/assets/briefs/deferred.md is the formal deferral record this ticket''s title asked for — lamp posts, barns, TVs, billboards each recorded with rationale (Phase-4 walkability needs exteriors; these are set-dressing for a walkable world — Phase 6 or late-4 polish), the Q-067 precedent, and the revisit trigger (Phase-4 exterior generation complete). Ratified on T-1049 (batch-6 activation), reviewed by Tyre (PR #213 — including his ruling that no D-record is needed) with the axis-completeness note ensuring the register accounts for all four D-235 axes. The ''or record formal deferral'' arm of this ticket''s deliverable is satisfied; closing done.', NULL, '2026-07-25 21:11:23', '2026-07-25 21:11:23.912', '2026-07-25 21:11:23.912', NULL, 'e4bc916a158945bf54d40d9585473f90', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPPHC9FZ4T0GNKR615PR', 'status', 'backlog', 'done', NULL, '2026-07-25 21:11:27', '2026-07-25 21:11:27.653', '2026-07-25 21:11:27.653', NULL, 'dafe6739e5ec3e606557ef89f48a59e5', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPE8FR7TGEM7X6QVPV4M', 'status', 'review', 'done', NULL, '2026-07-25 21:11:27', '2026-07-25 21:11:27.660', '2026-07-25 21:11:27.660', NULL, 'ec46f47d92d5c6fe9490a72aa929c9f2', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPZ0ZTM1QQXD5K972CMM', 'status', 'review', 'done', NULL, '2026-07-25 21:11:27', '2026-07-25 21:11:27.661', '2026-07-25 21:11:27.661', NULL, '8cebf78377da9513e22843c0e0c72a02', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSP4MX7C66N76V31EB88YC78', 'description', 'Found during the T-1053 briefing rewrite (2026-07-25): D-126 and D-131 have been repurposed to content unrelated to what v0.2-era documents cite them for. The old araminta briefing cited ''D-126 = character customisation dimensions'' — current D-126 reads ''Groundhog Day alarm clock homage — first game day only'' (the customisation work actually shipped as D-159–D-164). The old briefing cited ''D-131 = apartment/insert first-moment priority'' — current D-131 is ''broad economic verb vocabulary (life verbs, not tycoon-specific)''. This is ID-drift, not staleness: any document still citing the old meanings cites the WRONG decision entirely. Task: (1) first establish the MECHANISM — were these IDs renumbered during the DQR-tree migration, or were the era documents mis-cited at write time? If renumbering, derive the full affected-ID set from the migration mapping, not just these two. (2) Repo-wide grep for D-126/D-131 (and any other affected IDs) across docs/, wiki/, governance/ prose, and .claude/, classifying each hit as current-meaning (fine) vs era-meaning (fix or annotate). (3) Fix or annotate the stale citations; note the outcome here. The rewritten araminta.md (T-1053) is already clean. Clerk-profile work — D-record consistency audit.', 'Found during the T-1053 briefing rewrite (2026-07-25): D-126 and D-131 have been repurposed to content unrelated to what v0.2-era documents cite them for. The old araminta briefing cited ''D-126 = character customisation dimensions'' — current D-126 reads ''Groundhog Day alarm clock homage — first game day only'' (the customisation work actually shipped as D-159–D-164). The old briefing cited ''D-131 = apartment/insert first-moment priority'' — current D-131 is ''broad economic verb vocabulary (life verbs, not tycoon-specific)''. This is ID-drift, not staleness: any document still citing the old meanings cites the WRONG decision entirely. Task: (1) first establish the MECHANISM — were these IDs renumbered during the DQR-tree migration, or were the era documents mis-cited at write time? If renumbering, derive the full affected-ID set from the migration mapping, not just these two. (2) Repo-wide grep for D-126/D-131 (and any other affected IDs) across docs/, wiki/, governance/ prose, and .claude/, classifying each hit as current-meaning (fine) vs era-meaning (fix or annotate). (3) Fix or annotate the stale citations; note the outcome here. The rewritten araminta.md (T-1053) is already clean. Clerk-profile work — D-record consistency audit.
|
||
|
||
Batch-7 Si pre-answer (2026-07-25): the ticket''s question (1) is RESOLVED — the pql migration did NOT renumber decision ids. tooling/pql-migrate/restructure_decisions.py''s own docstring states the migration is token-preserving (''the [D-NNN] bracket text and #d-nnn-... anchor stay byte-identical'' — only file locations and link paths changed), and seed_tickets.py preserves decision_ref verbatim. Therefore the D-126/D-131 drift is write-time mis-citation in the era documents (or later reuse/repurposing through ordinary record editing), and the sweep scope is exactly D-126/D-131 (plus any other ids the sweep itself surfaces as suspicious), not a migration-derived affected set. Start at step (2).', NULL, '2026-07-25 21:15:56', '2026-07-25 21:15:56.268', '2026-07-25 21:15:56.268', NULL, 'a7f3bab5f499e3a21715219db421e630', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FB0TNSRXDCJS4P9Z5JQ1DAAM', 'description', 'Parallel asset pipeline producing the walls/doors/props/lamp-posts/etc. the tile fill places, with rural and station variants, tracked in a production-status catalog. Runs alongside generation.', 'Parallel asset pipeline producing the walls/doors/props/lamp-posts/etc. the tile fill places, with rural and station variants, tracked in a production-status catalog. Runs alongside generation.
|
||
|
||
Q-119 sequencing ruling (lead, batch-7 activation, 2026-07-25): the child stories T-1200..T-1204 follow the BRIEFS'' narrow reading — Q-119 gates only whether the generic-parent placeholder line-item counts as milestone-0; it never gates specific-token production. T-1049''s older ''Decide Q-119 before sequencing'' line is superseded as imprecise (the reviewed, merged briefs are the work contracts). Specific-token work on any story may start immediately; the generic-parent line items stay provisional until Q-119 resolves. Surfaced to Jeroen for cheap veto in the batch-7 report.', NULL, '2026-07-25 21:16:03', '2026-07-25 21:16:03.830', '2026-07-25 21:16:03.830', NULL, '36ca919e5e410cf99feb6bbfc3c91889', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPPM0KP850FN6WQ5PDEX9ZS4', 'status', 'backlog', 'in_progress', NULL, '2026-07-25 21:16:09', '2026-07-25 21:16:09.468', '2026-07-25 21:16:09.468', NULL, '074ebb15c9da80c5ae6778b969dad0bb', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSP4MX7C66N76V31EB88YC78', 'status', 'backlog', 'in_progress', NULL, '2026-07-25 21:16:09', '2026-07-25 21:16:09.474', '2026-07-25 21:16:09.474', NULL, 'c2cc60713ad1366da71e1d5c1071f21d', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSP7HT5ES8D83VZA6ETACRAW', 'status', 'backlog', 'in_progress', NULL, '2026-07-25 21:16:09', '2026-07-25 21:16:09.474', '2026-07-25 21:16:09.474', NULL, 'e04031c2f45d76cfaec042afa34b2863', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPPM0KP850FN6WQ5PDEX9ZS4', 'assigned_to', NULL, 'dudley', NULL, '2026-07-25 21:16:12', '2026-07-25 21:16:12.993', '2026-07-25 21:16:12.993', NULL, '5a1279c95e7f72db48cd78cbc492cc35', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSP7HT5ES8D83VZA6ETACRAW', 'assigned_to', NULL, 'justine', NULL, '2026-07-25 21:16:13', '2026-07-25 21:16:13.465', '2026-07-25 21:16:13.465', NULL, 'c00c4231a9e967524b556aadf3255cb8', 2) ON CONFLICT(hash) DO NOTHING;
|
||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSP4MX7C66N76V31EB88YC78', 'assigned_to', NULL, 'clerk', NULL, '2026-07-25 21:16:14', '2026-07-25 21:16:14.050', '2026-07-25 21:16:14.050', NULL, 'a1bb4b5b3f1fba52fc7fa1a6be8e5e02', 2) ON CONFLICT(hash) DO NOTHING;
|