Now also fix the admin_way_ids collection and the missing-ways check to include all way members, not just outer.


  2004→                        }
  2005→                    });
  2006→                }
  2007→
  2008→                // Reader thread (producer)
  2009→                {
  2010→                    osmium::io::Reader reader_nodes{input_file, osmium::osm_entity_bits::node};
  2011→                    while (auto buf = reader_nodes.read()) {
  2012→                        {
  2013→                            std::unique_lock<std::mutex> lock(queue_mutex);
  2014→                            queue_cv.wait(lock, [&]{ return block_queue.size() < MAX_QUEUE; });
  2015→                            block_queue.push_back(std::move(buf));
  2016→                        }
  2017→                        queue_cv.notify_one();
  2018→                    }

                        }
                    });
                }

                // Reader thread (producer)
                {
                    osmium::io::Reader reader_nodes{input_file, osmium::osm_entity_bits::node};
                    while (auto buf = reader_nodes.read()) {
                        {
                            std::unique_lock<std::mutex> lock(queue_mutex);
                            queue_cv.wait(lock, [&]{ return block_queue.size() < MAX_QUEUE; });
                            block_queue.push_back(std::move(buf));
                        }
                        queue_cv.notify_one();
                    }


2046:            std::unordered_set<int64_t> admin_way_ids;
2050:                        admin_way_ids.insert(way_id);
2053:                std::cerr << "  Admin assembly needs " << admin_way_ids.size() << " way geometries." << std::endl;
2247:                                    if (parallel_admin && !wnodes.empty() && admin_way_ids.count(way.id())) {


  2046→            std::unordered_set<int64_t> admin_way_ids;
  2047→            if (parallel_admin) {
  2048→                for (const auto& rel : data.collected_relations) {
  2049→                    for (const auto& [way_id, role] : rel.members) {
  2050→                        admin_way_ids.insert(way_id);
  2051→                    }
  2052→                }
  2053→                std::cerr << "  Admin assembly needs " << admin_way_ids.size() << " way geometries." << std::endl;
  2054→            }
  2055→

            std::unordered_set<int64_t> admin_way_ids;
            if (parallel_admin) {
                for (const auto& rel : data.collected_relations) {
                    for (const auto& [way_id, role] : rel.members) {
                        admin_way_ids.insert(way_id);
                    }
                }
                std::cerr << "  Admin assembly needs " << admin_way_ids.size() << " way geometries." << std::endl;
            }


Good — `admin_way_ids` already collects ALL way members regardless of role (no role filter at line 2049). Now fix the missing-ways check:


  2505→
  2506→                                // Skip relations with missing outer member ways —
  2507→                                // these cross the extract boundary and would produce
  2508→                                // incorrect partial polygons
  2509→                                bool has_missing = false;
  2510→                                for (const auto& [way_id, role] : rel.members) {
  2511→                                    if (role == "outer" || role.empty()) {
  2512→                                        if (data.way_geometries.find(way_id) == data.way_geometries.end()) {
  2513→                                            has_missing = true;
  2514→                                            break;
  2515→                                        }
  2516→                                    }
  2517→                                }
  2518→                                if (has_missing) {
  2519→                                    assembled_count.fetch_add(1);
  2520→                                    continue;
  2521→                                }
  2522→
  2523→                                auto rings = assemble_outer_rings(rel.members, data.way_geometries);
  2524→

                                // Skip relations with missing outer member ways —
                                // these cross the extract boundary and would produce
                                // incorrect partial polygons
                                bool has_missing = false;
                                for (const auto& [way_id, role] : rel.members) {
                                    if (role == "outer" || role.empty()) {
                                        if (data.way_geometries.find(way_id) == data.way_geometries.end()) {
                                            has_missing = true;
                                            break;
                                        }
                                    }
                                }
                                if (has_missing) {
                                    assembled_count.fetch_add(1);
                                    continue;
                                }

                                auto rings = assemble_outer_rings(rel.members, data.way_geometries);


Need to check ALL way members for missing geometries, not just outer.


Edit

                                // Skip relations with missing outer member ways —
                                // these cross the extract boundary and would produce
                                // incorrect partial polygons
                                bool has_missing = false;
                                for (const auto& [way_id, role] : rel.members) {
                                    if (role == "outer" || role.empty()) {
                                        if (data.way_geometries.find(way_id) == data.way_geometries.end()) {
                                            has_missing = true;
                                            break;
                                        }
                                    }
                                }

                                // Skip relations with missing member ways —
                                // these cross the extract boundary and would produce
                                // incorrect partial polygons
                                bool has_missing = false;
                                for (const auto& [way_id, role] : rel.members) {
                                    if (data.way_geometries.find(way_id) == data.way_geometries.end()) {
                                        has_missing = true;
                                        break;
                                    }
                                }