diff --git a/.pql/changelog/ticket_history/2026-07.sql b/.pql/changelog/ticket_history/2026-07.sql index 82ce2feed..3531974d8 100644 --- a/.pql/changelog/ticket_history/2026-07.sql +++ b/.pql/changelog/ticket_history/2026-07.sql @@ -1372,3 +1372,4 @@ Deferred (no preference given): standalone-HQ Zipf population shares stay as-is 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; diff --git a/.pql/changelog/tickets/2026-07.sql b/.pql/changelog/tickets/2026-07.sql index 9974834c1..1a29e3717 100644 --- a/.pql/changelog/tickets/2026-07.sql +++ b/.pql/changelog/tickets/2026-07.sql @@ -1761,3 +1761,29 @@ Deferred (no preference given): standalone-HQ Zipf population shares stay as-is 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).', 'in_progress', 'medium', 'dudley', 'server', 'D-242', '2026-06-14 15:29:50', '2026-07-16 13:34:49.724', NULL, '976f4eba75344d6e3f0ab9ba6393a5df', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FPPM0KP850FN6WQ5PDEX9ZS4', 'bug', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Road graph: 0 routable edges on water-heavy bodies — placements land in water-majority routing cells, every A* pair drops', 'Found during T-1076 (road-hub refinement) verification: several real bodies (GJ251c, GJ380c) produce 0 routable road edges because settlement placements land in water-majority routing cells, so every A* pair is dropped. PRE-EXISTING behavior (T-1038''s core had the same drop path) but now more visible with hub/spur semantics and on the Atlas road overlay. Candidate fixes per Dudley: coastal-cell routing relaxation (allow routing through coast-adjacent cells at a cost penalty) or a placement nudge (settlements snap out of water-majority cells at L3). Affects the Atlas planet-browsing experience directly: water-heavy bodies show settlements but no roads.', 'backlog', 'medium', NULL, 'server', NULL, '2026-07-16 14:23:57.874', '2026-07-16 14:23:57.874', NULL, '91a60e09275dd3bd232078fbe8bbb8b3', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash); +INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FCDG73V9R6N024QSFDEJ4R68', 'story', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Road-graph hub refinement — scaled-cap hubs + co-location collapse + hybrid minor attach + RailHeadFacing junction pass', 'Follow-on to T-1038 (road-graph core shipped). Hub-selection refinement, gated on the resolved settlement model (D-242). + +Build on server/src/atlas/road_graph.rs: +1. Hub selection: ''real cities, scaled cap'' — wiki cities anchor the MST; cap scales with body size; standalone HQs/minor settlements are non-hub. +2. Co-location collapse: group same-named settlements (defensive; the D-242 corp-HQ fix removes most at source). +3. Hybrid minor-settlement attach: snap to nearest existing road edge if close, else spur to nearest hub (add edge-split-at-attach). +4. RailHeadFacing junction pass (T-1038 step 6, deferred): junction settlements (RoadGraph::high_connectivity_junctions already computed) get FoundingOrientation::RailHeadFacing. REQUIRES a D-213 amendment (adopted enum has no RailHeadFacing) + Layer-4 skeleton_gen handling. + +Needs population ranking — blocked on the corp-HQ-model + population-bake tickets. + +--- +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).', 'review', 'medium', 'dudley', 'server', 'D-242', '2026-06-14 15:29:50', '2026-07-16 14:25:25.189', NULL, '6489dd0ff1f3803b055b0911e9c3b62e', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);