# วิธีจัดทำข้อมูล — ศูนย์การค้า (Shopping centers)

เอกสารนี้อธิบายว่าเว็บนับอะไร นับอย่างไร และอะไรที่ตัวเลขพิสูจน์ไม่ได้ ใช้คู่กับ [Product Statement](PRODUCT_STATEMENT.md) (รุ่น 0.6) ชื่อบนหน้าจอคือ “ศูนย์การค้า” (Shopping centers) ส่วนขอบเขตของข้อมูลยังเป็นศูนย์การค้าและสถานที่ค้าปลีกตามนิยามของเจ้าของ โค้ดที่ทำตามกติกาเหล่านี้คือ `scripts/build-data.py` (สร้างข้อมูล) และ `js/model.js`, `js/areas.js`, `js/area-insight.js`, `js/scales.js`, `js/pin-buildings.js`, `js/massing.js` (อ่านและคำนวณบนหน้าเว็บ) ค่าที่ใช้จริงของแต่ละรอบบันทึกใน `meta` ของ [data/venues.json](data/venues.json) และ [data/build-report.json](data/build-report.json)

ป้ายหลักฐานตาม Landometer Master Brand Brief v0.5.3 §3.7: **Observed fact** (จากแหล่งใน scope ของแหล่งนั้น) · **Owner-stated** · **Inference** (การตีความของผู้จัดทำ) · **Hypothesis**

## 1. แหล่งข้อมูลและหน่วย

| แหล่ง | ใช้ทำอะไร | ตัวตนของรอบนี้ |
|---|---|---|
| CityMETER Shopping Centers & Retail Venues — Research Master แท็บ `01_VENUES` | ทะเบียนสถานที่ หลักฐานรายช่อง การผ่านนิยาม สถานะ พิกัด | export 25 ต.ค. 2569 16:39 น. หลังเจ้าของปิดคิวตรวจนิยามครบ (เหลือ 0 จาก 11,009) · SHA-256 `a8d9a5f9…` ใน `meta.inputs` (internal working reference) |
| แท็บ `09_RELATIONSHIPS` | ชื่อเรียกอื่น (alias) และความสัมพันธ์โครงการแม่–พื้นที่ย่อย | SHA-256 ใน `meta.inputs` |
| แท็บ `10_VENUE_LOGOS` | ทะเบียนโลโก้ (ไฟล์ บทบาท SHA-256) | ไฟล์ใช้ได้เมื่อ SHA-256 ตรงเท่านั้น |
| แท็บ `13_BUILDING_LINKS` + geometry bundle `CityMETER-retail-venue-host-geometry-2026-10-23` | รูปทรงอาคารของสถานที่ที่ผ่านเกณฑ์ | `selected-host-geometry.geojson` SHA-256 `9c948f99…` |
| รูปเขตกรมแผนที่ทหาร (RTSD 2562 · OCHA ROAP / HDX COD-AB · geoBoundaries gbOpen THA ADM2, CC BY 3.0 IGO) | ขอบเขตเขต/อำเภอ 928 รายการ และจังหวัดที่ dissolve จากเขต — ชุดเดียวกับ CityMETER production (extent และ `areaSqm` ของ `base/info/lv1` ตรงกับรูปนี้) | SHA-256 `d3496a7a…` · `scripts/build-boundaries.py` |
| OpenGISData-Thailand `districts.geojson` (CC BY 4.0) | รหัสและชื่อเขต/อำเภอ: รูป RTSD แต่ละรูปรับรหัสของเขตที่ทับซ้อนมากที่สุด (ทุกคู่ทับกัน ≥ 78% ชื่ออังกฤษตรงกัน ยกเว้น Vadhana = Watthana) | commit `fafcea1` · SHA-256 `329315c2…` |
| CityMETER production `base/info/lv0` และ `base/info/lv1/{provinceId}` | รหัสจังหวัด (`abbrEn` เช่น `BKK`) และรหัสเขต 4 หลักที่ breadcrumb ใช้ | 77 จังหวัด · 928 เขต/อำเภอ |
| CityMETER: Luxury Brands `data/luxury.json` | ลิงก์จากสถานที่ไปหน้า Luxury Brands (`?place=`) เมื่อเปิดสถานที่เดียวกันได้ | 39 สถานที่ |

**Grain:** หนึ่งแถว = หนึ่งสถานที่ (site) โดยโครงการแม่ (parent complex) และพื้นที่ค้าปลีกย่อย (retail component) เป็นคนละแถวที่เชื่อมกันด้วย `parent_venue_id` · join key คือ `venue_id` เท่านั้น ชื่อใช้ค้นหาอย่างเดียว

## 2. นิยามและการนับ

นิยาม retail venue ของเจ้าของ (Owner-stated, 23 ต.ค. 2569): สถานที่ที่มี **หลายกิจการขายผู้บริโภค** และมี **ผู้ดำเนินการรายเดียวบริหารพื้นที่ร่วม** การผ่านนิยามมาจาก `venue_qualification_status` ที่ทีมวิจัยบันทึกพร้อมหลักฐาน หรือกฎรายประเภทที่เจ้าของยอมรับและบันทึกไว้ในทะเบียน (ข้อ 2.1) หน้าเว็บไม่ตัดสินนิยามเอง

| ระดับ | กติกา (ฟิลด์ใน 01_VENUES) | รอบนี้ (export 7 พ.ย. 2569 19:36) |
|---|---|---:|
| ทะเบียน | ทุกแถว | 11,139 |
| **ผ่านนิยาม** (`tier`) | `definition_supported*` / `qualified_*` = หลักฐานปัจจุบัน (`supported`) · `owner_<กฎ>_definition_accepted_*` และ `owner_confirmed_*` = ตามกฎที่เจ้าของข้อมูลยอมรับ (`owner`, ฟิลด์ `ownerRule`) · `historical_*` และ `definition_supported_historically_*` = หลักฐานย้อนหลัง · `planned_*` = โครงการอนาคต | 6,265 (หลักฐานปัจจุบัน 789 · กฎที่เจ้าของยอมรับ 5,247 · ย้อนหลัง 224 · โครงการอนาคต 5) |
| **นับได้** (`countable`) | ผ่านนิยาม และ `count_role` เป็นบทบาทที่นับ: `venue_site`, `venue_site_candidate`, `parent_complex`, `managed_site_parent`, `pending_scope_boundary_review`, `retail_scope_pending_terminal_boundary`, `retail_component_scope_not_entire_hotel_tower` · **ไม่นับแยก** (ฟิลด์ `countHold`): พื้นที่ย่อย `child_zone`, `child_venue`, `component_within_managed_site`, `retail_component_within_managed_site`, `retail_subarea_do_not_count_as_separate_parent_mall`, `child_component_not_independent_center_count` · อาจซ้ำ `duplicate_candidate_hold` และสถานะที่ระบุว่าอาจซ้ำ (`…_duplicate_count_held`, `…_duplicate_review`) แม้บทบาทจะเป็นบทบาทที่นับ · รอตรวจการนับ `retail_component_scope_count_review` · บริบทหลายสถานที่ `aggregate_context_not_independent_venue`, `individual_store_context_not_counted_as_venue` · **ยกเว้น (D6):** พื้นที่ย่อยที่ไม่มีโครงการแม่ในชุดที่ผ่านนิยาม นับเป็นสถานที่ของตัวเองเมื่อเป็นศูนย์การค้าหรือมอลล์ (กลุ่มจากหลักฐานเป็นศูนย์การค้าหรือคอมมูนิตี้มอลล์ หรือเจ้าของระบุ) | 6,162 (รวม D6 18 แห่ง) · ไม่นับแยก 103: พื้นที่ย่อย 74 · อาจซ้ำ 16 · รอตรวจการนับ 12 · บริบท 1 |
| **อุปทาน** (`status = supply`) | นับได้ และ `operation_group` ไม่ใช่ `future_project` (→ กำลังจะเปิด) หรือ `closed_source_evidence` (→ ปิดแล้ว) | 6,156 · กำลังจะเปิด 4 · ปิดแล้ว 2 |
| **ระบุตำแหน่งได้** (`located`) | พิกัดอยู่ในประเทศ และ `coordinate_status` / `coordinate_role` เป็นจุดอ้างอิงที่เลือกแล้ว (ไม่ใช่ `held_*`, `withheld_*`, `not_collected*`, `not_selected*`, `*not_revalidated*`, role `held_*` / `not_selected*` / `no_*`) | 6,140 จาก 6,156 (ไม่มีพิกัดที่ผ่านเกณฑ์ 12 · จุดอยู่นอกขอบเขตเขต/อำเภอ 4) |
| **รอตรวจนิยาม** | `pending_*`, `definition_pending*` และค่าที่ลงท้าย `_pending` ที่ไม่อยู่ในกลุ่มข้างบน | 0 (คิวปิดครบ) |
| **ตรวจแล้ว ยังยืนยันนิยามไม่ได้** (บนหน้าจอ “ยังยืนยันไม่ได้”) | ค่าที่ขึ้นต้น `reviewed_` และมีคำ `unconfirmed` (รอบนี้ `reviewed_definition_unconfirmed`) | 4,866 |
| **ทะเบียนสรุปว่าไม่ใช่สถานที่แยก** | ค่าที่ขึ้นต้น `excluded` `rejected` `disqualified` `not_` `non_` `out_of_scope` `definition_not_` `definition_failed` `fails_` `does_not_` หรือมีคำ `not_independent_venue` `not_retail_venue` `not_a_retail` `not_qualified` `not_qualifying` `not_eligible` · และ `parent_context_*` (โครงการแม่ที่ทะเบียนปิดเป็นบริบท ห้างข้างในผ่านนิยามแยก) | 8 |

- ตัวเลขทุกตัวบนหน้าเว็บ (ตัวนับ แผนที่ กราฟ ตาราง ข้อค้นพบแรก) นับจาก **อุปทานที่นับได้** ตามตัวกรอง; สถานะ “กำลังจะเปิด” และ “ปิดแล้ว” แสดงเป็นรายการแยกในแผง เลือกดูได้จากตัวกรองสถานะ และไม่รวมกับอุปทาน
- พื้นที่ย่อยไม่บวกกับโครงการแม่: แสดงในแผงของโครงการแม่ (“พื้นที่ย่อยในโครงการ · ไม่นับแยก”) และเปิดดูหลักฐานได้ · แผงของแถวที่ไม่นับแยกมีป้ายสั้นจาก `countHold` (“พื้นที่ย่อย · ไม่นับแยก” · “อาจซ้ำ · ไม่นับแยก” · “รอตรวจการนับ · ยังไม่นับ” · “บริบทของหลายสถานที่ · ไม่นับ”)
- **Owner decision D6 (25 ต.ค. 2569):** พื้นที่ย่อยที่ผ่านนิยามแต่โครงการแม่ไม่อยู่ในชุดที่ผ่านนิยาม จะถูกนับที่ระดับของตัวเองเมื่อเป็นศูนย์การค้าหรือมอลล์ — รอบนี้ 6 แห่ง: เซ็นทรัล พาร์ค (โครงการแม่ ดุสิต เซ็นทรัล พาร์ค ถูกทะเบียนปิดเป็นบริบท — ดู §14 ข้อ 6), วัน แบงค็อก (พื้นที่ค้าปลีก), สามย่านมิตรทาวน์, สีลมคอมเพล็กซ์ (สามแห่งนี้เจ้าของระบุว่าเป็นศูนย์การค้า; วัน แบงค็อก และสีลมคอมเพล็กซ์มีประเภทจากหลักฐานเป็น `retail_zone` จึงแสดงในกลุ่มศูนย์การค้าด้วยฐาน “เจ้าของระบุ”), อาทาระ มอลล์ ศรีราชา และมหานคร คิวบ์ (ประเภทจากหลักฐานเป็นคอมมูนิตี้มอลล์/ศูนย์การค้า) · หลักฐานรายช่องของสถานที่บอกว่า “นับเป็นสถานที่ของตัวเอง · โครงการแม่ไม่อยู่ในชุดที่ผ่านนิยาม” (ไม่ขึ้นบนหน้าจอหลัก) · ถ้าทะเบียนเพิ่มโครงการแม่ที่ผ่านนิยามในภายหลัง ระบบจะนับที่โครงการแม่แทนโดยอัตโนมัติ จำนวนรวมไม่ซ้ำ · D6 ใช้กับบทบาทพื้นที่ย่อยเท่านั้น ไม่ใช้กับรายการที่อาจซ้ำ รอตรวจการนับ หรือบริบท
- สถานที่ที่ยังไม่มีพิกัดที่ผ่านเกณฑ์อยู่ในตารางและผลค้นหาพร้อมป้าย “ยังไม่มีพิกัด” ไม่ถูกวางบนแผนที่ และไม่เข้าตัวเลขรายพื้นที่ จุดที่อยู่นอกเส้นเขตทุกเส้น (ริมทะเลหรือชายแดน) ก็ไม่เข้าตัวเลขรายพื้นที่เช่นกัน ตารางเขียนว่า “หมุดอยู่นอกเส้นเขต” แผงภาพรวมบอกจำนวนรวมของทั้งสองกลุ่มครั้งเดียว (“อีก k แห่งยังระบุเขต/อำเภอไม่ได้ · ดูในตาราง”) และคำบรรยายกราฟนับเฉพาะสถานที่ที่อยู่ในเขต/อำเภอ สองตัวเลขนี้บวกกันได้จำนวนทั้งหมดของขอบเขตที่อ่าน ตัวกรองจังหวัดใช้จังหวัดในที่อยู่เฉพาะแถวที่ไม่อยู่ในเขต/อำเภอใด
- ค่าที่ไม่มีคือไม่มี: ไม่แสดง 0 แทนค่าว่าง แผงแสดง “ยังไม่มีข้อมูล”
- **คำใหม่ของทะเบียน:** ค่า `venue_qualification_status` ที่ไม่ตรงกฎใดถือเป็นรอตรวจ (ไม่นับ) และถูกรายงานใน `meta.checks.qualificationFallback` · `count_role` ใหม่ของแถวที่ผ่านนิยามไม่นับและถูกรายงานใน `meta.checks.countRoleFallback` · test ไม่ผ่านจนกว่าจะจัดเข้ากฎทั้งสองอย่าง เพื่อไม่ให้รอบอัปเดตนับหรือซ่อนรายการโดยไม่มีคนตรวจ (ค่า `owner_<กฎ>_definition_accepted_*` ใหม่อ่านเป็นกฎของเจ้าของได้เอง และแสดงชื่อกฎกลาง “กฎรายประเภท” จนกว่าจะเพิ่มชื่อไทยใน `js/model.js`)

### 2.1 กฎรายประเภทที่เจ้าของข้อมูลยอมรับ (Owner-stated)

ทะเบียนรอบนี้บันทึกว่าเจ้าของยอมรับกฎรายประเภทเป็นการผ่านนิยาม (`owner_<กฎ>_definition_accepted_identity_current_and_count_separate`: ยอมรับนิยาม ตัวตนเป็นปัจจุบัน การนับแยกพิจารณาจาก `count_role`) กฎเหล่านี้ใช้แทนหลักฐานผู้บริหารพื้นที่ร่วมรายเดียวของประเภทนั้น ไม่ได้เพิ่มหลักฐานนั้น — เช่น ตลาด 3,858 จาก 3,904 แห่งยังมี `shared_area_governance_status = pending_single_operator_evidence` หลักฐานรายช่องของสถานที่จึงเขียนว่า “ผ่านนิยามตามกฎที่เจ้าของข้อมูลยอมรับ · <กฎ>” แทน “ผ่านนิยามด้วยหลักฐานปัจจุบัน”

| กฎ (`ownerRule`) | บนหน้าจอ | ผ่านนิยาม | อุปทาน |
|---|---|---:|---:|
| `market` | ตลาด | 3,904 | 3,898 (อาจซ้ำ 4 · พื้นที่ย่อย 1 · บริบท 1) |
| `fuel_retail_presence` | สถานีบริการน้ำมันที่มีร้านค้า | 1,173 | 1,173 |
| `exact_inside_multiple_businesses` | มีหลายกิจการอยู่ภายในที่เดียวกัน | 66 | 58 (พื้นที่ย่อย 8) |
| `lotus_restaurant_presence` | โลตัสที่มีร้านอาหาร | 26 | 26 |
| `anchor_second_business` | ร้านหลักที่มีกิจการอื่นอยู่ด้วย | 55 | 40 (การนับแยกยังรอตรวจ 12 · พื้นที่ย่อย 3) · +37 จาก §2.2 |
| `foodland_plus_tooklaedee` / `foodland_tooklaedee` | ฟู้ดแลนด์ที่มีร้านถูกและดี | 17 + 1 | 17 (พื้นที่ย่อย 1) |
| `project_source_common_management_inferred` | แหล่งข้อมูลโครงการบ่งชี้ผู้บริหารร่วม | 3 | 3 |
| `confirmed_managed_retail_component` (`owner_confirmed_*`) | เจ้าของข้อมูลยืนยันรายสถานที่ · พื้นที่ค้าปลีกที่บริหารร่วม | 2 | 2 |
| รวม | | 5,247 | 5,217 |

ตลาดที่ผ่านด้วยกฎนี้ส่วนใหญ่มีสถานะปัจจุบันแบบรอยืนยัน (`operation_group = needs_review`, `operation_status = not_revalidated` 3,574 แห่ง) จึงอยู่ใน “เปิดอยู่หรือรอยืนยันสถานะ” ตามกฎอุปทานเดิม แผงสถานที่บอกสถานะของแต่ละแห่ง

### 2.2 สถานที่ที่ทะเบียนตกหล่น ซึ่งชุดข้อมูลอื่นในทะเบียนชี้ไว้ — D30 (0.1.16, 7 พ.ย. 2569)

คำสั่งเจ้าของ 6 พ.ย. 2569 23:08 น. (Owner-stated): หาสถานที่ค้าปลีกที่ทะเบียนนี้ตกหล่นจากชุดข้อมูลอื่นใน CityMETER Dataset Registry ที่เชื่อมกับอาคาร แล้วเพิ่มเข้าชีต · อ่าน 21 แท็บ host ของชุดข้อมูลในทะเบียน (`R04_VENUE_CROSSWALK` 9,674 แถว) และจุดร้านของชุดข้อมูลร้านค้า (Grocery, Restaurants, Car Service, Camera, Playground, Pet, Bank) ณ 7 พ.ย. 2569

- **กฎที่ใช้ (กฎ `anchor_second_business` ที่เจ้าของยอมรับ 23 ต.ค. 2569 · Inference ในการจับคู่):** (1) ร้านบิ๊กซี โลตัส หรือแม็คโครของชุด Grocery ที่มีพิกัด (ถอดจาก vector tile ของ CityMETER production ราว 10 ม.) (2) มีกิจการผู้บริโภคอีกรายที่รายการสาขาของตัวเองระบุว่าอยู่ที่ร้านนี้ (ชื่อเครือในชื่อสถานที่ของสาขา) และจุดห่างไม่เกิน 300 ม. หรือไม่มีจุดแต่ชื่อและจังหวัดตรง (3) ไม่มีแถวในทะเบียนนี้ที่ชื่อหรือเครือเดียวกันภายใน 300 ม.–1.5 กม. รวมแถวที่ยังยืนยันนิยามไม่ได้ (4) ไม่มีหลักฐานว่าปิด · ไม่ใช้โรงแรม โรงพยาบาล สำนักงาน คอนโด หน่วยราชการ สถานีขนส่ง และปั๊มน้ำมันเป็นสถานที่หลัก
- **ผล:** เพิ่ม 37 แถว (บิ๊กซี 28 · โลตัส 3 · แม็คโคร 6) ท้ายแท็บ `01_VENUES` แถว 11104–11140 ด้วยค่าที่มีอยู่แล้วในคอลัมน์ (`record_origin = official_cross_dataset_host_addition`, `operation_status = not_revalidated`, `release_status = hold_identity_status_geometry_rights`) อ่านกลับครบ 3,441 เซลล์ (หลัง export แก้ `operation_source_url` ทั้ง 37 แถวให้ชี้หน้าค้นหาสาขาของร้านหลักตามแบบแถวอื่นที่ใช้สถานะเดียวกัน อ่านกลับ 37/37 · export ใหม่ 01:07 น. ต่างจากรอบ 00:26 น. เฉพาะ 37 เซลล์นี้ และเว็บสร้างจากรอบ 01:07) · หลักฐานกิจการที่สอง: หน้าสาขาของแบรนด์อื่น 23 แห่ง · ชื่อจุดร้านอาหารใน CityMETER production เท่านั้น 14 แห่ง · `linked_primary_store_observations` คือจำนวนสาขาที่ใช้เป็นหลักฐาน (รวม 64) และ `official_research_note` บอกรายสาขา ระยะ และแหล่ง
- **พักไว้ 7 แห่ง:** มีในทะเบียนแล้วห่าง 1.2 กม. (1) · อยู่ในศูนย์การค้าที่นับแล้ว (1) · รายการสาขาระบุร้านอื่น ไม่ใช่ร้านนี้ (2) · รายการเดียวที่เข้าได้กับบิ๊กซีสองแห่งในหาดใหญ่ (2) · มีเพียงศูนย์อาหารของผู้ประกอบการเอง (1) · ร้านหลักที่ไม่มีกิจการที่สองไม่เพิ่ม
- **ข้อจำกัด:** ยังไม่ตรวจภาคสนาม สถานะเปิดปัจจุบันรอยืนยัน จุดเป็นจุดอ้างอิงของร้านหลัก ไม่ใช่ทางเข้าหรือรูปทรงอาคาร ชื่อสาขาเป็นชื่อที่แหล่งเผยแพร่ ไม่ใช่ชื่อทางการเต็ม · จำนวนนี้ไม่ใช่ทุกสถานที่ที่ทะเบียนอาจตกหล่น
- **ทีมวิจัยเพิ่มอีก 90 แถวในช่วงเดียวกัน (6–7 พ.ย. 2569):** นับได้ 27 · อีก 63 เป็นพื้นที่ค้าปลีกในอาคารสำนักงาน โรงพยาบาล โรงแรม และสถานี อ่านเป็นพื้นที่ย่อยที่ไม่มีโครงการแม่ในชุดที่ผ่านนิยาม จึงแสดงแต่ไม่นับ (D6) · `office_retail_component` อ่านเป็นพื้นที่ย่อย (`TYPE_GROUP_ADDED_2026_11_07`)
- **รายชื่อร้าน:** `data/tenants/` ไม่เปลี่ยน · `scripts/refresh-tenant-receipt.py` ตรวจว่าสถานที่ที่มีรายชื่อยังอยู่ครบและจำนวน primary ไม่เปลี่ยน แล้วให้ใบรับ (`venueCoreSha256`) ชี้ข้อมูลหลักชุดใหม่ · 43 สถานที่ใหม่มี primary observations ในทะเบียน 74 รายการที่รายชื่อยังไม่มี บันทึกใน `venueCoreRefresh.awaitingRoster` ตัวเลขร้านจึงเป็น “—” ไม่ใช่ 0

## 3. กลุ่มประเภทบนหน้าจอ (Inference — ใช้นำทาง ไม่ใช่การจัดประเภทใหม่)

กลุ่มมาจาก `venue_type` ที่มีหลักฐานก่อน (`groupBasis = evidence`); ถ้าค่านั้นยังไม่อยู่ในตาราง ใช้คำในชื่อประเภทตามลำดับ (`evidence-keyword`); ใช้ `legacy_venue_type` เฉพาะเมื่อ `venue_type` เป็น `unclassified` (`legacy` — แผงสถานที่ติดป้าย “ประเภทตามแหล่งเดิม”); `owner` เฉพาะสถานที่ที่เจ้าของระบุว่าเป็นศูนย์การค้าตาม D6 ค่าต้นทางแสดงในแผงสถานที่เสมอ ประเภทใหม่ 60 ค่าที่มากับกฎของเจ้าของ (และ 92 ค่าที่มากับการปิดคิวรอบ 16:39 น.)ถูกตรวจการจัดด้วยคำทีละค่าแล้วบันทึกลงตาราง (`TYPE_GROUP_ADDED_2026_10_25`) จึงไม่มีประเภทที่ผ่านนิยามซึ่งยังต้องใช้ keyword

| กลุ่ม | สี / รูปทรง | อุปทาน (ระบุตำแหน่งได้) · export 7 พ.ย. 2569 19:36 |
|---|---|---:|
| ศูนย์การค้า (`mall`) | series 1 coral · วงกลม | 294 (283) |
| คอมมูนิตี้มอลล์ (`community`) | series 7 teal · หกเหลี่ยม | 194 (176) |
| ตลาด (`market`) | series 4 lime · ข้าวหลามตัด | 4,029 (4,026) |
| ไฮเปอร์มาร์เก็ตและซูเปอร์มาร์เก็ตที่มีร้านเช่า (`hoststore`) | series 5 mint · กากบาท | 280 (271) |
| พื้นที่ค้าปลีกในโครงการ (`component`) | series 6 sky · ดาว | 5 (5) |
| เอาท์เล็ต (`outlet`) | series 8 blue · วงแหวน | 13 (13) |
| สถานีบริการน้ำมันและจุดพักรถ (`fuel`) | series 10 green · บวก | 1,334 (1,333) |
| อื่น ๆ (`other`) | series 9 slate · ขีด | 7 (6) |

สีจาก `landometer-series-10-v8` ของ LDS 0.9.7 ใน `assets/theme.css` (ไม่มีม่วงหรือน้ำตาล; เว้น series 2–3 ที่เป็นส้ม/ทองซึ่งชนกับสเกลความหนาแน่น) รูปทรงกำกับทุกหมุดและทุกคำอธิบาย สีจึงไม่ใช่ทางเดียวที่บอกประเภท กลุ่ม `hoststore` แยกออกมาเพราะรายการรอตรวจจำนวนมากเป็นไฮเปอร์มาร์เก็ต/ซูเปอร์มาร์เก็ตที่มีร้านเช่า · กลุ่ม `fuel` เปลี่ยนชื่อเป็น “สถานีบริการน้ำมันและจุดพักรถ” (สั้น: สถานีบริการ) รอบนี้ เพราะส่วนใหญ่เป็นสถานีบริการที่มีร้านค้าตามกฎของเจ้าของ ไม่ใช่จุดพักรถ

**ตารางจับคู่ `venue_type` → กลุ่ม** (ตัวเต็มใน `meta.groupMapping.evidence`)

| กลุ่ม | `venue_type` (หลักฐาน) | `legacy_venue_type` |
|---|---|---|
| ศูนย์การค้า | `shopping_center`, `shopping_center_building`, `shopping_center_under_construction`, `retail_complex`, `managed_retail_center`, `lifestyle_center`, `power_center`, `entertainment_anchored_mall`, `specialty_shopping_center`, `specialty_retail_center`, `specialty_retail_and_consumer_services_center`, `department_store_or_retail_complex`, `fashion_retail_and_wholesale_center`, `former_fashion_retail_and_wholesale_center`, `shopping_office_retail_building`, `mixed_use_retail_venue`, `mixed_use_retail_host`, `mixed_use_parent_with_retail_component` | `mega_mall`, `traditional_regional_mall`, `entertainment_anchored_mall`, `mixed_use_super_regional` |
| คอมมูนิตี้มอลล์ | `community_shopping_center`, `community_shopping_center_candidate`, `community_shopping_center_opening_unconfirmed`, `community_mall`, `community_retail_center`, `community_food_and_retail_mall`, `community_retail_and_sports_complex`, `convenience_retail_center`, `retail_and_service_complex`, `retail_and_dining_complex`, `retail_service_plaza`, `specialty_retail_and_cultural_center` | `avenue`, `boutique_retail`, `convenience_strip`, `home_improvement_center` |
| ตลาด | `retail_market`, `fresh_market`, `market_unspecified`, `periodic_market`, `periodic_walking_street_market`, `licensed_type_1_market`, `floating_market`, `street_market`, `night_market`, `community_market`, `roadside_fresh_market`, `wholesale_produce_market`, `mixed_wholesale_retail_market`, `creative_market_and_retail_space`, `fresh_market_and_community_retail_center`, `community_mall_and_managed_market_complex`, `community_market_and_retail_complex`, `retail_bazaar_candidate` | `wet_market_covered`, `night_market`, `wholesale_agricultural_market`, `walking_street` |
| ไฮเปอร์/ซูเปอร์มาร์เก็ตที่มีร้านเช่า | `supermarket_store_or_host_component`, `hypermarket_store_or_host_component`, `wholesale_store`, `wholesale_store_or_host_component`, `specialty_retail_store_or_host_component`, `factory_outlet_retail_store`, `retail_store` | `supermarket_anchored`, `hypermarket_anchored`, `wholesale_club` |
| พื้นที่ค้าปลีกในโครงการ | `managed_retail_component`, `managed_retail_component_candidate`, `retail_zone`, `mixed_use_retail_component`, `office_retail_podium`, `residential_retail_podium`, `resort_retail_component`, `hospital_retail_component`, `duty_free_retail_component`, `transport_terminal_retail_component`, `transport_terminal_retail_scope` | `terminal_duty_free` |
| เอาท์เล็ต | `outlet_shopping_center`, `outlet_center` | `premium_outlet_village`, `standard_outlet` |
| สถานีบริการน้ำมันและจุดพักรถ | `fuel_station_retail_scope_unconfirmed`, `fuel_station_with_source_listed_retail_component`, `fuel_station_with_retail_component`, `fuel_station_with_historical_retail_component`, `multi_tenant_travel_retail_stop`, `highway_retail_rest_stop` | `gas_station_retail` |
| อื่น ๆ | `managed_retail_entertainment_precinct`, `retail_precinct`, `heritage_retail_destination_under_redevelopment`, `retail_food_and_wholesale_mixed_destination` | — |

ตารางข้างบนย่อเฉพาะค่าหลัก รอบ 25 ต.ค. 2569 เพิ่มประเภทที่มากับกฎของเจ้าของ: ตลาด 34 ค่า (เช่น `covered_market_source_reported`, `agricultural_wholesale_market`, `walking_street_market`, `municipal_market`) · ไฮเปอร์/ซูเปอร์มาร์เก็ต 16 (เช่น `grocery_store_with_source_listed_restaurant_component`, `supermarket_with_source_listed_consumer_unit_component`) · ในโครงการ 3 · อื่น ๆ 3 (`historic_retail_district`, `historic_retail_district_walking_street`, `retail_food_district`) · คอมมูนิตี้มอลล์ 1 · รอบ 16:39 น. เพิ่มอีก 92 ค่า (ตลาด 50 · ไฮเปอร์/ซูเปอร์มาร์เก็ต 16 · ในโครงการ 9 · คอมมูนิตี้มอลล์ 8 · อื่น ๆ 4 · สถานีบริการ 3 · ศูนย์การค้า 2; `TYPE_GROUP_ADDED_2026_10_25`)

**กฎคำสำหรับประเภทใหม่** (ลำดับแรกที่ตรงชนะ, `meta.groupMapping.keywords`): `fuel` / `rest_stop` / `travel_retail` → สถานีบริการ · `store_or_host_component` / `retailer_multibusiness` / `store_multibusiness` / `factory_outlet` / `single_retail` / `showroom` / `retail_store` / `supermarket` / `hypermarket` / `grocery` / `wholesale_store` → ไฮเปอร์/ซูเปอร์มาร์เก็ต · `component` / `podium` → ในโครงการ · `market` / `bazaar` → ตลาด · `outlet_center` / `outlet_shopping` / `outlet_village` → เอาท์เล็ต · `community` / `retail_and_dining` / `retail_and_service` → คอมมูนิตี้มอลล์ · `shopping_center` / `shopping_mall` / `department_store` / `plaza` / `mall` → ศูนย์การค้า · ไม่ตรงคำใด → อื่น ๆ

### 3.1 พื้นที่ค้าปลีกในโครงการที่มีชื่อของตัวเอง แสดงตามสิ่งที่เป็น (0.1.23, 7 พ.ย. 2569 · D36)

เจ้าของ 7 พ.ย. 2569 16:35: “จามจุรีสแควร์ ก็ไม่แสดงเป็นศูนย์การค้า พี่จัดดีๆให้หน่อยสิ ให้ consitent เข้าใจง่าย หาสาเหตุให้เจอ จะได้แก้เคสแบบเดียวกันนี้ที่เกิดกับอาคารอื่นๆด้วยให้ครบ” · “Park Silom, Life Center ที่ Q House ลุมพินี … ไม่มี ควรจะมีนะ”

- **สาเหตุ (Observed fact):** `venue_type` บอกว่าสถานที่ตั้งอยู่ตรงไหน (พื้นที่ค้าปลีกของโครงการใหญ่) ไม่ได้บอกว่าเป็นสถานที่แบบไหนสำหรับผู้ใช้ · ทุกประเภทกลุ่ม “ในโครงการ” จึงไปอยู่กลุ่ม `component` ซึ่งหน้าแรก (D33 ชุดศูนย์การค้า) ไม่แสดง · จามจุรีสแควร์ Park Silom และสยามสเคป นับอยู่แล้วแต่ไม่เคยขึ้นพร้อมศูนย์การค้า
- **กฎ (`scripts/build-data.py#retail_identity`, Inference เพื่อนำทาง):** แถวที่กลุ่มเป็น `component` และไม่มีโครงการแม่ในชุดที่ผ่านนิยาม คงเป็น `component` เฉพาะเมื่อเป็นโซน — บทบาทลูก (`child_zone` ฯลฯ) · ประเภทโรงพยาบาล สถานีขนส่ง ดิวตี้ฟรี หรือ `retail_zone` · ชื่อบอกโรงแรม โรงพยาบาล สนามบิน มหาวิทยาลัย หรือศูนย์ราชการ · ไม่มีชื่อของตัวเอง (“พื้นที่ค้าปลีก …”, “พื้นที่พาณิชย์ …”) — นอกนั้น ร้านหลักที่มีร้านเช่า (โลตัส บิ๊กซี แม็คโคร อินเด็กซ์ ท็อปส์ ฟู้ดแลนด์ โฮมโปร ไทวัสดุ โกลบอลเฮ้าส์) → `hoststore` · ประเภทตลาด → `market` · ชื่อบอกคอมมูนิตี้ หรือโพเดียมสำนักงาน ที่พัก รีสอร์ท และพื้นที่บริการ → `community` · อื่น → `mall` · ตัดสินจากชื่อ ไม่ใช่ผู้บริหาร (สำนักงานจัดการทรัพย์สินจุฬาฯ บริหารจามจุรีสแควร์และสยามสเคป) · `groupBasis = retail-identity` · แผงสถานที่เขียน “ทะเบียนจัดเป็นพื้นที่ค้าปลีกในอาคารหรือโครงการ · บนแผนที่แสดงตามลักษณะสถานที่ซึ่งมีชื่อของตัวเอง” · ค่าต้นทางยังอยู่ในแผงเสมอ
- **ผล (export 7 พ.ย. 2569 19:36):** เปลี่ยนกลุ่ม 126 แถว (`hoststore` 69 · `mall` 34 · `community` 20 · `market` 3) · คงเป็น `component` 5 แห่งที่นับได้ · ตามกฎ D6 พื้นที่ในโครงการที่โครงการแม่ไม่อยู่ในชุดและอ่านได้ว่าเป็นศูนย์การค้าหรือคอมมูนิตี้มอลล์ นับเป็นสถานที่ของตัวเองเพิ่ม 11 แห่ง (เช่น ไลฟ์ เซ็นเตอร์ คิวเฮ้าส์ ลุมพินี · เดอะ พอร์ทอล · RQ49 Mall · เอกมัย คอร์เนอร์ · เอ็มสเปซ) นับได้ 6,151 → 6,162 · รายชื่อในรายงาน build (`componentsRegrouped`)
- **ข้อจำกัด:** การอ่านจากชื่อเป็นการตีความ ไม่ใช่การจัดประเภทใหม่ของทะเบียน · ถ้าทะเบียนผูกโครงการแม่ภายหลัง แถวจะกลับเป็นพื้นที่ในโครงการและไม่นับซ้ำ (D6)

### 3.2 ย่านที่มีศูนย์การค้าเป็นพื้นที่ย่อย แสดงกับศูนย์การค้า (0.1.28, 8 พ.ย. 2569 · D41)

เจ้าของ 8 พ.ย. 2569 01:18 ตอบ “Yes” ต่อคำถาม “Siam Square: should Siam Square One, Siam Scape and the other places in the block become its sub-areas?” — บล็อกตามที่เจ้าของกำหนด 7 พ.ย. 2569 20:58 น. (ระหว่างถนนพระราม 1 ถึงซอยจุฬาฯ 64 และระหว่างถนนพญาไทถึงถนนอังรีดูนังต์)

- **ปัญหา (Observed fact):** เมื่อสามแห่งในบล็อกเป็นพื้นที่ย่อย จะไม่นับและไม่วาดแยก ส่วนสยามสแควร์มีประเภทในทะเบียนเป็นย่านค้าปลีก (`retail_precinct` → กลุ่ม `other`) ซึ่งหน้าแรก (D33) ไม่แสดง ทั้งบล็อกจะหายจากหน้าแรก
- **กฎ (`scripts/build-data.py#groups_from_subareas`, Inference เพื่อนำทาง):** สถานที่ที่นับได้ กลุ่ม `other` และมีพื้นที่ย่อย (ลูกที่ไม่นับ) อยู่ในกลุ่ม `mall` `community` หรือ `outlet` แสดงในกลุ่มที่พื้นที่ย่อยเป็นมากที่สุด (เสมอกันเรียง mall → community → outlet) · `groupBasis = sub-areas` · ยังนับครั้งเดียว และพื้นที่ย่อยไม่นับ · ประเภทในทะเบียนไม่เปลี่ยน แผงสถานที่บอกในหลักฐานรายช่องว่าทะเบียนจัดไว้อย่างไร · รายการทุกแถวที่กฎนี้เปลี่ยนอยู่ใน `meta.checks.groupsFromSubAreas` และ `data/build-report.json#groupsFromSubAreas`
- **ผล (export 7 พ.ย. 2569 23:55 + 12 ช่อง 8 พ.ย. 2569):** หนึ่งแถว — สยามสแควร์ `other` → `mall` (พื้นที่ย่อย สยามสแควร์วัน `mall` · เซ็นเตอร์พอยต์ `mall` · สยามสเคป `component`)

## 4. ผู้บริหาร (Inference)

`operator_name` เป็นข้อความอิสระ จึงจัดกลุ่มด้วยตารางชื่อที่ประกาศไว้: หาชื่อบริษัทในตารางที่ปรากฏ **ก่อนสุด** ในข้อความ (รวมสะกดไทย/อังกฤษของบริษัทเดียวกัน) ไม่พบในตาราง → กลุ่ม “อื่น ๆ” โดยคงชื่อที่ตัดคำอธิบายในวงเล็บออกแล้ว · ว่าง → “ยังไม่มีข้อมูล” · ข้อความดิบแสดงในแผงสถานที่เสมอ กราฟผู้บริหารเรียกว่า **สัดส่วนจำนวนสถานที่** ไม่ใช่ market share (LDS Location Profile `li.market_share`) และไม่ได้ถ่วงด้วยขนาด

| กลุ่ม | คำที่ใช้จับ | อุปทาน |
|---|---|---:|
| CP Axtra (Lotus’s) | CP Axtra · ซีพี แอ็กซ์ตร้า · Lotus’s | 202 |
| Central Pattana | Central Pattana · เซ็นทรัลพัฒนา · Siam Future Development · SF Development | 55 |
| Central Retail | Central Retail · (CRP) · สรรพสินค้าเซ็นทรัล | 32 |
| ปตท. บริหารธุรกิจค้าปลีก | ปตท.บริหารธุรกิจค้าปลีก · PTT Retail | 25 |
| Home Product Center | Home Product Center · โฮม โปรดักส์ เซ็นเตอร์ | 22 |
| Index Living Mall | Index Living Mall · อินเด็กซ์ ลิฟวิ่งมอลล์ · The Walk Company | 18 |
| เทศบาลและ อปท. | เทศบาล · องค์การบริหารส่วนตำบล · อบต. | 17 |
| Asset World (AWC) · ALLY · Big C | ชื่อไทย/อังกฤษของแต่ละบริษัท | 11 · 11 · 11 |
| OLM / Pena House | OLM PROPERTY · Outlet Mall Company · Pena House | 10 |
| The Mall Group | The Mall Group · เดอะมอลล์ | 9 |
| JAS Asset · Siam Piwat · Major Cineplex · Chic Republic · MBK · Minor | ชื่อไทย/อังกฤษของแต่ละบริษัท | 7 · 6 · 6 · 6 · 4 · 3 |
| อื่น ๆ (ชื่อของตัวเอง 160 ราย) | — | 225 |
| ยังไม่มีข้อมูล | — | 5,399 |

รอบนี้ผู้บริหารที่ระบุได้มี 680 จาก 6,079 แห่ง (ตลาดและสถานีบริการที่ผ่านด้วยกฎของเจ้าของส่วนใหญ่ยังไม่มีชื่อผู้บริหาร) กราฟผู้บริหาร (amCharts) จึงวาดเฉพาะผู้บริหารที่ระบุชื่อได้ 12 อันดับแรก และบอกจำนวน “ผู้บริหารรายอื่น” กับ “ยังไม่ระบุผู้บริหาร” ไว้เหนือกราฟเสมอ (ไม่ให้แท่งของรายการที่ไม่รู้กดแท่งอื่นจนอ่านไม่ได้) เปอร์เซ็นต์คิดจากสถานที่ทั้งหมดในจังหวัดที่อ่าน (หรือทั้งประเทศ) · ข้อสังเกต: “บริษัท ปิโตรเลียมไทยคอร์ปอเรชั่น จำกัด” (33) และ “Tops” (13) ยังไม่อยู่ในตารางชื่อ จึงแสดงเป็นชื่อของตัวเอง

## 5. พื้นที่

- **สมาชิกภาพ:** point-in-polygon ของจุดอ้างอิงที่เลือกแล้ว กับขอบเขตเขต/อำเภอความละเอียดเต็ม (shapely `covers`; จุดบนเส้นแบ่งใช้รหัสที่น้อยกว่า) คำนวณครั้งเดียวใน pipeline แล้วบันทึก `provinceCode` / `districtCode` ต่อแถว ไม่ใช้ชื่อหรือที่อยู่จัดเข้าพื้นที่ และไม่จับเข้าพื้นที่ใกล้ที่สุด จุดที่อยู่นอกขอบเขตทุกเขตไม่มีพื้นที่ (รอบนี้ 10 แห่งที่ผ่านนิยาม — ตลาดริมทะเลหรือริมแม่น้ำชายแดน เช่น ตลาดอาหารทะเลอ่างศิลา ตลาดริมเมย — นับในอุปทานแต่ไม่อยู่ในเขตใด และรายการที่ยังไม่ผ่านนิยาม 1 จุด)
- **รหัส:** จังหวัดใช้ `abbrEn` ของ production (77) · เขต/อำเภอใช้รหัส 4 หลักของ production; ขอบเขต `4026` เวียงเก่า (ขอนแก่น) ไม่มีใน production จึงจับคู่ด้วยชื่อในจังหวัดเดียวกันเป็น `4029` (`meta.checks.districtCodeRemaps`)
- **พื้นที่ ตร.กม.:** ใช้ `areaSqm` ของ CityMETER production (เท่ากับพื้นที่ geodesic ของรูป RTSD) เป็นตัวหารของ “แห่ง/ตร.กม.”; พื้นที่จังหวัด = ผลรวมพื้นที่เขตของจังหวัด
- **รูปทรงที่แสดง:** สองระดับ เพื่อการแสดงผลเท่านั้น — `data/districts.geojson` ลดจุด 0.25% แบบ keep-shapes (planar, precision 0.0001) สำหรับมุมประเทศและจังหวัด และ `data/districts/<จังหวัด>.geojson` ลดจุดตามขนาดเขต (เขตเล็กกว่า 25 ตร.กม. ห่างไม่เกิน 6 ม. · ไม่เกิน 150 ตร.กม. 15 ม. · ใหญ่กว่านั้น 35 ม.; precision 0.00001) ที่หน้าเว็บโหลดทีละจังหวัดเมื่ออ่านจังหวัดนั้นหรือซูมเข้า ≥ 9 (`js/district-detail.js`) · สีพื้นที่วาดใต้ชั้นน้ำของแผนที่ฐาน แม่น้ำจึงยังเป็นแม่น้ำ (D24) · จังหวัด dissolve จากเขตแบบหยาบ ตำแหน่งป้ายใช้ representative point ของรูปทรงเต็ม สมาชิกภาพไม่เปลี่ยนตามการลดจุด
- **เปลี่ยนรูปเขต 4 พ.ย. 2569 (D24):** `scripts/relocate-districts.py` คำนวณ `provinceCode` / `districtCode` ใหม่จาก snapshot เดิมด้วยฟังก์ชันเดียวกับ build (แถวอื่นไม่เปลี่ยน) — สถานที่ที่ผ่านนิยาม 80 แห่งย้ายเขต (65 แห่งตรงกับเขตในที่อยู่ของตัวเอง เทียบกับ 10 แห่งของรูปเดิม) และรายการบริบท 47 แถว · ที่อยู่ในฝั่งคลองสาน 17 แห่งอยู่ในคลองสานทั้งหมด (เดิม 3 แห่งตกในธนบุรี)
- เขต/อำเภอเป็นขอบเขตการปกครอง ไม่ใช่ catchment หรือย่านการค้า และกรอบจังหวัดเป็นบริบทนำทาง ไม่ใช่คำยืนยันเขตปกครอง

## 6. ข้อค้นพบแรก (Owner decision D1 → D33)

**D33 — หน้าแรกนับศูนย์การค้า คอมมูนิตี้มอลล์ และเอาท์เล็ต แล้วเรียงเขตตามจำนวน** (เจ้าของ 7 พ.ย. 2569 11:56 น. ถามว่า “ได้ first aha แบบนี้มันใช่มั้ย” แล้วเลือกข้อ ข “และดูเรื่อง หน้าจอด้วย ตอนนี้รกมาก และ ส่วนที่ highlight ที่ควร focus ไม่ได้ zoom to fit กับ viewport เลย”) · คำนวณทุกครั้งที่ข้อมูลหรือตัวกรองเปลี่ยน (`js/area-insight.js` `rank: 'count'`; Python คำนวณซ้ำไว้ตรวจใน `meta.checks.firstView`, `scripts/build-data.py#first_finding_d33`):

1. ตัวกรอง “ประเภท” เริ่มที่ชุด `centres` = ศูนย์การค้า + คอมมูนิตี้มอลล์ + เอาท์เล็ต (`js/model.js GROUP_SETS`) · ลิงก์ที่ไม่มี `group` อ่านชุดนี้ · `?group=all` = ทุกประเภท · ชิปตัวกรองบอกชุดที่ใช้ กดล้างแล้วเห็นทุกประเภท
2. ใช้อุปทานที่นับได้และมี `districtCode` ตามตัวกรอง (ก่อนการเลือกพื้นที่)
3. หาเขตที่มีจำนวนมากที่สุดของประเทศ (เสมอกันใช้แห่ง/ตร.กม. แล้วรหัสน้อยกว่า) → จังหวัด P ของเขตนั้น (ถ้าผู้ใช้เลือกจังหวัด ใช้จังหวัดนั้น)
4. เรียงเขตใน P ตามจำนวน (กติกาเสมอกันเดียวกัน) เลือก 3 เขตแรก
5. ตัวตั้ง = จำนวนในสามเขต · ตัวหาร = ที่ระบุตำแหน่งได้ใน P · บริบทพื้นที่ = พื้นที่สามเขต ÷ พื้นที่ P (แผงไม่แสดงอัตราส่วนความหนาแน่นแล้ว เพื่อให้ตัวเลขบนหน้าแรกน้อยลง)
6. **บรรทัดรถไฟฟ้า:** สัดส่วนของสถานที่ในสามเขตที่อยู่ห่างสถานีที่เปิดให้บริการไม่เกิน 500 ม. เทียบกับสถานที่ในเขตอื่นของ P (ตัวหารเดียวกัน: ที่ระบุตำแหน่งได้) · ระยะเป็นเส้นตรงระหว่างจุดอ้างอิงของสถานที่กับจุดอ้างอิงของสถานี (haversine) ไม่ใช่ระยะเดิน · แสดงเมื่อสถานที่ใน P อยู่ใกล้สถานีอย่างน้อย 1 แห่ง จังหวัดที่ไม่มีรถไฟฟ้าจึงไม่มีบรรทัดนี้ · โหลดไฟล์สถานีไม่ได้ = ไม่มีบรรทัดนี้ ไม่ใช่ 0%

รอบนี้ (export 7 พ.ย. 2569 19:36 น. หลัง D36 และจุดจากอาคารที่ OSM ตั้งชื่อ; ขอบเขต RTSD; สถานีจาก CityMETER · Transit release `transit-data-2026-10-31-r1`): ปทุมวัน 25 · วัฒนา 20 · คลองเตย 11 แห่ง → **56 จาก 232 แห่งของกรุงเทพฯ (24%) บนพื้นที่ 34.47 จาก 1,571.37 ตร.กม. (2.2%)** · **36 จาก 56 แห่ง (64%) อยู่ในระยะ 500 ม. จากสถานี เทียบกับ 69 จาก 176 แห่ง (39%) ในเขตอื่นของกรุงเทพฯ** (0.1.19–0.1.22: 46 จาก 199 · 65% เทียบ 39%; ส่วนที่เพิ่มมาจากศูนย์ที่ทะเบียนจัดเป็นพื้นที่ในโครงการซึ่ง D36 อ่านเป็นศูนย์การค้าหรือคอมมูนิตี้มอลล์ เช่น จามจุรีสแควร์ สยามสเคป ไลฟ์ เซ็นเตอร์ และศูนย์ที่ได้จุดรอบนี้ เช่น มาร์เช่ ทองหล่อ ริเวอร์ ซิตี้) — เป็นคำอธิบายการกระจุกตัวของสถานที่ที่ผ่านนิยามในทะเบียนนี้ ไม่ใช่คำตัดสินศักยภาพ ช่องว่างตลาด footfall หรือผลของรถไฟฟ้าต่อยอดขาย (Observed fact ของทะเบียน · ความสัมพันธ์กับรถไฟฟ้าเป็น Inference ที่ต้องทดสอบ §13)

ล้างตัวกรองเป็นทุกประเภท ข้อค้นพบแรกใช้กฎเดียวกัน (เรียงตามจำนวน): รอบนี้ได้อำเภอเมืองเชียงใหม่ 103 · สันทราย 22 · สันกำแพง 14 แห่ง = 139 จาก 234 แห่งของเชียงใหม่ (59%) เป็นตลาด 106 แห่ง และไม่มีบรรทัดรถไฟฟ้า · ทะเบียนเก็บตลาดเชียงใหม่ไว้ละเอียด ตัวเลขนี้จึงสะท้อนความครอบคลุมของทะเบียนด้วย (Inference)

### 6.1 สถานีรถไฟฟ้า (CityMETER · Transit, 0.1.19)

- **ที่มา:** `data/stations.json` สร้างด้วย `python3 scripts/build-stations.py <checkout ของ montri-th/transit>` · ระบุ commit (`5f5232d…`), SHA-256 ของ `data/transit.json` (`0916636a…0bb18`), release `transit-data-2026-10-31-r1` และ asOf 31 ต.ค. 2569 · กฎเดียวกับ CityMETER · Hotel: ใช้เฉพาะสถานีสถานะ `operating` (อยู่ในรายชื่อสถานีปัจจุบันของผู้ให้บริการ) 195 สถานี · สถานีที่กำลังสร้างเป็นโครงการ ไม่ใช่บริการ จึงไม่วาดและไม่นับ · สถานีร่วม (interchange) เป็นหนึ่งรายการต่อสาย ตาม Transit
- **สถานีใกล้สุดของแต่ละสถานที่ (`js/stations.js#attachNearestStations`):** สถานีที่ใกล้ที่สุดภายใน 2 กม. แบบเส้นตรง (haversine) จากจุดอ้างอิงของสถานที่ · เกิน 2 กม. = “เกิน 2 กม.” · ไม่มีพิกัด = ไม่มีค่า (ไม่ใช่ 0)
- **มุมมองสถานี (`?station=<id>`):** สถานที่ตามตัวกรองที่อยู่ในระยะ 500 ม. เรียงใกล้ก่อน พร้อมระยะ · สถานที่ที่ใกล้สองสถานีถูกนับที่ทั้งสองสถานี มุมมองสถานีจึงไม่บวกข้ามสถานี · ไม่เติมสีพื้นที่และไม่แสดงป้ายเขตระหว่างเปิดสถานี
- **ข้อจำกัด:** ระยะเส้นตรงไม่ใช่ระยะเดินหรือ catchment · จุดอ้างอิงของสถานีไม่ใช่ทางออก · ไม่ได้บอกจำนวนผู้โดยสาร

**D1 (25 ต.ค. 2569 – 0.1.18)** — สูตรเดิม ยังใช้กับรายการ “เขตที่แน่นที่สุด” กราฟ และสีของพื้นที่ (เติมสีเฉพาะสามเขตที่โฟกัส):

ทุกครั้งที่ข้อมูลหรือตัวกรองเปลี่ยน (`js/area-insight.js`; Python คำนวณซ้ำไว้ตรวจใน `meta.checks.aha`):

1. ใช้อุปทานที่นับได้และมี `districtCode` ตามตัวกรอง (ก่อนการเลือกพื้นที่)
2. หาเขตที่มีแห่ง/ตร.กม. สูงสุดของประเทศ (เสมอกันใช้จำนวน แล้วรหัส) → จังหวัด P ของเขตนั้น (ถ้าผู้ใช้เลือกจังหวัด ใช้จังหวัดนั้น)
3. เรียงเขตใน P ตามแห่ง/ตร.กม. เลือก 3 เขตแรกที่มีอย่างน้อย 1 แห่ง
4. ตัวตั้ง = จำนวนในสามเขต · ตัวหาร = อุปทานที่ระบุตำแหน่งได้ใน P · บริบทพื้นที่ = ผลรวมพื้นที่สามเขต ÷ พื้นที่ P

รอบนี้ (รูปเขต RTSD, 4 พ.ย. 2569): สัมพันธวงศ์ 4.97 · พระนคร 4.64 · บางรัก 4.46 แห่ง/ตร.กม. → **50 จาก 861 แห่งของกรุงเทพฯ (5.8%) บนพื้นที่ 10.83 จาก 1,571.37 ตร.กม. (0.69%)** — แผงแสดงอัตราส่วนสองค่านี้เป็น “แน่นกว่าค่าเฉลี่ยของกรุงเทพฯ 8 เท่า” (สัดส่วนจำนวน ÷ สัดส่วนพื้นที่ = ความหนาแน่นของสามเขต ÷ ความหนาแน่นของจังหวัด ปัดเป็นจำนวนเต็ม แสดงเมื่อ ≥ 2) (รอบ 15:06 น.: 49 จาก 838 · ก่อนรวมกฎรายประเภทของเจ้าของ: ปทุมวัน บางรัก ราชเทวี 36 จาก 185 · ก่อน D6: 32 จาก 181) ตลาดในย่านเยาวราช–สำเพ็งและพระนครทำให้สามเขตนี้ขึ้นมาแทน เป็นคำอธิบายการกระจุกตัวของสถานที่ที่ผ่านนิยามในชุดนี้ ไม่ใช่คำตัดสินศักยภาพ ช่องว่างตลาด หรือ “ทำเลทอง”

## 7. สเกลสีของพื้นที่ (LDS 0.9.7)

| ระดับ | ค่า | สเกล | วิธีให้สี |
|---|---|---|---|
| เขต/อำเภอ (ในจังหวัดที่อ่าน) | แห่ง/ตร.กม. | `density.area` LUT 41 ค่า (`scaleVersion 554812a7…`) | ใช้ครบ 41 ค่า ตามลำดับค่าของเขตที่อ่าน |
| จังหวัด (ทั้งประเทศ, zoom < 9) | จำนวนสถานที่ที่ระบุตำแหน่งได้ | `count` LUT 41 ค่า (`scaleVersion 4ff5c1fb…`) | ใช้ครบ 41 ค่า ตามลำดับค่าของจังหวัด |
| ช่องตารางพื้นที่ × ประเภท | จำนวนสถานที่ | `count` LUT 41 ค่า | ใช้ครบ 41 ค่า ตามลำดับค่าของช่อง |

**คำสั่งเจ้าของ 25 ต.ค. 2569: สเกลสีใช้ครบ 41 สีตาม LDS** — ทุกพื้นที่และทุกช่องใช้ตัวอย่างสีหนึ่งใน 41 ค่าของ LUT ตรง ๆ (DATAVIZ-02 continuous ramp) ไม่ใช้ชุด 3/5 ระดับอีก วิธี (consumer-supplied ตาม DATAVIZ-02 และประกาศในคำอธิบายแผนที่): เรียงค่าที่มากกว่า 0 ของพื้นที่ที่กำลังอ่าน แต่ละค่าได้ตำแหน่ง LUT ตาม mid-rank percentile ที่ยืดให้ค่าต่ำสุดอยู่ index 0 และค่าสูงสุดอยู่ index 40 (ค่าเดียวอยู่ index 40) ค่าเท่ากันได้สีเดียวกัน ไม่มีการ interpolate ระหว่างตัวอย่าง ค่าสูงสุดปิดสเกลเอง (ไม่มีชั้นเปิดหรือการ clamp) และแผนที่ ป้าย กราฟ และคำอธิบายแผนที่อ่านค่าชุดเดียวกัน (`buildRamp` ใน `js/scales.js`) · class table 3/5/7/9 ของ LDS ยังเก็บไว้เป็น token คงที่ (`--scale-count-1…5`) แต่ไม่ใช้ระบายข้อมูล

ความต่างที่ต้องรายงาน: สัญญา MapLegend ของ LDS 0.9.7 เขียนถึง classes 3/5/7/9 ส่วน DATAVIZ-02 เปิดให้ใช้ continuous ramp ของ LUT 41 ค่าเดียวกัน — หน้านี้ทำตามคำสั่งเจ้าของ (อำนาจสูงกว่า LDS ตามลำดับของโครงการ) โดยไม่สร้างสีใหม่

- คำอธิบายแผนที่แสดงทั้ง 41 สีเรียงกัน พร้อมค่าจริงที่ตำแหน่งของค่าต่ำสุด สูงสุด และค่าที่ใกล้ index 10 · 20 · 30 (ห่างกันอย่างน้อย 8 ตำแหน่ง) ชื่อที่ screen reader อ่านบอกวิธี ค่าต่ำสุด สูงสุด และหน่วย · สีคำนวณใหม่ตามตัวกรองและพื้นที่ที่อ่าน จึงเทียบสีข้ามตัวกรองไม่ได้ — เทียบด้วยตัวเลขในกราฟอันดับหรือตาราง
- สถานะข้อมูลตาม EVID-05: **ศูนย์ที่วัดได้** (เขตในจังหวัดที่ไม่มีสถานที่) ใช้ตัวอย่าง index 0 พร้อมเส้นขอบศูนย์ และช่องศูนย์ในคำอธิบายใช้สีเดียวกับที่แผนที่วาด · **ไม่มีข้อมูล** ไม่ระบาย · **นอกขอบเขตการอ่าน** ไม่ระบาย เหลือเส้นขอบบาง
- HEX เดียวกันทั้งธีมสว่างและมืด ไม่มีสูตร dark ไม่ปรับความโปร่งใสของสีข้อมูล ป้ายชื่อพื้นที่เป็นชิปหมึกที่มีพื้นรองของตัวเอง ตัวเลขในช่องตารางที่วางบนสีซึ่งหมึกทั้งสองแบบไม่ถึง 4.5:1 (`count` index 27–29) อยู่บนพื้นรองกลาง โดยสีของช่องยังเป็นสีข้อมูลเดิม
- เมื่อซูมเกิน 14.5 สีพื้นที่ถอยเป็นเส้นขอบ เพื่อให้หมุดและอาคารอ่านได้

## 8. สถานะ

| `operation_group` | บนหน้าจอ |
|---|---|
| `operating_source_evidence`, `official_listing_not_field_verified` | มีหลักฐานว่าเปิด |
| `partially_operating` | ทยอยเปิด |
| `needs_review`, `current_operation_unconfirmed`, `operation_conflict`, `recent_source_evidence_current_operation_separate`, `historical_primary_current_reverification_pending`, ว่าง | รอยืนยันสถานะ (แผงสถานที่บอกรายละเอียดของแต่ละค่า) |
| `future_project` | กำลังจะเปิด (หมุดเส้นประ) |
| `closed_source_evidence` | ปิดแล้ว (หมุดกลวง; หลักฐานรายช่องเขียนว่า “ปิดตามหลักฐาน”) |

สถานะมาจากแหล่งที่อ้างไว้ ไม่ใช่การตรวจภาคสนาม “ผ่านนิยาม” จึงไม่เท่ากับ “ยืนยันว่าเปิดวันนี้” · รอบนี้อุปทาน 6,079 แห่งเป็นรอยืนยันสถานะ 4,193 แห่ง (ส่วนใหญ่เป็นตลาด) และมีหลักฐานว่าเปิดหรือทยอยเปิด 1,886 แห่ง

## 9. รายละเอียดสถานที่และหลักฐานรายช่อง

แผงสถานที่โหลดรายละเอียดจาก `data/details/NN.json` (NN = FNV-1a 32-bit ของ `venue_id` แบบ UTF-8 mod จำนวน shard; อย่างน้อย 32 shard และเพิ่มเป็นสองเท่าเมื่อเฉลี่ยเกิน 40 สถานที่ต่อ shard) แต่ละช่องมีฐานของค่า ลิงก์แหล่งสาธารณะ และวันที่ตรวจเมื่อมี · **หน้าจอหลักไม่มี caveat (เจ้าของสั่ง 25 ต.ค. 2569):** ส่วนที่มองเห็นแสดงค่าอย่างเดียว ส่วนวิธี ฐานของค่า คำว่า “ไม่ใช่ …” บทบาทพิกัด ขอบเขตของเวลาเปิด และวิธีของขนาด อยู่ในรายการ “หลักฐานรายช่อง” ที่พับไว้ (test ตัด `<details>` ออกแล้วต้องไม่เหลือคำเหล่านี้)

- **ลิงก์:** เก็บเฉพาะ URL สาธารณะ ตัดลิงก์ `docs.google.com` / `drive.google.com` / `googleusercontent.com` และ host ภายในออก หลักฐานที่เป็นเอกสารภายในแสดงเป็นข้อความไม่มีลิงก์ test ตรวจทุกไฟล์ใน repository ว่าไม่มีรหัสไฟล์ Drive/Sheets
- **เวลาเปิด:** แสดงเวลา ส่วนขอบเขตของเวลา (`opening_hours_scope` — บางแห่งเป็นเวลาของร้านหลัก ไม่ใช่ของทั้งสถานที่) และหมายเหตุในวงเล็บท้ายข้อความเวลา (เช่น ที่มาของเวลาหรือ “operating days not specified”) อยู่ในหลักฐานรายช่องพร้อมข้อความเต็ม
- **ตัวเลขหลักบนแผง (D18):** ร้านที่ยืนยันว่าอยู่ข้างใน · GLA หรือจำนวนชั้นที่แหล่งรายงานโดยตรง · วันหรือปีที่เปิด — ค่าประมาณเดิม (D3) ไม่ขึ้นเป็นตัวเลขหลัก ค่าที่ไม่มีไม่แสดงเป็น 0 แต่ไม่ขึ้นช่อง · พิกัดและเมื่อที่อยู่กับจุดอยู่คนละจังหวัด อยู่ในหลักฐานรายช่อง
- **ขนาด (Owner decision D3):** GLA/GFA ที่แหล่งรายงานโดยตรงแสดงพร้อมขอบเขต · ค่าประมาณเดิม (`gla_sqm_legacy`, `gfa_sqm_legacy`) แสดง **เฉพาะในแผงสถานที่** เป็น “พื้นที่เช่าราว … ตร.ม.” และเฉพาะเมื่อไม่มีค่าที่แหล่งรายงานโดยตรง วิธีคำนวณกับคำว่า “ค่าประมาณจากทะเบียนเดิม ไม่ใช่ GLA ทางการ” อยู่ในหลักฐานรายช่อง ไม่อยู่ในตัวกรอง กราฟ ตาราง ผลรวม หรืออันดับ
- **ร้านที่อยู่ข้างใน:** นับเฉพาะลิงก์ที่ชุดข้อมูลร้านค้าของ CityMETER ยืนยันแล้ว แยกตามชุดข้อมูลต้นทาง candidate ไม่นับ ลิงก์ไป Luxury Brands แสดงเมื่อ CityMETER id ของสถานที่อยู่ในข้อมูลที่หน้านั้นเปิดได้
- **รหัส:** `venue_id` (join key) · Shopping Center id (`mall_external_id`) · CityMETER id (`citymeter_venue_id`) พร้อมลิงก์บันทึกใน production เมื่อมี

### 9.1 รายชื่อร้านและลำดับ — D19 (25 ต.ค. 2569)

`data/tenants/NN.json` เป็นรายชื่อแบบ lazy ใช้ FNV-1a UTF-8 ของ venue ID mod **32** คงที่ แยกจาก detail shards โหลดเมื่อเลือกสถานที่ แสดง 10 รายการแล้วดูเพิ่มไม่เกิน 10 จนครบ คงจำนวนที่ขยายเมื่อแผงวาดใหม่ ปุ่มดูเพิ่มไม่ผ่านทางเดินกล้อง โหลดผิดพลาดลองใหม่ได้ ชื่อยังอ่านได้เมื่อไม่มี/โหลดโลโก้ไม่สำเร็จ

รายชื่อเผยแพร่ 2,230 รายการใน 461 venue จาก 2,232 source observations: primary graph เดิม 1,579 (อีก 10 อยู่กับ host นอกชุด qualified ที่หน้าเว็บแสดง) + official restaurant chain ที่ตรวจ exact named host 644 + Grocery locatives ที่ตรง parent relationship เดิม 7 แยก `sourceRole` และ `relationshipBasis` ชัดเจน ไม่ใช้ spatial/name candidates ที่ยังไม่ผ่าน ไม่เขียนกลับความสัมพันธ์ต้นทางหรือเปลี่ยน core data โดยอัตโนมัติ พัก Greyhound The Crystal และ Pizza Hut/Taco Bell Pantip Chiang Mai เพราะ canonical venue ID กำกวม; Mahatun Plaza อยู่นอกชุด qualified จึงคงเป็น omitted source item

ตัวเลขและรายชื่อในแผงสถานที่ใช้ roster ล่าสุด ส่วนแผนที่ การ์ด ย่าน กราฟ และตารางคง primary-link snapshot เดิม รายชื่อเป็นการสังเกตตามแหล่ง/วันที่ ไม่ใช่ tenant census ทั้งศูนย์หรือคำยืนยันว่าทุกร้านเปิดวันนี้ `sourceUrl` เป็นหลักฐานรายรายการ (เก็บหลายลิงก์ใน `sourceUrls`); `checkedOn`/`sourceDate`/สถานะต้นทางคงแยกกัน สถานะขัดกันแสดงข้างชื่อ

คงสาขาที่ native ID/โทรศัพท์ต่างกัน เช่น MK M111/M206 ที่เดอะมอลล์งามวงศ์วาน บัตร Dairy Queen สองศูนย์ที่ยังแยกหน้าร้านไม่ได้เก็บเป็นรายการเดียวต่อ brand/host พร้อม `sourceObservations`, `sourceObservationCount` และ `identityStatus`; source observations จึงมากกว่ารายการแสดงผลสองรายการ

ลำดับ `venue-role-v1`: ร้านหลักที่มีหลักฐาน → ร้านหลักซึ่งตรงชื่อศูนย์ → บทบาทจาก positioning ทางการใน `data/tenant-profiles.json` (11 ศูนย์) → specialty/รูปแบบศูนย์ → บทบาททั่วไป โดยบทบาทเท่ากันเรียงชื่อ สาขา และ ID คงที่ Community/hoststore/market เน้นของใช้และอาหาร; สถานีบริการเน้นอาหาร เครื่องดื่มและร้านสะดวกซื้อ; ศูนย์แฟชั่นหรูหรือไอทีที่มี positioning ใช้บทบาทนั้นนำ เป็นการประเมินของ CityMETER ไม่มีคะแนนจากขนาดเครือ โลโก้ GLA เดิม ยอดขาย หรือ footfall ไม่ใช่อิทธิพลที่วัดจริง เคาน์เตอร์ในห้างไม่ถูกอ่านเป็นห้างทั้งแห่ง และหมวดผสม restaurant/cafe ใช้ “อาหารและเครื่องดื่ม” โดยไม่เดาประเภทย่อย

โลโก้ 1,609 รายการใช้ไฟล์เดิม 178 ไฟล์ จับคู่ `dataset|brandId` และตรวจ SHA-256 กับ `assets/tenant-logos-manifest.json`; ไม่มี fuzzy matching โหลดภาพ lazy เฉพาะรายการที่แสดง ใช้พื้นรองตาม asset ให้เห็นทั้งสองธีม การรวบรวมไฟล์ไม่ใช่ใบอนุญาตเครื่องหมายการค้า

สร้างซ้ำด้วย `python3 scripts/build-tenant-data.py --observations <reviewed-tenant-observations.json> --logos assets/tenant-logos-manifest.json` โดย input ที่ตรวจแล้วเก็บในงานวิจัยภายใน เผยแพร่เฉพาะ input hash และผลรวมใน `data/tenants/build-report.json` ไม่เผยแพร่รหัสไฟล์ภายใน

ตัวแทนจำหน่ายหลายแบรนด์ 8 รายการใช้ชื่อร้านจริงและไม่ใช้โลโก้ของผู้ผลิตแทนโลโก้ร้าน; สาขา mono-brand ที่มีชื่อร้าน/ผู้ดำเนินการชัดเจนคงชื่อเต็มจากต้นทางและโลโก้แบรนด์ของ boutique แยก BVLGARI boutique กับ SHH Pendulum ที่สยามพารากอนคนละยูนิตและใช้หลักฐานสาขาทางการที่ตรวจแก้แล้ว โดยไม่แก้ master ต้นทางอัตโนมัติ


### 9.2 ชุดข้อมูลที่เชื่อมเข้ามา — CityMETER Fitness (0.1.5, 30 ต.ค. 2569)

คำขอเจ้าของ 30 ต.ค. 2569 06:23 “map fitness กับ venue ตาม https://montri-th.github.io/shoppingcenter/ ใน registry” (Owner-stated) · ชีตวิจัยของ Fitness ผูกสาขากับสถานที่ในทะเบียนนี้ด้วยรหัสเท่านั้น (`common_retail_venue_ids` สถานะ `accepted_identity_and_located_in`) ไม่ใช้ชื่อหรือระยะ

- **อินพุต:** release สาธารณะของ CityMETER Fitness ที่ commit `6775063` (`data/fitness.json`, `data/brand-logos.json` — SHA-256 ใน `data/tenants/build-report.json#linkedDatasets`) ไม่ใช่ชีตภายใน · สร้างด้วย `python3 -I scripts/link-dataset-tenants.py --fitness <checkout> --commit <sha>`
- **เกณฑ์ (`linked_gate`):** ผูกแล้วกับสถานที่เดียวที่อยู่ใน `data/venues.json` · แหล่งทางการยังแสดงสาขา (`source_listed`) · ลิงก์แหล่ง https สาธารณะ · วันตรวจไม่เกินวันของรายชื่อ · release และแถวระบุได้ (commit · SHA-256 · outlet_id) · ถ้าสาขามีจุดของตัวเองต้องห่างจุดของสถานที่ไม่เกิน 300 ม. เว้นแต่เจ้าของยืนยันว่าอยู่ในสถานที่นั้น (Fitness `meta.ownerConfirmedHost` — Physique 57 Erawan ที่ Erawan Bangkok)
- **ผล (Observed fact, release `6775063`):** ผูกไว้ 147 แถว → เข้ารายชื่อ 139 สาขาใน 124 สถานที่ · ไม่เข้า 8 แถวเพราะยังเป็นประกาศเปิดหรือสถานะไม่ชัด · โลโก้แบรนด์ 27 ไฟล์ (บทบาท `brand_primary` ไบต์เดิม พื้นรองตามทะเบียนโลโก้ของ Fitness) ครบทั้ง 139 รายการ
- **ไม่เปลี่ยน:** รายการเดิมทุกรายการ (ไบต์เดิม) แถวหลักของสถานที่ จำนวนร้านแบบ primary และตัวเลขของแผนที่ การ์ด ย่าน กราฟ — ตัวเลขในแผงสถานที่ใช้รายชื่อล่าสุดตามกติกา D19 · บทบาท “ฟิตเนสและสตูดิโอ” อยู่ระหว่างเทคโนโลยีกับกล้องในลำดับเชิงบรรณาธิการ ไม่ใช่จำนวนคนเข้า
- **ลิงก์ข้ามเว็บ:** สถานที่ที่มีสาขา Fitness มี “ดูฟิตเนสที่นี่ใน CityMETER Fitness” (`https://montri-th.github.io/fitness/?venue=<venue id>`) และ Fitness 0.3.1 ลิงก์กลับด้วยรหัสทะเบียนเดียวกัน
- **ข้อจำกัด:** สาขาเป็นรายการตามหน้าทางการ ณ วันตรวจ 26 ต.ค. 2569 ไม่ใช่การตรวจภาคสนาม ไม่ยืนยันชั้น ห้อง หรือว่าเปิดวันนี้ · 19 แถวที่ Fitness พักไว้ (ทะเบียนซ้ำ ส่วนย่อยของศูนย์ ชื่อ/เลขสาขากำกวม) ไม่เข้า · หลังสร้างรายชื่อหลักใหม่จาก input ภายใน ต้องรันสคริปต์นี้อีกครั้ง (test ล้มถ้าลืม)

### 9.3 ชุดข้อมูลร้านค้าที่แหล่งทางการระบุชื่อศูนย์ — 7 ชุด (0.1.6, 4 พ.ย. 2569)

คำขอเจ้าของ 4 พ.ย. 2569 19:43 (Owner-stated): “มี dataset ใหม่เพิ่มมาหลายอัน ทบทวนความลึก/กว้าง ของข้อมูลที่ได้มาใหม่ มีหลาย dataset ที่ related to Shopping center โดยตรง เทียบกับ product statement แล้วปรับปรุงความสามารถของ web demo นี้เพื่อประโยชน์สูงสุดแก่ ICP” · การทบทวนทั้งทะเบียนอยู่ใน `PRODUCT_STATEMENT.md` §9

- **หน่วย:** หนึ่งแถวสาขาของชุดข้อมูล (`02_STORES` `outlet_id`) ที่แหล่งทางการของแบรนด์หรือของศูนย์ (store locator รายชื่อสาขา หรือไดเรกทอรีของศูนย์) ระบุชื่อศูนย์ไว้ และชีตของชุดข้อมูลนั้นจับคู่ชื่อศูนย์กับสถานที่ในทะเบียนนี้ได้แห่งเดียวด้วยชื่อตรงหรือ alias ที่ตรวจแล้ว — มาตรฐานเดียวกับ `official_chain_exact_named_host_listing` ของรายชื่อหลัก (ร้านอาหาร 644 รายการ) · บทบาทแหล่ง `dataset_source_named_host_listing` แยกจาก `dataset_accepted_host_link` ของ Fitness
- **อินพุต:** แท็บ `02_STORES` ของ research master แต่ละชุด export เป็น CSV 4 พ.ย. 2569 (และ `17_CROSS_DATASET_LINKS` ของ Apparel) เก็บในงานวิจัยภายใน เผยแพร่เฉพาะ SHA-256 วันที่ export และข้อเท็จจริงที่ได้ ใน `data/tenants/build-report.json#linkedDatasets` (`kind: named_host_listing`) · สร้างด้วย `python3 -I scripts/link-research-tenants.py --exports <dir> --exported-on 2026-11-04` หลัง `build-tenant-data.py` และ `link-dataset-tenants.py` แล้วตามด้วย `scripts/build-tenant-index.py`
- **เกณฑ์ (`named_gate` + คำศัพท์ของแต่ละชุดใน `ADAPTERS`):** ลิงก์ศูนย์ตามแหล่งทางการด้วยชื่อตรงหรือ alias เดียว · แหล่งยังแสดงสาขา (สถานะ `source_listed*`) · ขอบเขตแบรนด์ที่เจ้าของอนุมัติ (ไม่รับ `candidate`) · แหล่งทางการ (store locator / รายชื่อสาขา / ไดเรกทอรีศูนย์ — ไม่รับไดเรกทอรีรอง โซเชียล รายชื่อคู่ค้าชำระเงิน แคมเปญชั่วคราว จุดรับสินค้า และผู้ขายส่งต่อ) · เป็นร้านหรือเคาน์เตอร์ของแบรนด์เอง (ไม่รับ stockist ที่เป็นสินค้าของแบรนด์ในร้านอื่น) · สถานที่เดียวที่อยู่ใน `data/venues.json` · ลิงก์ https สาธารณะ ไม่ใช่ลิงก์แผนที่หรือเอกสารภายใน · ถ้ามีจุดของตัวเองต้องห่างจุดของสถานที่ไม่เกิน 300 ม. · ไม่มีบันทึกสถานะขัดกัน
- **หนึ่งแบรนด์ต่อหนึ่งสถานที่ (รุ่น 0.1.6–0.1.7 · แทนด้วยหน่วยสาขา D23 ในรุ่น 0.1.8 — ดู §9.5):** แถวใหม่ที่แบรนด์ (ชื่อแบรนด์ที่ทำให้เป็นมาตรฐานแบบช่องค้นหา `normalizeText`) มีอยู่แล้วในรายชื่อของสถานที่นั้น — จากรายชื่อหลัก Fitness หรือชุดก่อนหน้า — ไม่เข้า (`same_brand_already_listed_at_venue`) · ลำดับ Sport → Apparel → Furniture → Pet → Massage & Spa → Salon & Barber → Nail · แถวของชุดเดียวกันและแบรนด์เดียวกันในสถานที่เดียวกันรวมเป็นรายการเดียวพร้อม `sourceObservationIds` · แถว Apparel ที่อ้างสาขาของ Sport หรือ Luxury (`17_CROSS_DATASET_LINKS`) เป็นร้านเดียวกัน ไม่เข้า · กติกานี้ใช้กับการแสดงผลเท่านั้น ไม่ใช่การจับคู่เพื่อนับ
- **ผล (Observed fact, export 4 พ.ย. 2569):**

| ชุดข้อมูล | แถวที่มีลิงก์สถานที่ | เข้ารายชื่อ | สถานที่ | ไม่เข้าเพราะ (มากสุด) |
|---|---:|---:|---:|---|
| Sport Stores | 468 | 315 | 100 | ขอบเขตแบรนด์ยังเป็น candidate 66 · stockist/บทบาทอื่น 40 · จุดห่างเกิน 300 ม. 23 |
| Apparel Stores | 1,036 | 667 | 137 | ขอบเขตแบรนด์ยังเป็น candidate 108 · ร้านเดียวกับ Sport/Luxury 100 · สถานะไม่ใช่รายการปัจจุบัน 60 |
| Furniture, DIY & Kitchenware | 141 | 107 | 74 | แถวที่พักไว้ 17 · แหล่งเป็นรายชื่อคู่ค้า 8 · จุดห่าง 5 |
| Pet | 81 | 58 | 48 | แถวที่พักไว้ 17 · พื้นที่สัตว์เลี้ยงของศูนย์ (สิ่งอำนวยความสะดวก ไม่ใช่ร้าน) 4 |
| Massage, Spa & Onsen | 21 | 21 | 16 | — (อีก 67 แถวผูกกับโรงแรม ไม่อยู่ในทะเบียนนี้) |
| Salon & Barber | 102 | 61 | 41 | แหล่งรอง/โซเชียล 16 · แถวที่พักไว้ 15 |
| Nail | 79 | 23 | 14 | แถวที่พักไว้/ประวัติ 39 · ขอบเขตรอพิจารณา 11 |

รายชื่อร้านข้างในทั้งเว็บ: **3,713 รายการ ใน 529 สถานที่ จาก 17 ชุดข้อมูล** (เดิม 2,461 รายการ ใน 502 สถานที่ จาก 10 ชุด) · 27 สถานที่มีรายชื่อร้านเป็นครั้งแรก · รายการเดิมทุกรายการไบต์เดิม · แถวหลักของสถานที่ จำนวนร้านแบบ primary และตัวเลขของแผนที่ การ์ด ย่าน กราฟ ไม่เปลี่ยน (D19)

- **ไม่เชื่อมในรอบนี้ (ลิงก์ศูนย์ยังเป็น candidate — candidate ไม่เข้ารายชื่อตาม D19):** Beauty Stores (ที่ผูกว่าอยู่ในศูนย์แล้ว 131 แถวเป็นสาขาของ Luxury และ Pharmacy ที่อยู่ในรายชื่อแล้ว · อีก 1,790 แถว `candidate_requires_confirmation`) · Beauty Clinic (651 แถว `source_supported_candidate` ใน 122 สถานที่) · Playground & Family Entertainment (160 แถว `exact_name_candidate`) · Car Service (212 แถว `candidate_not_selected`) — บันทึกใน `build-report.json#excludedDatasets`
- **ข้อจำกัด:** เป็นรายการตามหน้าทางการ ณ วันตรวจ ไม่ใช่การตรวจภาคสนาม ไม่ยืนยันว่าเปิดวันนี้ · ชั้นหรือห้องเป็นข้อความตามแหล่ง (ตัดเบอร์โทร ที่อยู่ และหมายเหตุออก) · ยังไม่มีโลโก้ของแบรนด์กลุ่มนี้ · ลิงก์บางรายการเป็น endpoint ของ store locator ที่หน้าเว็บของแบรนด์ใช้

### 9.4 ตัวช่วยอ่านรายชื่อร้าน — ส่วนผสมร้าน เทียบศูนย์ใกล้เคียง และแบรนด์ (0.1.6)

`data/tenant-index.json` (`scripts/build-tenant-index.py`) เก็บหนึ่งแถวต่อรายการที่เผยแพร่ `[สถานที่, แบรนด์, ชุดข้อมูล, category, storeFormat]` เป็นดัชนีของพจนานุกรมเล็ก ๆ (3,713 แถว · 529 สถานที่ · 593 แบรนด์ · 110 KB) หน้าเว็บโหลดเมื่อเปิดสถานที่ ค้นหา หรือเปิดแบรนด์ และคำนวณบทบาทด้วย `tenantRole()` ตัวเดียวกับแผงสถานที่ · test เทียบดัชนีกับ shard ทุกแถว

- **ส่วนผสมร้าน (แผงสถานที่):** จำนวนร้านในรายชื่อต่อบทบาท กดเพื่อดูเฉพาะบทบาทนั้น (กดซ้ำหรือ “ทั้งหมด” เพื่อกลับ) · บทบาทของ 7 ชุดใหม่มาจากชุดข้อมูล: เสื้อผ้าและแฟชั่น · กีฬาและเอาท์ดอร์ · บ้านและเฟอร์นิเจอร์ · สัตว์เลี้ยง · นวดและสปา · ทำผมและตัดผม · ทำเล็บ — ลำดับการแสดงเป็นการประเมินเชิงบรรณาธิการ ไม่ใช่ยอดเข้าชมหรือยอดขาย
- **เทียบศูนย์ใกล้เคียง:** สถานที่กลุ่มศูนย์การค้า คอมมูนิตี้มอลล์ เอาท์เล็ต พื้นที่ค้าปลีกในโครงการ และไฮเปอร์/ซูเปอร์มาร์เก็ตที่มีร้านเช่า ที่นับเป็นอุปทาน มีพิกัด และมีร้านในรายชื่ออย่างน้อย 3 ร้าน ในรัศมี 5 กม. (เส้นตรงระหว่างจุดอ้างอิง ไม่ใช่ catchment) ใกล้สุดไม่เกิน 5 แห่ง ไม่นับโครงการแม่และพื้นที่ย่อยของตัวเอง · บอก (1) บทบาทที่ศูนย์ใกล้เคียงมีแต่รายชื่อของที่นี่ยังไม่มี (2) แบรนด์ที่อยู่ในศูนย์ใกล้เคียงตั้งแต่ 2 แห่ง (หรือ 1 เมื่อมีศูนย์ใกล้เคียงแห่งเดียว) แต่ยังไม่อยู่ในรายชื่อของที่นี่ (3) แบรนด์ที่มีที่นี่และยังไม่อยู่ในรายชื่อของศูนย์ใกล้เคียง · ทุกข้อเป็นการเทียบรายชื่อ ไม่ใช่ข้อสรุปว่าร้านไม่มีอยู่จริงหรือเป็นช่องว่างตลาด · ณ export นี้: สถานที่ที่เทียบได้และมีรายชื่อ 484 แห่ง มีศูนย์ใกล้เคียงอย่างน้อย 1 แห่ง 282 แห่ง
- **แบรนด์ (`?brand=<key>`):** ค้นชื่อแบรนด์ในช่องค้นหา (ส่วน “แบรนด์ในรายชื่อร้าน”) แล้วเปิดดูว่าแบรนด์อยู่ในรายชื่อของสถานที่ใด · นับสถานที่โดยโครงการแม่กับพื้นที่ย่อยเป็นที่เดียว · จังหวัดนับจากจุดในขอบเขตแบบเดียวกับสีจังหวัด และแผนที่ระดับประเทศใช้สีและป้ายจังหวัดเป็นจำนวนสถานที่ที่มีแบรนด์นั้น (สเกล `count` 41 ค่าเดิม) · “มักอยู่ในที่เดียวกับ” = แบรนด์ที่อยู่ในรายชื่อของสถานที่เดียวกันตั้งแต่ 2 แห่ง เรียงตามจำนวนสถานที่ร่วม
- **คีย์แบรนด์:** `normalizeText()` ของชื่อแบรนด์ที่แสดง (NFKC ตัวพิมพ์เล็ก ไม่มีช่องว่างและเครื่องหมายบางตัว) ใช้ค้นหาและแสดงผลเท่านั้น ไม่ใช่การเชื่อมเพื่อนับ · ชื่อแบรนด์ที่สะกดต่างกันในต่างชุดอาจแยกเป็นสองคีย์
- **รุ่น 0.1.6–0.1.7:** ตัวเลข “ร้านข้างใน” ของภาพรวม ย่าน รายการสถานที่ และตารางยังเป็นจำนวนแบบ primary เดิม (D19) · รุ่น 0.1.8 ใช้รายชื่อชุดเดียวกันทุกจุด (D22 — §9.5)

### 9.5 สาขา ลิงก์ศูนย์ที่ตรวจแล้ว ตัวเลขร้านข้างใน และ “ข้างในมี” — D22–D23 (0.1.8, 5 พ.ย. 2569)

คำสั่งเจ้าของ 4 พ.ย. 2569 (Owner-stated): 21:23 “ทำเลย ตามที่พี่แนะนำ” (D22 · ตรวจลิงก์ศูนย์ · ซิงก์ทะเบียน · สัตว์เลี้ยงและโลโก้) และ “ช่วย research ให้ดี ผูกกับศูนย์การค้าให้ถูกต้อง อย่าเดา” · 21:24 “มีบางร้าน อาจจะมีหลายสาขาในศูนย์การค้าเดียว เช่น เมกาบางนา มี Starbucks 3 สาขา” (D23)

- **หน่วย = สาขา (D23):** หนึ่งรายการคือหนึ่งร้านหรือเคาน์เตอร์ที่แหล่งทางการลงเป็นรายการของตัวเอง · แบรนด์เดียวกันที่แหล่งเดียวกันลงหลายรายการในศูนย์เดียว (ร้านกับเคาน์เตอร์ · Men กับ Women · คนละชั้น) เป็นหลายสาขา · รายการเดียวกันซ้ำ หรือสาขาชั้นเดียวกันจากแหล่งอีกแห่ง (เช่น ไดเรกทอรีของศูนย์) เป็นสาขาเดียว เก็บทุก `outlet_id` ใน `sourceObservationIds` · ข้ามชุดข้อมูล: แถวของชุดหลังที่ชั้นตรงกับสาขาของแบรนด์นั้นที่มีอยู่แล้ว หรือไม่มีชั้นให้แยก ถือเป็นสาขาเดิม (`same_branch_already_listed_at_venue`) · ตัวอย่าง Observed fact: Watsons ยูเนี่ยนมอลล์ 3 สาขา (BF · GF · 2F) · adidas เซ็นทรัล ภูเก็ต 3 สาขา (Originals · Store · Shop-in-Shop)
- **ลิงก์ศูนย์ที่ตรวจแล้ว (Beauty, Beauty Clinic, Playground, Car Service):** sheet ของชุดเหล่านี้บันทึกศูนย์ไว้เป็นผู้สมัครเท่านั้น `scripts/review-candidate-hosts.py` รับแถวเมื่อผ่านครบ: (1) sheet ของชุดเองนับแถวนี้ (ขอบเขต สถานะ บทบาท) (2) แหล่งเป็นเว็บของแบรนด์หรือของศูนย์ ไม่ใช่ไดเรกทอรี โซเชียล แผนที่ หรือเว็บรวม (Beauty ใช้ `source_type` ของ sheet) (3) ชื่อสาขาที่แหล่งเผยแพร่มีชื่อของศูนย์ผู้สมัคร — ชื่อในทะเบียน ชื่อที่ R04 ยืนยันตัวตนแล้ว หรือชื่อที่ sheet ของชุดอื่นจับคู่ไว้ — และไม่มีชื่อศูนย์อื่นที่ไม่ใช่โครงการแม่ พื้นที่ย่อย หรือพื้นที่ย่อยร่วมโครงการ · คำเครือข่ายลำพัง (Central, Lotus's, Big C …) ไม่นับเป็นชื่อศูนย์ · ชื่อที่วางหลังคำว่า ก่อนถึง ใกล้ ตรงข้าม หน้า หลัง นอก (หรือ near, opposite, next to …) เป็นจุดสังเกต ไม่ใช่ที่ตั้ง (4) จังหวัดตรง (5) พิกัดของแถว (ถ้ามี) ห่างจุดศูนย์ไม่เกิน 300 ม. หรืออยู่ในอาคารของศูนย์ (+50 ม.) · การเทียบชื่อไม่ fuzzy: ปรับรูปแบบตายตัวอย่างเดียว (ตัวพิมพ์ ช่องว่าง เครื่องหมาย ตัวการันต์ เช่น เวสต์เกต · เวสท์เกต · เวสเกต และชื่อที่ผู้บริหารเปลี่ยนเองตามเอกสาร: CentralPlaza และ CentralFestival เป็น Central · The Mall เป็น The Mall Life Store) และชื่อทางการ 1 ชื่อจากแหล่งสาธารณะ (ฟิวเจอร์พาร์ค รังสิต → ฟิวเจอร์พาร์ค และ สเปลล์) · ชื่อที่สะกดผิด ย่อ หรือเป็นภาษาอื่นยังเป็นผู้สมัคร
- **ผลการตรวจ (Observed fact, export 4 พ.ย. 2569):**

| ชุดข้อมูล | แถวผู้สมัคร | ผ่าน | ขึ้นเว็บ (สาขา) | สถานที่ | ยังเป็นผู้สมัครเพราะ (มากสุด) |
|---|---:|---:|---:|---:|---|
| Beauty Stores | 1,790 | 1,083 | 1,075 | 357 | sheet ยังไม่นับแถว 553 · จุดห่าง 71 · ชื่อสาขาไม่มีชื่อศูนย์ 53 · ชื่อสาขาระบุศูนย์อื่น 12 |
| Beauty Clinic | 627 | 436 | 436 | 100 | sheet ยังไม่นับแถว 74 · ชื่อสาขาไม่มีชื่อศูนย์ 54 · แหล่งไม่ใช่ของแบรนด์หรือศูนย์ 45 |
| Playground & Family Entertainment | 160 | 103 | 103 | 68 | sheet ยังไม่นับแถว 39 · สถานะไม่ใช่รายการปัจจุบัน 8 · แหล่งไม่ใช่ของแบรนด์หรือศูนย์ 6 |
| Car Service | 212 | 147 | 147 | 135 | ผู้สมัครไม่อยู่ในรายชื่อที่นับ 33 · จุดห่าง 12 · สถานะไม่ใช่รายการปัจจุบัน 7 · ชื่อบอกว่าอยู่ก่อนถึงศูนย์ 4 |

  ผ่าน 1,769 จาก 2,789 แถว · อีก 1,020 แถวพร้อมเหตุผลรายแถวอยู่ใน Google Sheet ทบทวนของทีมวิจัย (ภายใน) · ใบเสร็จต่อชุด `build-report.json#linkedDatasets` (`kind: reviewed_candidate_host`, `candidateRows`, `reviewAccepted`) · รายการที่ผ่านมี `hostIdentityStatus: candidate_confirmed_by_citymeter_review`, `sourceGate: official_label_unique_registry_name` และ `identityNote` (แหล่ง · ชื่อที่ตรง · ระยะ)
- **รายชื่อร้านข้างในทั้งเว็บ:** **5,493 สาขา ใน 619 สถานที่ จาก 21 ชุดข้อมูล** (รุ่น 0.1.7: 3,713 ใน 529 จาก 17 ชุด) · รายการเดิมทุกรายการไบต์เดิม · Sport +4 Apparel +14 Salon & Barber +1 จากหน่วยสาขา
- **ตัวเลข “ร้านข้างใน” (D22):** ภาพรวม ย่าน รายการสถานที่ ตาราง การ์ด และแผงสถานที่ใช้รายชื่อชุดเดียวกัน (จำนวนรายการต่อสถานที่ใน `data/tenant-index.json`) · สถานที่ที่ยังไม่มีรายชื่อแสดง “—” และการเลือกที่ไม่มีรายชื่อเลยแสดง “—” ไม่ใช่ 0 · ผลรวมของพื้นที่นับรายการของสถานที่ที่นับได้ในพื้นที่นั้น (สาขาในพื้นที่ย่อยที่ไม่นับแยกอยู่กับรายการของพื้นที่ย่อยนั้น) · บรรทัดที่มาบอกจำนวนชุดข้อมูลและช่วงวันตรวจของรายชื่อ · หน้าเว็บโหลดดัชนีรายชื่อ (40 KB gzip) ทันทีหลังข้อมูลหลัก ระหว่างนั้นตัวเลขร้านเป็น “—”
- **ตัวกรอง “ข้างในมี” (`?role=`):** เหลือเฉพาะสถานที่ที่รายชื่อร้านมีบทบาทนั้น (บทบาทจาก `tenantRole()` ตัวเดียวกับส่วนผสมร้าน · บทบาทใหม่: ความงาม คลินิกความงาม เครื่องเล่นและครอบครัว บริการรถยนต์) แล้วแผนที่ ข้อค้นพบแรก สี ตัวเลข กราฟ และตารางคำนวณใหม่จากสถานที่ที่เหลือ · สถานที่ที่ยังไม่มีรายชื่อไม่เข้า (ไม่รู้ ไม่ใช่ไม่มี) · ตัวเลือกบอกจำนวนสถานที่ที่นับได้ต่อบทบาท
- **พื้นที่สำหรับสัตว์เลี้ยง (`?role=pet-area`, `data/venue-amenities.json`):** แถวของ Pet ที่ sheet ระบุว่าเป็นพื้นที่สัตว์เลี้ยงของศูนย์เอง (`store_format` `shopping_centre_pet_amenity` / `host_dog_park`) ผูกกับสถานที่เดียว (`source_explicit_named_host`) และมีแหล่งสาธารณะ — ไม่เข้ารายชื่อร้าน เป็นบรรทัด “สัตว์เลี้ยง” ของแผงสถานที่พร้อมแหล่งและวันที่ในหลักฐานรายช่อง · 5 แห่ง: เซ็นทรัล อีสต์วิลล์ · เซ็นทรัล เวสต์วิลล์ · เมกาบางนา · ฟิวเจอร์พาร์ค และ สเปลล์ (หน้าเว็บของศูนย์) · ปาร์ค บางนา (เจ้าของข้อมูลแจ้ง หน้าโซเชียลของศูนย์) · หมายถึงศูนย์มีพื้นที่สำหรับสัตว์เลี้ยงตามแหล่ง ไม่ใช่นโยบายว่าพาสัตว์เข้าได้ทั้งศูนย์ ไม่ใช่การตรวจหน้างาน
- **โลโก้แบรนด์ของชุดใหม่:** 01_BRANDS ของ 11 ชุดมีไฟล์โลโก้พร้อม SHA-256 เพียง Apparel 13 แบรนด์ ที่เหลือบันทึก `not_collected` หรือว่าง — ยังไม่มีโลโก้ในเว็บ

### 9.6 Official tenant directories, cross-industry identity and retail reference points (0.1.20, 7 November 2026)

The private evidence ledger retains 23,217 publisher observations from seven collections covering 55 canonical hosts: True Digital Park, five The Mall branches, ICONSIAM, 44 CPN codes, Mega Bangna, Future Park/Zpell and One Bangkok. Publisher observations are not branch totals: 7,749 CPN product/department/counter presences and 1,347 parent/component-held rows retain their original grain. Raw routing nodes are not selected shopfront points. A directory omission is not a closure.

Existing industry masters are searched before intake. Reuse a confirmed source brand/outlet identity; retain the actual evidence tab and source row when the source has no canonical outlet. Unmatched consumer banners and venue-scoped provisional names go to the new Miscellaneous master, using the Luxury template's brand/store structure plus provenance, company-role, coverage and future-migration fields. Shared existing brand IDs are reused. A later dataset split preserves the original IDs through a migration crosswalk; membership in Miscellaneous does not approve an industry POS, legal operator, current operation or national coverage.

The reviewed public interchange has 1,500 observations. Its branch/card identity gates add 1,208 displayed items with 1,223 underlying source observations; corroboration groups on 201 old items and 14 new items add evidence without adding branches. All 5,493 original item facts remain unchanged. Final roster: 6,701 items, 638 hosts, 25 datasets and 946 brand/concept keys; True Digital Park 122 items from 17 datasets. Format, floor/unit and exact canonical/publisher-card checks prevent duplicate source references from becoming extra shops. The adapter holds 13 point conflicts, three multiple-existing-identity conflicts and four unresolved unit conflicts. Earlier static, candidate-only, provisional and parent/component holds stay outside the roster. A department counter, brand presence and a physically separate outlet are not interchangeable units.

An own selected point must be within 300 m of the host, or inside its exact retained footprint. A host-context point is not substituted for the branch point; 57 such source points remain NULL as own points. Each record states whether its integrity hash describes HTTP bytes, rendered DOM, normalized publisher fields or a native source row. Public files exclude private workbook/Drive URLs, local artifact paths and raw collector responses.

The original 31 added venues were audited individually: 23 source-qualified retail/tenant/foodcourt/building references selected and eight unresolved points left NULL. These are not asserted entrances, retail centroids, footprints, measured accuracies or field-verified operation. Rejected station, campus, viewport and conflicting locator points remain in private review/evidence records. All 31 venues have a verified source-branch backlink; exact and candidate source links remain distinguishable. Only the original 31 details and 23 core rows changed, with every venue's existing qualification/count role and the original primary graph preserved. Located countable supply becomes 6,084, while qualified/countable/supply totals remain 6,265/6,151/6,145. The 79 approved display boundary files, sites, models and stations remain byte-identical to the preceding release. The current site snapshot is 392 sites / 5,743 building reference points, including Promenade parking E once and no Seacon Srinakarin site.

Parent/portfolio/peer discovery remains an evidence-linked research layer. Restaurant network rows separate sourced company roles and portfolio links from peer leads, source branch observations and coverage checkpoints; they do not automatically create outlets or legal ownership. Nationwide brand-locator follow-ups and the remaining official venue directories are an ongoing coverage queue, not a completed census. Rebuild with `scripts/link-venue-network-tenants.py` followed by `scripts/build-tenant-index.py`; input hashes and held reasons are in `data/tenants/build-report.json#venueNetwork`.

### 9.7 Continued directory/branch reconciliation (0.1.21, 7 November 2026)

A further 12 canonical host directories contribute 3,686 raw observations: 3,524 consumer-source observations, including 680 held counter/component/duplicate views, plus 162 held visibility/location contexts. The 842 total source holds are not eligible-retailer counts. The native ledger now has 26,903 observations at 67 host IDs (65 complex groups after the three One Bangkok parts are rolled up). The earlier 55-host summary uses approximately 15,358 strict consumer-entry groups after removing 7,749 CPN department/product/counter presences and 110 exact label/floor/nonblank-unit repeats; these are directory groups, not independently confirmed legal tenants or physical storefronts. Department/card views, shared food-hall names, event spaces, amenities and coming-soon labels keep their separate roles.

The public interchange now contains 1,847 observations. Round two admits 347 source records, adds 271 items (260 food and 11 Miscellaneous), and adds 71 corroboration groups to existing items. It preserves all 6,701 preceding item facts. Final roster: 6,972 items / 638 hosts / 25 datasets / 962 brand-concept keys. The 95 food identity/host disagreements, 31 explicit source-role/planned holds, five Emporium manufacturer/counter contexts and six service scope/unit holds are excluded from this intake. A corroborating source and an additional source-qualified branch identifier do not add another physical outlet.

CHAGEE Chamchuri Square and Samyan Mitrtown use distinct canonical outlet and exact venue IDs. Samyan's current-open state is an explicit owner assertion dated 7 November 2026. Its named Google feature and marker identify the source branch; they do not supply an official brand UUID, floor, unit or surveyed entrance. These fields remain unknown. The official locator's omission is not closure evidence. Publisher HTTP/collector/native-row integrity hashes and the owner assertion are separately scoped.

The native source-discovery queue has all 11,139 registry IDs, including nonqualified/context rows without upgrading their status. Its 594 completed URL preflights establish availability and potential directory links only. National Huawei, True, 425 Degree and AIS consumer-locator intake is retained as candidates or source-only holds; format, source date, partner/publisher versus operator role and same-unit identity must be reconciled before public projection. A staging/test directory is not an authoritative consumer network. No source/public point, approval, POS or primary-relationship upgrade follows from this discovery queue.

Native reconciliation appends 348 canonical-source branch/host pairs after a complete existing-key scan, preserving historical source namespaces and evidence. Source-qualified references can point to the same deduplicated public branch; their row count is not the public shop count. All venue qualification/count roles, primary relationships, core files, 79 approved display boundary files, stations, sites and models remain unchanged. Current site snapshot: 392 / 5,743 building reference points, parking E once at Promenade and no Seacon Srinakarin site.

### 9.8 Exact identity, source units and nationwide consumer locators (0.1.24, 7 November 2026)

Round three adds 173 dated source/capture records: 48 reconciled food references, 10 fresh LUSH branch capture receipts, 24 views of 12 existing 425 Degree canonical branch candidates, and 91 named nationwide telecom/electronics consumer locations. These yield 136 new public items and 25 corroboration groups on preceding items. Roster: 7,108 items / 640 hosts / 25 datasets / 968 display/search brand-concept keys. All 6,972 preceding item facts remain intact; a source view or receipt is not another storefront. Fresh LUSH check dates and hashes name new HTTP capture receipts; the original native branch observations and their earlier dates are retained.

The 48 food resolutions use selected authoritative host-UUID crosswalks or explicit ordinal/Thai-direction floor aliases. Raw unit/floor strings, existing canonical outlet IDs, native selected point roles and current-operation qualifications are not replaced. Forty-seven of the preceding 95 food holds remain unresolved. LUSH's Thai publisher lists 10 detail pages, all captured HTTP200: nine explicit units and one floor-only Westville address. The Parade is the accepted One Bangkok child host; Floresta stays a named zone of Central Phuket, not an extra outlet.

The nationwide intake independently checks consumer format, existing recognized banner, exact branch/host identity and source geography. Seven of 98 accepted host references are not admitted publicly: one Huawei Asok unit conflict, one unresolved True Sphere embedded-service format and five raw branch-marker disagreements of 311.5–879.2 m without an established contained retail footprint. Their native host FKs and unselected raw coordinates remain available; NULL selected shop coordinates do not bypass the disagreement. Runtime projection checks a retained branch-bound raw marker against the actual current host point/footprint. Publisher context or viewport points require separate source-role evidence; no 1,500 m fallback is used.

Official consumer HTML must bind the exact regional endpoint or pinned publisher JSON before it is treated as consumer evidence. AIS staging/test aggregate contexts and partner/employer/product lists remain excluded; an endpoint's hostname alone is not authority. HTTP-body, publisher-image, reader, normalized-row and native-integrity hashes retain distinct scopes. The True source snapshot period is separate from current trading. Mobile/electronics display categories are editorial role mappings, not an industry-scope or POS approval.

No new canonical food/Beauty outlet, selected shop point, physical-unit merge, legal operator, source closure inference or primary venue graph is introduced. Company/portfolio/peer leads remain role-specific research evidence. D33–D36 and the preceding 341 core/detail/boundary/site/model/station files are preserved. The site snapshot remains 392 sites and 5,743 reference points; Seacon Srinakarin has no research site. Remaining directories, national branches, scope/unit/point conflicts and the source-sync backlog are explicit research queues, not a completed national census.

### 9.9 ทางไปต่อใน Google: AI Mode · Google Maps · Street View หันหน้าเข้าอาคาร (0.1.25, 7 พ.ย. 2569 · D37)

เจ้าของ 7 พ.ย. 2569 22:13 น.: “ควรจะมี Google AI Mode, Google Maps และ Streetview แบบเปิดแล้วหันหน้าเข้าตึกพอดี” · เหตุผลตามผู้ใช้กลุ่มหลักอยู่ใน `PRODUCT_STATEMENT.md` §12 · โค้ด `js/look-around.js` (pure ยกเว้นตัวอ่าน tile) · ทดสอบ `tests/look-around.test.js`

**ลิงก์ (สร้างจากชื่อสาธารณะและเรขาคณิตของเราเท่านั้น ไม่มีข้อมูลผู้ใช้ ไม่มีรหัสภายใน ไม่เก็บอะไรจาก Google):**

| ปุ่ม | URL | เนื้อหา |
|---|---|---|
| ถาม AI Mode | `https://www.google.com/search?udm=50&q=…` | “<ชื่อ> (<ประเภท> <เขต/อำเภอ> <จังหวัด> บริหารโดย <ผู้บริหาร>) …” ตามด้วยคำถามตามประเภทและสถานะ: ทั่วไป “ติดต่อเช่าพื้นที่ได้ทางไหน มีร้านหลักอะไรบ้าง ลูกค้าส่วนใหญ่เป็นใคร เดินทางอย่างไร และมีข่าวล่าสุดอะไร” · ตลาด “ติดต่อเช่าแผง … เปิดวันและเวลาใด ขายอะไรเป็นหลัก …” · สถานีบริการ/ไฮเปอร์มาร์เก็ต “มีร้าน(เช่า)อะไรบ้าง ติดต่อเช่าพื้นที่ …” · กำลังจะเปิด “กำหนดเปิด ความคืบหน้า และติดต่อจองพื้นที่เช่า” · ปิดแล้ว “ปิดเมื่อไร และตอนนี้พื้นที่นี้เป็นอะไร” (`venueQuestion`) |
| เปิด Google Maps | `https://www.google.com/maps/search/?api=1&query=<ชื่อ> <เขต/อำเภอ> <จังหวัด>` | สถานที่ที่ไม่มีจุดใช้จังหวัดตามที่อยู่ |
| ดู Street View | `https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=<lat>,<lon>&heading=…&pitch=…&fov=…` | เฉพาะสถานที่ที่มีจุด · ก่อนคำนวณเสร็จหรือเมื่อคำนวณไม่ได้: `viewpoint` = จุดของสถานที่ ไม่ส่งมุม (Google เลือก) |

**จุดยืนและมุมของ Street View (`streetViewView`):**

1. **อาคารที่จะมอง** (`lookTarget`, จากสิ่งที่ `js/buildings.js` วาดให้สถานที่นั้น): มวลอาคารจากไฟล์แบบ (D29) → รูปทรงอาคารที่ตรวจแล้ว → อาคารที่หมุดตั้งอยู่ (`site_point` 0) → ส่วนที่ใหญ่ที่สุดที่วาด · ไม่มีอาคาร = มองที่จุดของสถานที่
2. **ถนน** (`roadsOfLayer`): ชั้น `transportation` ของ tile z14 ชุดเดียวกับที่แผนที่วาด (OpenFreeMap) ภายใน 260 ม. ของอาคาร · ใช้ `trunk`, `primary`, `secondary`, `tertiary`, `busway`, `minor`, `service` · ไม่ใช้ `motorway` (ทางด่วนยกระดับ), สะพาน, ทางลอด, ทางลาด, ทางในอาคาร, `access=no`, และ service แบบลานจอดรถ ทางเข้าบ้าน drive-through
3. **จุดยืนของแต่ละถนน:** จุดบนถนนที่ใกล้ศูนย์กลางอาคารที่สุด (ทุกช่วงของเส้น) ถ้าจุดนั้นอยู่ใต้อาคารไม่นับ · ระยะถึงผนังที่ใกล้ที่สุด (gap) ต้องไม่เกิน 250 ม. (ศูนย์ชานเมืองและร้านขนาดใหญ่ตั้งหลังลานจอดรถลึก 100–200 ม.)
4. **คะแนน (น้อยชนะ):** (gap + 40 ม.) × น้ำหนักชั้นถนน (`trunk`/`primary` 1 · `secondary` 1.2 · `tertiary` 1.5 · `busway` 2 · `minor` 3 · `service` 6) × 3 เมื่อเส้นสายตาถึงผนังผ่านอาคารอื่น (อาคารจาก tile เดียวกัน ยกเว้นอาคารที่ซ้อนกับอาคารของสถานที่) × 2 เมื่อจุดยืนอยู่ห่างโครงสร้างยกระดับไม่เกิน 15 ม. (สะพานของ `transit`/`rail` คือรางรถไฟฟ้า, `path` คือสกายวอล์กและสะพานลอย, `motorway` คือทางด่วน)
5. **มุม:** หันไปที่ผนังที่ใกล้ที่สุด (ถนนที่ไปสุดข้างอาคารจึงมองเห็นอาคารแบบมุมเฉียง ไม่ใช่มองไปตามถนน) · `fov` กว้างพอให้เห็นทุกมุมของอาคาร (40–100°) · `pitch` มองขึ้นหนึ่งในสี่ของความสูง (สูงสุด 30 ม.) ไม่เกิน 10° และไม่เกิน 3° ใต้โครงสร้างยกระดับ · Google เปิดภาพพาโนรามาที่ใกล้จุดยืนที่สุด

**ปรับค่าบน tile จริง (7 พ.ย. 2569, ในเบราว์เซอร์บนหน้าเว็บนี้):** รอบแรกให้น้ำหนัก service ต่ำเกินไป สามย่านมิตรทาวน์จึงได้ถนนส่งผู้โดยสารที่ชิดอาคาร (gap 0 ม.) แทนถนนพญาไท · เซ็นทรัลเวิลด์ได้จุดใต้รางและสกายวอล์กถนนพระรามที่ 1 ที่ภาพเห็นแต่โครงสร้าง แล้วเมื่อเลี่ยงได้ถนนราชดำริแต่ยังหันไปตามถนน (หาศูนย์กลางอาคาร) จึงเปลี่ยนเป็นหันไปที่ผนังที่ใกล้ที่สุด ผลรอบสุดท้ายอยู่ใน `handoff/VERIFICATION.md`

**ข้อจำกัด:** ภาพ คำตอบ รูป และรีวิวเป็นของ Google ไม่ใช่หลักฐานของ CityMETER และไม่เข้าตัวเลขใด · Google ถาม “Continue with this search?” หนึ่งครั้งเมื่อเปิด AI Mode จากเว็บอื่น · วันที่ภาพ Street View ต่างกันตามจุด · อาคารบังที่ OpenStreetMap ยังไม่มี กำแพง ต้นไม้ และป้าย คำนวณไม่ได้ · ชั้นถนนและโครงสร้างยกระดับตามข้อมูล OpenStreetMap ใน tile (planet build ของ OpenFreeMap)

### 9.10 Recovery from owner leads and nationwide source-to-public accounting (0.1.26, 7 November 2026)

The owner supplied 283 leads: Park Silom27, Central Park56 and One Bangkok200. These are search-result leads, not first-party opening-status evidence. Park Silom's earlier availability check had reached a home page without discovering the retail directory. The current official retail page has52 distinct first-render logo slots across B1/G/L/2F/3F; all original images were inspected, responsive duplicates excluded, whole HTML and separate image hashes retained. Upper offices and nearby premises are not automatically retail tenants. An image URL never inherits the parent HTML's byte hash.

Native reconciliation retains113 existing food branch identities and creates one source-listed Karun Park Silom canonical research branch (L floor; no unit, point or operator inferred). Eleven existing nonfood branches receive exact host evidence, and one DHL candidate reuses the existing Miscellaneous banner. Kaia and sara sara enter their existing industry masters with scope review unchanged and are excluded from public admission. Seventy-one owner-lead issues remain in the native review queue, including literal unit/address conflicts and non-retailer contexts; four food intake issues retain their existing source queue.

Round4 admits126 source memberships:110 new public listings and16 exact-ID corroborations. All preceding7,108 item identities/facts remain. Six prior Parade items are presented at SC-C0015, the already counted One Bangkok retail venue; `registeredChildVenueId` retains the exact native component. New source records also retain literal component/floor/unit. This is a publication view, not an outlet merge, a new site or a change to the native host FK. Roster7,218 items/639 hosts/25 datasets/1,010 display-search brand/concept keys. Park23, CentralPark64, OneBangkok97. The retained raw branch marker must pass the actual publication-host point/footprint gate even when selected coordinates are NULL. Round4 merging uses only canonical/source ID crosswalks; same brand and floor do not merge storefronts or resolve a missing identity bridge.

The national audit reads the complete current native coverage inventory11,139 rows, official directory26,955 observations and native source-link211,203 rows. Directory evidence covers68 native hosts/66 publication groups. It records15,675 unreconciled and9,006 held publisher observations at their own grain. Native accepted host memberships3,381, candidate-only host references6,468 and1,129 accepted links needing publication-gate review remain separate from public listings. Native rows without a host reference are not evidence that a host exists. Scope, operation, unit, source authority and venue definition still require their own gates.

Run the audit after tenant projection with a dated, complete private native snapshot and actual admission outcomes. New required source identities comprise126 admitted memberships plus2 explicitly non-admitted scope-review intakes; release accounting has zero blockers. Prior20 adapter holds remain separately documented. Tests bind the exact numbered shard bytes, venue core and reviewed source receipt, then check every admitted source identity/hash/scope/date once in public evidence, including corroborations. Only aggregate audit metrics are public; per-venue queues and native identities stay private. The audit does not imply fresh source collection for every venue or complete national physical-tenant coverage. D33–D36,392 sites,5,743 building-reference points and original counting/source dates are preserved.

**Venue-core refresh without a new audit (0.1.27, 8 November 2026):** an export of the Research Master that only places points — the 29 counted venues the owner identified on 7 November (28 at a building, Siam Square at the area; `owner_identified_*_point_not_field_verified`) — changes no inventory row, identity, qualification, count role, name, group, status or tenant evidence. `python3 -I scripts/refresh-coverage-receipt.py --previous <the core the receipt names>` proves that (the same venue ids; only `lat`, `lon`, `located`, `provinceCode`, `districtCode` changed; the 32 roster shards still hash to `publicRosterSha256`) and then names the new core in `data/tenant-coverage-audit.json#venueCoreRefresh`, keeping the core the audit read (`auditedCoreSha256`). Anything else stops the script: rerun the private audit.

### 9.11 รายชื่อร้านตามไดเรกทอรีของศูนย์ (0.1.27, 8 พ.ย. 2569 · D38)

**คำสั่งเจ้าของ (Owner-stated, 7 พ.ย. 2569 23:49 น.):** “รับข้อ 1 ไหมครับ รับครับ” — ข้อ 1 คือ “ร้านที่ไดเรกทอรีทางการของศูนย์ลงไว้ ขึ้นเว็บได้ทันที แสดงชื่อตามที่ศูนย์ลง ชั้นและยูนิต หมวด วันที่ตรวจ และลิงก์แหล่ง แม้ยังไม่ผูกแบรนด์ · ไม่รวมเคาน์เตอร์ในห้างสรรพสินค้า กิจกรรมหรือพื้นที่ส่วนกลาง จุดบริการ ร้านที่ “เร็ว ๆ นี้” และรายการซ้ำชื่อ+ชั้น+ยูนิต · รายการที่ตรงกับร้านบนเว็บอยู่แล้ว (ชื่อแบรนด์และชั้นเดียวกัน) เพิ่มเป็นหลักฐาน ไม่เพิ่มร้าน · ร้านที่ผูกแบรนด์แล้วได้โลโก้ การค้นตามแบรนด์ และการนับสาขาข้ามศูนย์”

**ข้อมูลเข้า:** แท็บ `18_OFFICIAL_TENANTS` ของ Research Master export เป็น CSV (7 พ.ย. 2569 ราว 23:55 น. · 26,955 แถว · 68 รหัสสถานที่ · 51,070,466 ไบต์ · SHA-256 `c9f3d4f5…3ced32`) เก็บนอก repository · เผยแพร่เฉพาะ hash ขนาด จำนวนแถว และวันที่ (`data/directory/build-report.json#input`)

**วิธี (`python3 -I scripts/build-directory-listings.py --directory <csv> --exported-on <date> [--receipt <csv นอก repository>]`):**
1. **ไม่แสดง** ตามลำดับ: เคาน์เตอร์แบรนด์ในห้างสรรพสินค้า (`outlet_match_status = product_counter_identity_not_independent_outlet`) · แถวที่ชีตพักไว้ (`public_projection_status = held_*` — เคาน์เตอร์หรือรูปแบบร้านที่ยังไม่ตัดสิน หน้าไดเรกทอรีที่ซ้ำ กิจกรรม พื้นที่ส่วนกลาง สิ่งอำนวยความสะดวก รูปแบบร่วมหรือห้าง ผู้ประกอบการไม่มีชื่อ การมองเห็นของผู้บริโภค) · `count_role = held_source_observation_not_additive_outlet` · ร้านที่ “เร็ว ๆ นี้” · จุดบริการของศูนย์ (`brand_match_status = not_a_brand_service_or_facility` หรือชื่อที่ขึ้นต้นด้วย ATM ห้องน้ำ ที่จอดรถ ประชาสัมพันธ์ ลิฟต์ ห้องละหมาด ห้องให้นม ล็อกเกอร์ ฯลฯ — “Foot Locker” ยังเป็นร้าน) · แถวไม่มีชื่อ · แถวไม่มีลิงก์ https สาธารณะ (ไม่รับ Drive/Docs/Sheets และ URL ที่มีรูปแบบรหัสผ่านหรือ token)
2. **ข้อยกเว้นเดียวของการพัก:** แถวที่ชีตพักไว้เพียงเพราะยังไม่แยกส่วนย่อยของโครงการ (`held_counter_or_component` + `relationship_status = parent_component_scope_held`) แสดงที่สถานที่นั้นเมื่อทะเบียนนับทั้งโครงการเป็นสถานที่เดียวและไม่มีส่วนย่อยที่ลงทะเบียน (เซ็นทรัล ภูเก็ต: Festival กับ Floresta 383 แถว)
3. **สถานที่:** สถานที่ที่นับได้ หรือส่วนย่อยของสถานที่ที่นับได้ — แสดงที่สถานที่แม่ พร้อม `registeredChildVenueId` และ “ใน <ชื่อส่วนย่อย>” (พาเหรด และ เดอะ สตอรี่ส์ ที่ วัน แบงค็อก) · แถวของสถานที่ที่ไม่อยู่ในชุดที่นับได้และไม่มีแม่ที่นับได้ไม่แสดง
4. **หน่วย:** หนึ่งรายการ = หนึ่งชื่อบนหนึ่งชั้นและยูนิตของสถานที่ (ชื่อเทียบแบบ NFKC ตัวพิมพ์เล็ก ไม่นับเว้นวรรคและเครื่องหมาย โดยคงสระและวรรณยุกต์ไทย · ชั้นอ่านเป็นรหัส: “G Floor” = “GF” = “G”, “3rd Floor” = “3F” = “L3”) · ห้างสรรพสินค้าหลายชั้นเป็นหนึ่งรายการ (“ชั้น G, L1, L2”)
5. **ไม่แสดงซ้ำกับรายชื่อแบรนด์:** รายการที่รายชื่อแบรนด์แสดงอยู่แล้วที่สถานที่เดียวกัน — ตรงรหัส observation หรือรหัสสาขาที่ชีตผูกไว้ก่อน แล้วจึงชื่อเดียวกัน (ตรงทั้งชื่อ หรือเมื่อตัดคำทั่วไปอย่าง The · Shop · Restaurant · Coffee) หรือแบรนด์ที่ชีตผูกหรือเสนอไว้ของแถวนั้น บนชั้นเดียวกัน (หรือรายชื่อแบรนด์ไม่ระบุชั้น) · หนึ่งรายการของรายชื่อแบรนด์จับได้หนึ่งรายการของไดเรกทอรี · แบรนด์ที่มีหลายชั้นมากกว่าที่รายชื่อแบรนด์ลงไว้ได้ชั้นที่เหลือเป็นรายการเพิ่ม (D23) · เป็นกฎการแสดงผล ไม่ใช่การรวมตัวตนในชีต
6. **บทบาท (เพื่อแสดงผลและเรียงลำดับเท่านั้น):** ตามหมวดของศูนย์ (`ROLE_RULES`) · หมวดกว้าง “Entertainment” อ่านจากชื่อ: โรงภาพยนตร์ คาราโอเกะ โบว์ลิ่ง VR ห้อง escape เป็นความบันเทิง · ที่เล่นเด็กและเกมเซ็นเตอร์เป็นเครื่องเล่นและครอบครัว · ฟิตเนส · ที่เหลืออ่านแบบร้านทั่วไป · ศูนย์ไม่ให้หมวด → บทบาทของชุดข้อมูลรายอุตสาหกรรมที่มีชื่อแบรนด์ตรงกันทุกตัวอักษร เมื่อทุกชุดที่ตรงอ่านบทบาทเดียวกัน (`candidate_dataset_ids`) ไม่ทำให้ได้รหัสแบรนด์หรือโลโก้ · ในบทบาทเดียวกัน ร้านที่ผูกแบรนด์แล้วขึ้นก่อนรายการไดเรกทอรี (`js/tenants.js#rankTenants`)
7. **แบรนด์:** รหัสแบรนด์และโลโก้เฉพาะเมื่อชีตยืนยันการผูก (`registry_brand_membership_linked` แบรนด์เดียว) — รอบนี้ 4 รายการ ไม่มีโลโก้ · รายการไดเรกทอรีไม่อยู่ในการค้นแบรนด์ มุมมองแบรนด์ และแบรนด์ของศูนย์ใกล้เคียง (`mergeDirectoryCounts` เพิ่มเฉพาะจำนวนร้านและบทบาท)

**ผลลัพธ์:** `data/directory/NN.json` 32 ส่วน (ฟังก์ชันแบ่งส่วนเดียวกับ `data/tenants/`) · `data/directory/counts.json` (จำนวนและบทบาทต่อสถานที่ — ตัวเลขร้านข้างในของแผนที่ ตาราง พื้นที่ ตัวกรอง “ข้างในมี” และศูนย์ใกล้เคียง) · `data/directory/build-report.json` (ใบรับรองข้อมูลเข้า ผลของทุกแถวตามเหตุผล ความครบรายสถานที่ และ `rosterSha256` / `venueCoreSha256` ที่ build นี้อ่าน — test ล้มเมื่อรายชื่อแบรนด์หรือแกนสถานที่เปลี่ยนโดยไม่สร้างไดเรกทอรีใหม่) · `--receipt` เขียนผลรายแถว (observation id → แสดง / มีอยู่แล้ว / พักไว้พร้อมเหตุผล) สำหรับเขียนสถานะในชีต เก็บนอก repository

**ตัวเลข (export 7 พ.ย. 2569):** 26,955 แถว → แสดง 15,137 แถวเป็น 14,941 รายการใน 65 ศูนย์ · มีอยู่แล้ว 3,161 แถว (ตรงรหัส 1,835 · ชื่อและชั้นเดียวกัน 1,326) · พักไว้ 8,657 แถว (เคาน์เตอร์ 7,749 · `held_counter_or_component` 674: เอ็มโพเรียม 456 ที่ชีตยังไม่ตัดสินว่าเป็นเคาน์เตอร์หรือร้าน และเอ็มควอเทียร์ 218 ที่ซ้ำจากอีกหน้าของไดเรกทอรี · การมองเห็นของผู้บริโภค 163 · จุดบริการ 40 · กิจกรรมและพื้นที่ส่วนกลาง 14 · รูปแบบร่วมหรือห้าง 10 · สิ่งอำนวยความสะดวก 4 · เร็ว ๆ นี้ 2 · ผู้ประกอบการไม่มีชื่อ 1) · รายชื่อร้านทั้งเว็บ 22,159 รายการใน 639 สถานที่

**ข้อจำกัด:** รายการคือชื่อที่ศูนย์ลงไว้ในวันที่ตรวจ ไม่ใช่ร้านที่ตรวจภาคสนาม ผู้เช่าตามสัญญา หรือยอดขาย · การไม่มีในไดเรกทอรีไม่ได้แปลว่าปิด · ชื่อที่ศูนย์เขียนต่างภาษากับชุดข้อมูลแบรนด์อาจปรากฏสองครั้งจนกว่าจะผูกแบรนด์ · การรู้ว่าเป็นจุดบริการใช้คำในชื่อและหมวด · บทบาทจากชื่อหรือชุดข้อมูลที่ชื่อตรงกันเป็นการจัดกลุ่ม ไม่ใช่การยืนยันแบรนด์ · ลำดับการสร้างใหม่: หลังสร้างรายชื่อแบรนด์ (`data/tenants/`) หรือแกนสถานที่ใหม่ทุกครั้ง ให้รัน `build-directory-listings.py` อีกรอบ

### 9.12 แบรนด์ในห้างสรรพสินค้า (0.1.28, 8 พ.ย. 2569 · D40)

เจ้าของ 8 พ.ย. 2569 01:18 ตอบคำถามที่ 2 ว่า “separate category”

- **ที่มา:** แถวของ `18_OFFICIAL_TENANTS` ที่ไดเรกทอรีของศูนย์ลงเป็นเคาน์เตอร์ภายในห้างสรรพสินค้าของศูนย์ (D38 พักไว้ 7,749 แถว) · `scripts/build-directory-listings.py` อ่านชื่อห้างและชื่อแบรนด์จากป้ายของแถว แล้วรวมตาม (ศูนย์ · ห้าง · แบรนด์) — แบรนด์เดียวกันหลายชั้นเป็นหนึ่งแบรนด์ที่มีหลายชั้น
- **ไม่แสดงเป็นแบรนด์:** แถวที่เป็นชื่อห้างเอง (`department_store_name_row`, 14 แถว) · ร้านที่ยังไม่เปิด จุดบริการ และแถวที่ไม่มีลิงก์สาธารณะ ตามกฎเดียวกับ D38 · เอ็มโพเรียม 456 แถวและเอ็มควอเทียร์ 218 แถวยังพัก (`held_counter_or_component`) เพราะชีตยังไม่ตัดสินว่าเป็นเคาน์เตอร์หรือร้าน และเป็นมุมมองซ้ำของไดเรกทอรี
- **บนเว็บ:** `data/directory/NN.json#venues.<id>.counters` = [{store, brands, floors:[{floor, brands}], sourceUrl, checkedOn, sourceObservationCount}] · แผงสถานที่มีหัวข้อ “แบรนด์ในห้างสรรพสินค้า” ใต้ร้านข้างใน พับไว้ · ไม่นับในร้านข้างใน ไม่อยู่ในการค้นตามแบรนด์ ไม่เข้าการเทียบศูนย์ใกล้เคียง และแบรนด์เดียวกันอาจอยู่ในรายชื่อร้านด้วย (ร้านแยกของแบรนด์นั้นในศูนย์)
- **ใบรับรายแถว (ส่วนตัว):** สถานะ `shown_as_department_store_brand` / เหตุผล `department_store_brand`
- **ตัวเลข (export 7 พ.ย. 2569):** 7,735 แถว → 7,268 แบรนด์ใน 18 ศูนย์ของเซ็นทรัล (เซ็นทรัล ภูเก็ต 933 · เซ็นทรัล พระราม 9 841 · เซ็นทรัลเวิลด์ 801 · เซ็นทรัล ปิ่นเกล้า 540 …)
- **แก้กฎจุดบริการ:** รุ่น 0.1.27 อ่านชื่อแบรนด์ที่ขึ้นต้นด้วย baby และ “customer service” เป็นจุดบริการของศูนย์ · รุ่นนี้ 17 แถวขึ้นเป็นรายการไดเรกทอรี (เช่น BABY LOVETT · Baby Basket · BABY FACE CLINIC · Huawei Customer Service Center) · ไดเรกทอรี 14,941 → 14,958 รายการ
- **พิสูจน์ไม่ได้:** รายชื่อในไดเรกทอรีวันที่ตรวจ ไม่ใช่เคาน์เตอร์ที่ยืนยันหน้างาน พื้นที่ขาย หรือยอดขาย

### 9.13 พื้นที่ย่อยของสยามสแควร์: ทะเบียน การนับ ร้าน และใบรับ (0.1.28, 8 พ.ย. 2569 · D41)

- **ทะเบียน (เขียนโดย Claude และอ่านกลับ 8 พ.ย. 2569):** แท็บ `01_VENUES` 4 แถว 12 ช่อง — สยามสแควร์วัน `SC-001223` · SIAMSCAPE `SC-001222` · Centerpoint Siam Square `SC-001236`: `parent_venue_id` = `VN-5523fa4482b213` · `count_role` `venue_site` / `venue_site_candidate` → `child_zone` · `hierarchy_role` → `retail_component` (สยามสเคปเป็นอยู่แล้ว) · ต่อท้าย `review_reason` ทั้งสี่แถวด้วยคำตัดสินและค่าเดิม · `count_role` และ `hierarchy_role` ของสยามสแควร์ไม่เปลี่ยน · ข้อมูลรุ่นนี้สร้างจาก export 7 พ.ย. 2569 23:55 น. ที่แทนค่า 12 ช่องนั้น (ไม่ได้ดาวน์โหลดใหม่) — `meta.inputs.01_VENUES.sha256` คือไฟล์นั้น
- **การนับ:** พื้นที่ย่อยไม่นับ (`child_zone`) และไม่วาดเป็นหมุดของตัวเอง เมื่อเลือกสยามสแควร์ จุดของพื้นที่ย่อยขึ้นพร้อมกัน · ทั้งบล็อกนับเป็นหนึ่งแห่ง กลุ่มตาม §3.2
- **ร้าน (หน้าเว็บ, `js/tenants.js`):** รายชื่อร้านของสถานที่ที่นับได้รวมร้านของพื้นที่ย่อย (ลูกที่ไม่นับ) แต่ละร้านมีชื่อพื้นที่ย่อยกำกับ (`createTenantLoader` `parts`) · ดัชนีร้านนับร้าน บทบาท และแบรนด์ของพื้นที่ย่อยที่สถานที่หลัก และย้ายแบรนด์ของพื้นที่ย่อยไปที่สถานที่หลัก เพื่อไม่ให้ “พบใน N สถานที่” นับบล็อกเดียวซ้ำ (`rollUpSubAreas`) · ร้านของพื้นที่ย่อยเองไม่เปลี่ยน (แผงของพื้นที่ย่อย และรายการพื้นที่ย่อยในแผงหลัก) · กฎเดียวกันใช้กับทุกสถานที่ที่มีพื้นที่ย่อยซึ่งมีร้าน: สยามสแควร์ 13 → 42 · เกษรวิลเลจ 14 → 22 (เกษรอัมรินทร์ 8) · ร้านข้างในของสถานที่ที่นับได้และเปิดอยู่ 22,100 รายการใน 614 แห่ง → 22,108 ใน 612 แห่ง
- **ค้นหา (`js/model.js#prepareRows`):** คำค้นของสถานที่ที่นับได้รวมชื่อพื้นที่ย่อย — ค้น “Siam Square One” แล้วแผนที่แสดงสยามสแควร์ และพื้นที่ย่อยอยู่ในผลค้นหากลุ่ม “พื้นที่ย่อย”
- **ใบรับ:** shard รายชื่อแบรนด์และ shard ไดเรกทอรีไม่เปลี่ยนแม้แต่ไบต์เดียว · `scripts/refresh-tenant-receipt.py --previous <core เดิม>` ให้ใบรับรายชื่อร้านชี้ core ใหม่ · ใบรับความครบ (`data/tenant-coverage-audit.json`) ใช้ `scripts/refresh-coverage-receipt.py --previous <core เดิม> --hierarchy SC-001223,SC-001222,SC-001236,VN-5523fa4482b213 --decision "<คำตัดสิน>"` — โหมดใหม่ยอมให้สถานที่ที่ระบุเปลี่ยนเฉพาะช่องลำดับชั้น (`parentId` `children` `countRole` `countable` `countHold` `countBasis` `group` `groupBasis`) ตามคำตัดสินของเจ้าของ ที่อื่นยังต้องเปลี่ยนแค่ช่องพิกัด ไม่งั้นหยุด · บันทึกใน `venueCoreRefresh.hierarchyChange` ว่ารอบตรวจส่วนตัวครั้งก่อนอ่านความสัมพันธ์แม่-ลูกก่อนการเปลี่ยนนี้ รอบหน้าต้องอ่านความสัมพันธ์ใหม่ (`componentPublicationHosts`)
- **ความต่างของหลักฐาน:** หมายเหตุวิจัยของสยามสแควร์เขียนว่า สยามสแควร์วันเป็นหน่วยธุรกิจแยกของสำนักงานจัดการทรัพย์สิน จุฬาฯ และ “component relations remain pending; no automatic parent” — D41 ปิดเรื่องการนับและการแสดงผล ไม่ได้แก้ข้อเท็จจริงเรื่องการบริหาร · ขอบเขตบล็อกเป็นคำนิยามของเจ้าของ ยังไม่ได้ลากเป็นรูปแปลง

## 10. รายการที่ยังไม่ผ่านนิยาม (Owner decision D4)

รายการที่ยังไม่ผ่านนิยามมีสองสถานะ: **รอตรวจ** (รอบนี้ 0 — คิวปิดครบ) และ **ยังยืนยันไม่ได้** (4,869 — `reviewed_definition_unconfirmed`; ไม่ใช่การสรุปว่าไม่ใช่สถานที่ค้าปลีก) ที่มีพิกัด 4,851 รายการ อยู่ใน `data/pending.json` แบบ columnar (`id, name, lon, lat, provinceCode, districtCode, group, state`; `state = "reviewed"` สำหรับที่ยังยืนยันไม่ได้ — รอบนี้ทุกจุด) โหลดหลังภาพแรก วาดเป็นจุดเทาเล็กด้วย GPU layer ที่ zoom ≥ 11 ไม่มีโลโก้ ไม่อยู่ใน tab order ซ่อนได้จากคำอธิบายแผนที่ (“ยังยืนยันไม่ได้ 4,851”, `?pending=0`) ค้นหาได้พร้อมป้ายสถานะและคำว่าไม่นับ และกดแล้วได้การ์ดย่อ “ยังยืนยันไม่ได้ · ไม่นับ” ไม่เข้าตัวเลข สี หรือกราฟใด ๆ ถ้าโหลดไม่ได้ ตัวเลขทั้งหมดไม่เปลี่ยน

## 11. อาคารของสถานที่

รูปทรงมาจาก geometry bundle ที่ทีมวิจัยตรวจแล้ว เชื่อมด้วย `13_BUILDING_LINKS` (`qualified_host_observation_ids`, `preferred_part_observation_ids`) เข้ากับ `venue_id` ที่ผ่านนิยาม รอบนี้ 130 รูปทรงของ 77 สถานที่ (parts 10 สถานที่ · footprint อย่างเดียว 67 สถานที่; 75 สถานที่อยู่ในชุดที่นับได้ — เซ็นทรัล พาร์ค นับแล้วรอบนี้ — ส่วนเกษรอัมรินทร์ และอาคารผู้โดยสารหลักที่ 1 เป็นพื้นที่ย่อย)

- parts ใช้ `selected_base_m` → `selected_top_m`; โครงการแม่ที่มี parts วาดเป็นเส้นขอบ
- footprint ที่มีความสูงจากโมเดลหรือ OSM ยกตามความสูงนั้น; ความสูงที่ไม่รู้ใช้แผ่นแสดงผล 3 ม. โดย `height_m` คงเป็น `null`; ความสูงที่รอตรวจ (`model_height_review`) ใช้ 3 ม. ในการแสดงผลและเก็บค่าเดิมไว้ในข้อมูล
- อาคารของสถานที่เป็นชั้นข้อมูลเดียวที่มีสีข้อมูล (LDS map role) มวลอาคารทั้งเมืองจาก OpenFreeMap/OSM เป็นบริบท ความสูงไม่ใช่ข้อเท็จจริงของชุดนี้ และการปัดมุมโค้งในพื้นที่โฟกัสเป็นการแสดงผลเท่านั้น
- **อาคารที่หมุดตั้งอยู่ (เจ้าของสั่ง 25 ต.ค. 2569: “หมุดศูนย์การค้า ทั้ง 8 ประเภท ถึงแม้ไม่ยืนยัน Operator ถ้า mapped กับ 3d building ได้ก็ต้องแสดง 3d building ทั้งหมด”):** สถานที่ที่นับได้ซึ่งไม่มีรูปทรงข้างบน แสดงอาคารจาก layer `building` ของ tile แผนที่ฐาน (OpenMapTiles z14 ของ OpenFreeMap, © OpenStreetMap contributors) ที่หมุดตั้งอยู่ข้างใน หรือห่างขอบไม่เกิน 3 ม. (ความละเอียดของ tile) คำนวณบนเครื่องผู้ใช้เมื่อแผนที่หยุดนิ่งที่ zoom ≥ 14 (`js/pin-buildings.js`) — ทำทีละรูปหลายเหลี่ยม เพราะ OpenFreeMap รวมอาคารที่สูงเท่ากันใน tile เดียวเป็น MultiPolygon ที่ใช้ id เดียว · อาคารที่มี building:parts (เส้นขอบ `hide_3d`) ใช้ parts ข้างในเส้นขอบ · รูปหลายเหลี่ยมที่ใหญ่เกิน 150,000 ตร.ม. ไม่นับเป็นอาคารของสถานที่ · ชิ้นของอาคารเดียวกันใน tile ข้างเคียงหาได้จากพื้นที่ซ้อนกันจริง (ไม่ใช่ผนังที่ติดกัน) · ไม่ใช้ชื่อ และไม่ใช้อาคารที่ใกล้ที่สุด ตลาดเปิดโล่งที่หมุดไม่อยู่ในอาคารจึงไม่มีอาคาร · วาดสีน้ำเงินเดียวกับอาคารของสถานที่ ขยายออก 0.8 ม. และยก 0.4 ม. ให้ครอบสำเนาสีเทาของแผนที่ฐาน (ตั้งแต่ 0.1.18 ปัดมุมและขยายเท่าอาคารบริบท ข้อ 11.4) ความสูงตาม `render_height` ของแผนที่ฐาน (อาคารที่แหล่งไม่มีความสูงใช้ค่าตั้งต้นของ schema) · แผงสถานที่บอกว่า “อาคารของสถานที่” หรือ “อาคารที่หมุดตั้งอยู่” หรือ “ยังไม่พบอาคารที่ตำแหน่งหมุด” · รูปทรงเหล่านี้ไม่ได้บันทึกเป็นไฟล์ข้อมูลของชุดนี้
- **มวลอาคารทั้งเมืองอ่านได้ทุกที่:** มวลอาคารนอกโฟกัสจางลงตามระยะ (500 → 2,200 ม.) วัดจากจุดของสถานที่ในโฟกัสและจากกลางภาพ (ขยับจุดเมื่อกลางภาพเลื่อนเกิน 300 ม. ที่ zoom ≥ 12.5) และอาคารที่ OpenFreeMap รวมเป็นชิ้นเดียววัดจากชิ้นที่ใกล้ที่สุด · หน้าสถานที่โฟกัสวงรัศมี 650 ม. รอบสถานที่ — แก้อาการที่ชานเมืองและต่างจังหวัดไม่มีอาคาร 3 มิติ (สาเหตุเดิม: จุดวัดระยะเป็นจุดยอดของเขตโฟกัสหรือ 60 แถวแรกของข้อมูล และอาคารที่ถูกรวมทั้ง tile วัดจากจุดแรกของมัน จึงจางหายทั้ง tile)
- สิทธิ์: ODbL (OpenStreetMap) เว้นแต่รูปทรงระบุอื่น · README ของ bundle ระบุว่าการที่ production ใช้ได้ไม่ได้พิสูจน์สิทธิ์เผยแพร่ต่อแบบเปิดโดยลำพัง

### 11.1 อาคารต่อพื้นที่ ภูมิประเทศ และไซต์หลายอาคาร (0.1.9, 5 พ.ย. 2569)

เจ้าของสั่ง 5 พ.ย. 2569 00:34: “ช่วยปรับการแสดงผล 3d building mass พร้อม terrain ในรูปแบบเดียวกับ https://montri-th.github.io/hotel ทั้งส่วนที่เป็น multiple building property (campus style) รวมถึงการใช้แหล่งข้อมูลอาคารเสริมจาก CityMETER: building ด้วย เพื่อซ่อมพื้นที่ต่างจังหวัดที่ OSM มีข้อมูลอาคารจำกัด”

- **หน่วยและกฎ (กฎของ CityMETER · Hotel, เจ้าของตัดสิน 1 พ.ย. 2569 “ใช้เกณฑ์ 15% … ได้”, “กรุงเทพฯ ใช้เขตเป็นหน่วย … ได้”):** หน่วย = อปท. (production `municipalityInfos`) ที่มีสถานที่ที่มีพิกัดอย่างน้อย 1 แห่ง · กรุงเทพฯ ใช้เขต (อ่านอาคารทีละแขวง) · ใช้ CityMETER Building V4 เมื่อจำนวนอาคารในหน่วย ≥ 1.15 เท่าของ OpenStreetMap ในหน่วยเดียวกัน ไม่งั้นใช้ OSM · ทั้งสองแหล่งต่ำกว่า 10 อาคาร = `gap`
- **วางสถานที่ลงหน่วย:** จุดของสถานที่อยู่ในเส้นขอบหน่วย (เส้นขอบของ hotel ที่ตัดสินแล้ว หรือเส้นขอบ อปท. จาก production `base/info/geom/{id}/MUNICIPALITY`) · กรุงเทพฯ ตามรหัสเขตของสถานที่ · ไม่ใช้ชื่อ · ผล: 6,072 จาก 6,076 สถานที่ที่มีพิกัด (4 จุดอยู่นอกเส้นขอบทุก อปท.)
- **ผล (`data/building-units/index.json`):** 2,175 หน่วย ใน 77 จังหวัด · CityMETER 2,153 · OSM 22 · gap 2 · ใช้ผลที่ hotel ตัดสินแล้ว (นับ 1 พ.ย. 2569, `montri-th/hotel@177e592`) 1,643 หน่วย · ตัดสินใหม่ 532 หน่วย: จำนวน CityMETER จาก production `building/info/lv1/{province}?version=V4` (อ่าน 5 พ.ย. 2569) · จำนวน OSM จาก ohsome API (HeiGIT; OSM วันที่ 27 ก.ค. 2569; ทาง `building=*` แบบ way) ในกรอบสี่เหลี่ยมของหน่วยเป็นเพดาน 518 หน่วย และในรูปหน่วย (ลดจุดเหลือ ≤ 200; 4 รูปทำให้ถูกต้องด้วย shapely ก่อนนับ) 14 หน่วย · ใหม่เป็น CityMETER 531 หน่วย OSM 1 หน่วย · ไฟล์จังหวัดรวม 5.1 MB (gzip ราว 1.4 MB) โหลดเฉพาะจังหวัดที่ภาพต้องใช้
- **บนแผนที่ (ถึง 0.1.17 · ตั้งแต่ 0.1.18 เลือกทีละอาคาร OSM ก่อน ตามข้อ 11.4):** ในหน่วย CityMETER ชั้นอาคารโฟกัสวาดอาคาร CityMETER Building V4 (ไทล์ production z14 ต่อ อปท./แขวง, วาดอาคารละครั้งจากไทล์ที่มีจุดภายใน, รูปทรงปัดมุมเหมือน OSM, สูงตาม `height_m` ซึ่งเป็นค่าประมาณจากแบบจำลอง; ไม่มีค่าใช้ 3 ม.) แทนอาคาร OSM ที่จุดภายในอยู่ในหน่วย · อาคาร OSM ที่วาดเป็นหลายส่วน (`building:part`, LOD2) คงไว้ และไม่วาดอาคาร CityMETER ที่ตั้งอยู่ในเส้นขอบนั้น · ไทล์ที่โหลดไม่ได้หรือเกิน 40 คำขอต่อโฟกัส คงเป็น OSM · ชั้นมวลอาคารทั้งเมืองซ่อนชิ้นของ OpenFreeMap ที่ถูกแทนหรือทับอาคารของสถานที่ทั้งชิ้น แล้ววาดอาคารอื่นของชิ้นนั้นกลับ (ในโฟกัสเป็นอาคารโฟกัส นอกโฟกัสเป็นบริบทสีจาง) จึงไม่มีอาคารหาย · แสดง “อาคาร: CityMETER Building V4” ในเครดิตแผนที่ขณะมีอาคารของชุดนี้บนจอ
- **อาคารที่หมุดตั้งอยู่ในหน่วย CityMETER (ถึง 0.1.17 · ตั้งแต่ 0.1.18 เลือกทีละอาคาร OSM ก่อน ตามข้อ 11.4):** ใช้อาคาร CityMETER ที่หมุดอยู่ข้างในหรือห่างขอบไม่เกิน 3 ม. (กฎเดิม ไม่ใช้ชื่อ ไม่ใช้อาคารใกล้สุด) · อาคาร OSM แบบหลายส่วนคงเป็น OSM · ถ้า CityMETER ไม่มีอาคารที่จุดนั้นแต่ OSM มี ใช้ของ OSM · “หลักฐานรายช่อง” บอกแหล่งรูปทรงและว่าความสูงประมาณจากแบบจำลอง
- **ภูมิประเทศ (เหมือน hotel 0.3):** เปิดเองในมุม 3 มิติ ที่ zoom ≥ 12.5 เมื่อพื้นในภาพต่างระดับ ≥ 30 ม. (ปิดเมื่อ < 20 ม. หรือ zoom < 12.2) · เมื่อเปิดสถานที่ ใช้ความต่างระดับ ±1 กม. รอบหมุดแทน · ภูมิประเทศ 3 มิติขยาย 1.5 เท่า (คำอธิบายแผนที่บอก) + เงาเนินโทนพื้นฐานของธีมใต้สีข้อมูล · สีเขต/อำเภอดับที่ zoom 12.5 (ตัดทันที ไม่จาง) · อาคารตั้งบนพื้น (MapLibre ยกตามพื้นที่ centroid) ภาพอาคารที่เปิด (x-ray) ยกตามพื้นที่ centroid และผนังลงถึงพื้นต่ำสุดใต้อาคาร · กล้องสถานที่คำนวณบนพื้นจริงและลองมุมอื่นของอาคารเมื่อ MapLibre จะยกกล้องพ้นเนิน · กรุงเทพฯ ที่ราบไม่เปิด · DEM: Terrain Tiles on AWS (Mapzen/Tilezen, SRTM 30 ม. สำรวจปี 2543) โหลดในเบราว์เซอร์
- **ไซต์หลายอาคาร (campus style, เหมือน hotel 0.3.6):** `data/venue-sites.json` เก็บจุดภายในอาคารละ 1 จุดของไซต์จากงานวิจัย (≤ 600 ม. จากหมุด) จำนวนอาคาร แหล่ง ลิงก์ผังสาธารณะ และวันที่ เท่านั้น (ขอบเขต เลขโฉนด และข้อมูลแปลงอยู่ในชีตวิจัย) · แต่ละจุดหาอาคารด้วยกฎเดียวกับหมุด · แผงสถานที่เขียน “ทั้งโครงการ N อาคาร” (N ตามรายการของไซต์) · `scripts/build-venue-sites.py --sites <CSV>` อ่านแท็บไซต์ `SITE_BOUNDARY_CHECK` ของชีตวิจัยศูนย์การค้า (คอลัมน์ชุดเดียวกับ `49_SITE_BOUNDARY_CHECK` ของ hotel) เฉพาะแถว `checked` (จุดห่างหมุดเกิน 600 ม. หยุด build) · **ยังไม่มีไซต์ของศูนย์การค้าที่ตรวจแล้ว:** แท็บไซต์เปิด 5 พ.ย. 2569 (381 แถว: `todo` 366 · `osm_area` 15) และทีมวิจัยได้รับใบสั่งงานแล้ว ไฟล์จึงยังว่างและยังไม่มีไซต์บนแผนที่จนกว่าจะมีแถว `checked` และ rebuild · ทีมวิจัยใช้ `scripts/site-candidates.mjs` (เหมือนของ hotel: อ่านอาคาร CityMETER Building V4 ด้วยโค้ดเดียวกับแผนที่ จุดอาคารทุกจุดต้องมาจากตัวช่วยนี้ ไม่อ่านพิกัดจากแผนที่อื่น) และรายการงานที่เรียงตามพื้นที่อาคารที่รายงาน (ค่าประมาณเดิม ใช้จัดลำดับงานภายในเท่านั้น ไม่ขึ้นหน้าเว็บ — D3) · **ร่างจาก OpenStreetMap (เจ้าของ 5 พ.ย. 2569 20:38 น. “ลองตามที่พี่แนะนำได้เลย เริ่มที่ ราว 130 ศูนย์ที่ร่างได้เลย ตรวจแห่งละ 3–5 นาที ก่อน”):** `draft` เลือกขอบเขตพื้นที่ใน OpenStreetMap ที่เล็กที่สุดที่หมุดตั้งอยู่ (`landuse=retail` · พื้นที่ `shop=mall` ที่ไม่ใช่อาคาร · `amenity=marketplace`) แล้วเลือกอาคาร CityMETER ทุกหลังที่จุดภายในอาคารอยู่ในขอบเขต (กฎเดียวกับ `row --site`; `scripts/site-draft.mjs`) · Claude ร่างเฉพาะขอบเขตที่ไม่มีหมุดของสถานที่อื่นที่นับ (ยกเว้นส่วนประกอบของศูนย์เอง) และทุกมุมห่างหมุดไม่เกิน 600 ม. · ร่างไม่ใช่แถว `checked` ทีมวิจัยตรวจทุกแห่ง (3–5 นาที) แล้วยอมรับด้วย `--source osm_outline` หน้าเว็บเขียนแหล่งว่า “ขอบเขตพื้นที่จาก OpenStreetMap” พร้อมลิงก์ OSM · ขอบเขต OSM ไม่ใช่โฉนด เนื้อที่ หรือกรรมสิทธิ์ · แท็บภายใน `SITE_DRAFTS` (5 พ.ย. 2569 · อ่าน OpenStreetMap ครบ 381 ศูนย์): `ready` 118 แห่ง (1,603 อาคาร) · `one_building` 9 · `osm_area` 8 · `empty` 3 · `by_hand` 1 (เมกาบางนา) · `not_drafted` 242 · **Claude ตรวจและเผยแพร่ (เจ้าของ 5 พ.ย. 2569 23:57 น. “ภาคผนวก ข คืออะไรไม่เข้าใจครับ ผมต้องทำอะไรต่อ พี่ทำให้จบเลยได้มั้ย”, D28, เว็บรุ่น 0.1.13):** ไม่ตัดอาคารหลักเสมอ (อาคารที่หมุดตั้งอยู่ ถ้าหมุดไม่ได้ตั้งบนอาคารใช้อาคารใหญ่สุดในร่าง) · ตัดอาคารที่มีจุดใน OpenStreetMap ของโรงแรมและที่พัก (แท็ก tourism hotel, motel, hostel, guest_house, apartment) ศาสนสถาน สถานีตำรวจ สถานีดับเพลิง ศาลาว่าการ สถานีขนส่ง หรือเรือนจำ และอาคารเล็กกว่า 1,000 ตร.ม. ที่มีจุดปั๊มน้ำมัน · ตัดอาคารที่จุดภายในอยู่ในที่ดินอยู่อาศัย โรงเรียน มหาวิทยาลัย วิทยาลัย อนุบาล โรงพยาบาล หรือสถานีขนส่ง ที่อยู่ในขอบเขตทั้งผืน เล็กกว่าครึ่งของขอบเขต และไม่ครอบหมุด · จุดโรงเรียนกวดวิชาและคลินิกในอาคารห้างถือเป็นผู้เช่า ไม่ตัด · อาคารที่เส้นตัดผ่านอยู่ฝั่งที่มีพื้นที่เกินครึ่ง · ตัดอาคารที่จุดภายในซึ่งตัวช่วยคำนวณตกบนขอบอาคารพอดี (check ไม่ผ่าน) · อ่าน OpenStreetMap จากชั้นแผนที่ OpenFreeMap ชุด 1 พ.ย. 2569 เพราะ Overpass ใช้ไม่ได้ตั้งแต่ราว 00:16 น. 6 พ.ย. จึงไม่ได้ตรวจประเภทอาคารที่ระบุเป็นแท็กอาคาร (คอนโด สำนักงาน บ้าน) · ไม่ได้เทียบผัง ภาพดาวเทียม หรือแปลงโฉนด · `boundary_source = osm_outline_auto` (หน้าเว็บ “ขอบเขตพื้นที่จาก OpenStreetMap · ตรวจด้วยกฎอัตโนมัติ”) · ผล 6 พ.ย. 2569: 119 ไซต์ 1,685 อาคาร (ตัดหอโรงแรม 4 หลังใน 4 ศูนย์ · ตัดอาคารที่ส่วนใหญ่อยู่นอกเส้น 4 · เพิ่ม 2 · ตัดอาคารที่จุดตกขอบ 1) รวมเมกาบางนา 89 อาคารตามคำตอบเจ้าของ · ทุกแถวผ่าน `check` · เจ้าของอนุญาตให้เขียนแท็บ `SITE_BOUNDARY_CHECK` แล้ว (6 พ.ย. 2569) Claude เขียนคอลัมน์ C–L 131 แถว อ่านกลับ 3,810 ช่องตรงทุกช่อง และ `check` ด้วยจุดที่อ่านกลับผ่าน 119/119 · ไฟล์ไซต์สร้างจากแท็บแล้ว (`meta.input.kind = site_tab_export`; ก่อนได้รับอนุญาตสร้างจากแถวที่เตรียมไว้ด้วย `--staged`) · สถานที่ที่มีรูปทรงอาคารที่ตรวจแล้ว (host) ยังใช้รูปทรงเดิม และไซต์เพิ่มอาคารอื่นของโครงการ (29 ไซต์)
- ข้อจำกัด (Observed fact จากเอกสาร hotel): จำนวน CityMETER บางหน่วยต่ำผิดปกติ (เทศบาลตำบลเชียงคาน 98, เทศบาลเมืองนครพนม 72) · ความสูงบางอาคารเป็นค่าชั้นเดียว · ไม่มีการระบุสิทธิ์เผยแพร่ของ CityMETER Building V4 · ด้านลาดลงของอาคารบนเนินลอยเหนือพื้นเล็กน้อย (MapLibre ยกทั้งหลังตามพื้นที่ centroid)

### 11.2 มวลอาคารจากไฟล์แบบของโครงการ (0.1.15, 6 พ.ย. 2569)

เจ้าของส่งไฟล์ SketchUp ของ PARC Bangna และ LIVE Ramintra เมื่อ 6 พ.ย. 2569 09:19 น.: “ผม upload .skp สำหรับ PARC Bangna และ Live Ramintra พี่ช่วยนำไปใช้งานร่วมกันใน website และ simplify ให้เหมาะสมที่ user จะใช้งานร่วมกับอาคารอื่นๆในเวบได้ลื่นไหล optimize ให้ดี” · 09:22 น.: “จะชึ้นใหม่ให้พอได้รูปร่าง 3d building mass ก็ได้นะครับ ให้โหลดเร็วๆไม่หนัก” · 09:23 น.: “เอาที่พี่ว่าดีเลย”

- **สิ่งที่เผยแพร่:** มวลอาคารอย่างง่าย (LOD1: รูปพื้น ฐาน และยอดของแต่ละชิ้น) ตำแหน่งที่วาง วันที่ของไฟล์ (27 ต.ค. 2569) และวันที่ได้รับเท่านั้น · ไฟล์แบบอยู่นอก repo · ไม่เผยแพร่ชื่อไฟล์ ตำแหน่งไฟล์ในเครื่อง หรือภาพดาวเทียมที่ใช้ตรวจ (ภาพตรวจใช้ภายในเท่านั้น) · ทดสอบ `venue-models` ไม่ยอมให้ไฟล์ที่เผยแพร่มีนามสกุลไฟล์แบบ ลิงก์ส่วนตัว หรือ path ในเครื่อง
- **จากไฟล์เป็นมวลอาคาร (`scripts/skp-masses.py`):** อ่านไฟล์ SketchUp 2025 โดยตรง ไม่ใช้โปรแกรม SketchUp · ใช้เฉพาะกลุ่มของโครงการ ไม่เอากลุ่มบริบท ชั้นที่ซ่อนในไฟล์ คน ต้นไม้ รถ เฟอร์นิเจอร์ และป้าย · ทำแผนที่ความสูงทุก 0.5 ม. แล้วแบ่งเป็นชิ้นตามช่วงความสูง 1.5 ม. (สูงจากพื้นของแบบตั้งแต่ 2.5 ม. · ชิ้นละอย่างน้อย 12 ตร.ม. · ลดจุดที่ 0.6 ม.) · ชิ้นที่ผิวล่างสูงเกิน 2.5 ม. และผนังลงถึงพื้นไม่ถึง 15% ของขอบ เป็นแผ่นลอย (หลังคาคลุม สะพาน) ฐานอยู่ที่ผิวล่างนั้น · ความสูงทุกค่าเป็นความสูงตามแบบ ไม่ใช่ผลรังวัด
- **วางบนแผนที่ (`scripts/venue-model-placements.json` → `scripts/build-venue-models.py`):** ไฟล์ทั้งสองไม่มีพิกัดจริง จึงวางด้วยการหมุนและเลื่อนจากหมุดในทะเบียน (เมตรไปทางตะวันออก/เหนือ) แล้วตัดตามขอบเขตไซต์ถ้ามี · ตัดชิ้นที่บางกว่า 0.6 ม. (ราว ป้าย ขอบ) เว้นแต่ชิ้นนั้นกว้างตั้งแต่ 2,000 ตร.ม. ซึ่งเป็นหลังคาหรือลาน · จุดใดห่างหมุดเกิน 600 ม. build หยุด · ไฟล์ละไม่เกิน 60 KB · สถานที่ที่ตั้ง `"publish": false` ไม่มีไฟล์บนเว็บ และทดสอบไม่ยอมให้มีไฟล์ที่ดัชนีไม่ได้ระบุ
- **ตำแหน่งที่เจ้าของเลือกจากภาพตรวจ (Owner-stated, 6 พ.ย. 2569):**
  - **LIVE Ramintra (`VN-af6f8f302b8c83`) — เผยแพร่แล้ว:** เจ้าของเลือก “B: บนโครงที่กำลังสร้าง” คือทิศเหนือของแบบตรงกับทิศเหนือจริง และอาคารโค้งวางบนโครงอาคารที่กำลังก่อสร้างในภาพดาวเทียม คลาดได้หลายเมตร · 15 ชิ้น สูงสุด 16.5 ม. ตามแบบ · ไฟล์ 9.5 KB · ชิ้นบางที่เก็บไว้มีชิ้นเดียว คือแผ่นหลังคา 8,465 ตร.ม. หนา 0.5 ม. ที่ความสูง 4.9–5.4 ม. ตามแบบ ขนาดใกล้สวนในร่ม 5 ไร่ที่เจ้าของเล่าไว้ (Owner-stated ยังไม่มีเอกสาร)
  - **PARC Bangna (`SC-000977`) — ยังไม่เผยแพร่:** ภาพตรวจชุดแรก เจ้าของตอบ “ภาพ B ไม่ค่อยตรงสภาพจริง หรือ ภาพถ่าย satellite เลย พี่หาที่ดีกว่านี้ได้มั้ย” · ภาพ C วางครึ่งเหนือของไฟล์ลงตรงอาคารปัจจุบันได้ แต่ครึ่งใต้ยาวเกินที่ดินไปตกถนนบางนา–ตราด และอาคารยาวฝั่งเหนือที่สร้างแล้วไม่มีในไฟล์ (เทียบกับภาพดาวเทียมปัจจุบัน) ไม่มีการหมุนหรือเลื่อนแบบเดียวที่ทำให้ทั้งไฟล์ตรง · เจ้าของเลือก “รอไฟล์ที่ตรงกับที่สร้างจริง” → `"publish": false` · PARC ยังแสดงอาคารของไซต์ 14 หลังตาม §11.1
- **บนหน้าเว็บ:** `js/venue-models.js` อ่านดัชนี `data/venue-models.json` แล้วโหลดไฟล์ของสถานที่ครั้งเดียว เมื่อเปิดสถานที่ หรือเมื่อกรอบของสถานที่อยู่ในภาพที่ zoom ≥ 14 · `js/buildings.js` วาดมวลอาคารเป็นอาคารของสถานที่ (สีน้ำเงินของอาคารสถานที่) แทนอาคารที่หมุดตั้งอยู่และอาคารของไซต์ อาคารบริบทที่ทับจึงไม่วาด · แผงสถานที่เขียน “อาคาร · มวลอาคารตามแบบของโครงการ” และใน “หลักฐานรายช่อง”: จำนวนชิ้น วันที่ของไฟล์ ความสูงสูงสุดตามแบบ วิธีวาง และ “ไม่ใช่ผลรังวัด และอาจต่างจากอาคารที่สร้างจริง”
- **ข้อจำกัด:** แบบไม่ใช่สภาพจริง — LIVE ยังสร้างไม่เสร็จ และไฟล์ PARC ไม่ตรงกับอาคารที่สร้างแล้ว · ตำแหน่ง LIVE มาจากการเทียบภาพ คลาดได้หลายเมตร · LOD1 ไม่มีหลังคาโค้งหรือลาด · ทำซ้ำได้: `python3 -I scripts/skp-masses.py <ไฟล์แบบ LIVE> VN-af6f8f302b8c83 <dir> --bounds -260 -120 260 330 --groups 0,1,2,4,5,8,9,10,11,12,13` ได้ผลเดิมทุกไบต์ (ตรวจ 6 พ.ย. 2569) แล้ว `python3 scripts/build-venue-models.py <dir>`
- **0.1.18 (เจ้าของ 7 พ.ย. 2569 08:25 · VERBATIM: “Live Ramintra พี่วางตึกเกินขอบเขต site ไปสองก้อนที่วงในภาพแนบ ตัดสองก้อนนั้นออก เหลือไว้แค่อันกลาง”):** ไม่วาดแผ่นหลังคา 8,465 ตร.ม. ห่างไปทางเหนือราว 270 ม. (มวลที่ 8) และชิ้นอาคารโค้งห่างไปทางตะวันตกราว 200 ม. (มวลที่ 13–16) ด้วย `drop_parts` ใน `scripts/venue-model-placements.json` · เหลือ 10 ชิ้น 6.6 KB จุดไกลสุดห่างหมุด 145 ม. · ชิ้นเล็กที่เหลือใกล้อาคารหลัก (ใหญ่สุด 117 ตร.ม. สูง 5 ม. ห่างไปทางตะวันตกราว 90 ม.) คงไว้ตามภาพที่เจ้าของวงไว้ 2 ก้อน

### 11.3 ไซต์หลายอาคารรอบสอง: ตลาดและสถานที่ที่ยังไม่มีไซต์ ทั่วประเทศ (0.1.17, 7 พ.ย. 2569)

เจ้าของสั่ง 6 พ.ย. 2569 23:19 น.: “ปรับเรื่อง การรวม venue ที่มีหลายอาคาร เป็น multiple building venue และใช้วิธีตาม skill ใหม่เพิ่มเติม * `osm-area-site-join และ` * `campus-site-join` เรียงลำดับแบบฉลาดนะ เอาแบบ quick win เอา low hanging fruit ก่อน แค่ให้ครอบคลุมทั้งประเทศ ถ้าสำคัญน้อย เอายาก ก็ไม่เอาครับ” · 7 พ.ย. 2569 (คำตอบในแชท): “เพิ่มแถวท้ายแท็บได้” — ตลาดและสถานที่ที่แท็บไซต์ยังไม่มี เพิ่มเป็นแถวท้ายแท็บ ตรวจด้วยกฎ D28 แล้วเผยแพร่ (D31)

- **ลำดับงาน (ทำง่ายและได้มากก่อน):** สถานที่ที่มีพิกัดและยังไม่มีไซต์ 4,475 แห่ง (ตลาด 4,026 · ไฮเปอร์มาร์เก็ตและซูเปอร์มาร์เก็ตที่มีร้านเช่า 208 · ศูนย์การค้า 126 · คอมมูนิตี้มอลล์ 106 · เอาท์เล็ต 9) · แบ่งเป็นช่อง 0.5° แล้วเรียงตามจำนวนสถานที่ต่อคำถามหนึ่งครั้ง (ศูนย์การค้าและคอมมูนิตี้มอลล์ได้น้ำหนักมากกว่าตลาด) · อ่าน 29 ช่องแรก (กรุงเทพฯ แบ่งเป็น 4 ช่อง 0.25°) ครอบคลุม 2,483 แห่ง (55%) ใน 41 จังหวัด · ช่องที่เหลือมีสถานที่ไม่กี่แห่งต่อช่อง ใช้คำถามมากแต่ได้ไซต์น้อย จึงยังไม่อ่าน
- **กรอบพื้นที่จาก OpenStreetMap (`osm-area-site-join`):** Overpass ทีละช่อง เว้นอย่างน้อย 45 วินาที รันจากหน้าเว็บของเราเอง · 28 ช่องจาก overpass-api.de ข้อมูล OSM ณ 7 พ.ย. 2569 01:44–02:49 น. · 1 ช่อง (หาดใหญ่–สงขลา 6.5–7.0°N 100.0–100.5°E) จาก overpass.kumi.systems ซึ่งข้อมูลอยู่ที่ 24 ก.ค. 2569 (3 ไซต์จากช่องนี้: SC-C2501 · SC-C1408 · SC-011833) · จับคู่กรอบกับหมุดด้วยตำแหน่งและชื่อตามกฎของ skill (`osm_match.py --dataset mall`)
- **เลือกกรอบ (กฎเดียวกับ D28):** กรอบที่เล็กที่สุดซึ่งหมุดตั้งอยู่ (`landuse=retail` · `shop=mall` ที่ไม่ใช่อาคาร · `amenity=marketplace`) ไม่มีหมุดอื่นของรอบนี้ 1,000–600,000 ตร.ม. และไม่ได้ตั้งชื่อตามสถานที่อื่น · `landuse=commercial` ใช้เฉพาะเมื่อชื่อตรงกับสถานที่ · ได้ 270 แห่ง (site tag 251 · commercial ที่ชื่อตรง 19) · ร่างด้วย `scripts/site-candidates.mjs draft --outline` ได้ 254 แห่ง · ร่างไม่ได้ 16: หน่วยที่แผนที่วาดอาคาร OSM (`osm_area`) 14 · กรอบไกลหมุดเกิน 600 ม. 2
- **ตรวจกิจการอื่น (D28 + แท็กอาคาร):** Overpass กลับมาใช้ได้ จึงอ่านแท็กอาคารเพิ่มจากรอบ 0.1.13 (`building` = hotel · apartments · residential · dormitory · house · detached · terrace · religious · temple · church · mosque · shrine · school · university · college · kindergarten · hospital) นอกจากจุดและที่ดินตามกฎเดิม · ข้อมูล OSM ณ 7 พ.ย. 2569 05:53–06:04 น. (6 คำถาม 1,149 รายการ) · ห้องแถวที่ OSM แท็ก `terrace` หรือ `house` ถือเป็นที่อยู่อาศัยและตัดออก เพราะใส่อาคารของเพื่อนบ้านผิดแย่กว่าขาดไปหนึ่งหลัง (`campus-site-join`)
- **ผล (Claude ตรวจอัตโนมัติ):** 177 ไซต์ 2,911 อาคาร (ตลาด 171 · คอมมูนิตี้มอลล์ 3 · ศูนย์การค้า 2 · ไฮเปอร์มาร์เก็ตที่มีร้านเช่า 1) ใน 25 จังหวัด · มัธยฐาน 8 อาคาร ใหญ่สุดตลาดเจริญศรี อุบลราชธานี 142 อาคาร · ตัดอาคารกิจการอื่น 90 หลังใน 18 ไซต์ (แท็กห้องแถว `terrace` 52 · บ้าน 25 · จุดโรงแรม 5 · ศาสนสถาน 3 · `apartments` 3 · โฮสเทล 2) · ตัดอาคารที่ส่วนใหญ่อยู่นอกเส้น 6 · เพิ่มอาคารที่ส่วนใหญ่อยู่ในเส้น 11 · ตัดอาคารที่จุดภายในตกขอบอาคาร 1 (โรบินสัน ไลฟ์สไตล์ สระบุรี) · ข้าม 92 แห่ง: เหลืออาคารเดียว 41 · ไม่มีอาคาร CityMETER ในกรอบ 34 · ร่างไม่ได้ 16 · มีหมุดสถานที่อื่นที่นับในกรอบ 1 · ทรู ดิจิทัล พาร์ค ผ่านกฎเช่นกันแต่ไม่เขียนทับ เพราะทีมวิจัยตรวจด้วยผังของผู้ดำเนินการแล้ว
- **เขียนแท็บไซต์ `SITE_BOUNDARY_CHECK`:** ต่อท้าย 173 แถว (แถว 383–555: ตลาด 171 · โลตัส ลพบุรี · บีไฮฟ์ ไลฟ์สไตล์ มอลล์ ที่แท็บยังไม่มี; คอลัมน์ A–Z ครบ hint บอกวันที่และคำสั่ง) · เขียน C–L ของ 4 แถว `todo` (แถว 39 · 41 · 244 · 314) · ไม่แตะแถวที่ทีมตัดสินแล้ว · map หัวตารางและ `venue_id` ใหม่ก่อนเขียน (ไม่มีแถวเปลี่ยนระหว่างงาน) · อ่านกลับผ่าน gviz CSV 4,538 ช่อง ไม่ต่างเลย และแถวอื่นไม่เปลี่ยน · แถว 41 เขียนอีกครั้งหลัง `check` เพื่อตัดอาคารจุดตกขอบ แล้วอ่านกลับตรง
- **`check` ด้วยจุดที่อ่านกลับ:** ผ่านครบ 299 แถว `checked` · 4 จุดที่เป็นอาคาร OSM (หลังคา Topgolf ของเมกาบางนา และ 3 อาคารของแฟชั่นไอส์แลนด์ที่ทีมวิจัยใส่) ตรวจด้วยโค้ดอ่านอาคาร OSM ของตัวช่วย (`scripts/site-osm.mjs`, โค้ดเดียวกับแผนที่) ในเบราว์เซอร์ เพราะเครื่องทำงานเข้าไทล์ OpenFreeMap ไม่ได้
- **`data/venue-sites.json`:** 299 ไซต์ 4,606 อาคาร ใน 38 จังหวัด (เดิม 119 ไซต์ 1,685 อาคาร) = 119 เดิม + 177 รอบนี้ + 3 แถวของทีมวิจัย (แฟชั่นไอส์แลนด์ 4 · เดอะ พรอมานาด 2 · ทรู ดิจิทัล พาร์ค 4 อาคาร; `site_layout` ผังของผู้ดำเนินการ ตรวจ 7 พ.ย. 2569 ผู้ตรวจ “Codex (draft)”) · อ่านจากแท็บ 554 แถว (`site_tab_export`, SHA-256 `aa9ee9a1…40f5`)
- **`campus-site-join` (ผังโครงการและโฉนด):** ไม่ได้ทำรอบนี้ — ต้องหาผังทีละแห่งและใช้โควตา LandsMaps 20 ครั้งต่อวัน ได้ไซต์น้อยต่อเวลา จึงเข้าข่าย “เอายาก ก็ไม่เอา” · ศูนย์ใหญ่ที่ยังไม่มีไซต์ ทีมวิจัยทำต่อในแท็บเดิมได้
- **ข้อจำกัด:** ขอบเขต OSM ไม่ใช่โฉนด เนื้อที่ หรือกรรมสิทธิ์ · ไม่ได้เทียบผัง ภาพดาวเทียม หรือแปลงโฉนด · ห้องแถวที่ OSM ไม่ได้แท็กยังอยู่ในไซต์ (Inference: ไซต์ตลาดบางแห่งอาจรวมห้องแถวเอกชนรอบตลาด) · หมุดตลาดหลายแห่งไม่ได้ตั้งบนอาคาร แถวจึงใช้อาคารใหญ่สุดในกรอบเป็นอาคารหลัก · ร่างรอบนี้มีเฉพาะอาคาร CityMETER Building V4 — อาคารที่ CityMETER ไม่มีแต่ OSM มี (แบบหลังคา Topgolf) ไม่ได้ใส่ เพราะเครื่องทำงานอ่านไทล์ OpenFreeMap ไม่ได้ · 35 จุดใน 14 ไซต์ (จาก 4,606) เป็นอาคารเล็กกว่า 12 ตร.ม. ซึ่งแผนที่ไม่วาด (`MIN_PART_AREA_M2`) เช่น ตลาดเจริญศรีนับ 142 อาคาร แผนที่วาด 131 ส่วนอาคาร (“หลักฐานรายช่อง” บอกทั้งสองตัวเลข) — `check` ของตัวช่วยยังไม่ใช้ขั้นต่ำนี้ · ข้อมูลแผนที่ © OpenStreetMap contributors (ODbL) — การเผยแพร่จุดที่เลือกด้วยกรอบ OSM นอกเดโมควรให้ฝ่ายกฎหมายดูก่อน

### 11.4 มุมมนแบบเดียวกันทุกอาคาร และ OpenStreetMap ก่อน CityMETER (0.1.18, 7 พ.ย. 2569 · D32)

> กฎเลือกแหล่งอาคารในหัวข้อนี้ใช้ถึง 0.1.21 ตั้งแต่ 0.1.22 ใช้ §11.6 (D35) แทน มุมมนยังเหมือนเดิม

เจ้าของสั่ง 7 พ.ย. 2569 08:25: “PARC Bangna ทำได้ดีนะ แต่ทำไมมุมไม่มน style ไม่เหมือนอาคารอื่นๆที่ทำก่อนหน้านี้ ทำให้เหมือนกัน พวกอาคารที่พี่เอามาจาก CityMETER ทั้งหมดก็น่าจะเหมือนกัน ปรับให้ style มุมมนเหมือนกันหมดนะ” · 08:31: “ให้ดีคือ ถ้ามี อาคารจาก OSM ที่รายละเอียดดีกว่า ให้ใช้ OSM ก่อน CityMETER ใช้ เป็น fallback นะ”

- **มุมมน (แสดงผลเท่านั้น):** อาคารสีน้ำเงินของสถานที่ทุกชนิด (รูปทรงที่ตรวจแล้ว อาคารที่หมุดตั้งอยู่ และอาคารของไซต์ ทั้งจาก OSM และ CityMETER) วาดแบบเดียวกับอาคารบริบทในโฟกัส: ขยายออกเท่ากัน (อย่างน้อย 0.8 ม.) แล้วปัดมุมด้วยรัศมีเดียวกัน (ราว 4 px บนจอ ในช่วง 3–12 ม. ตามระดับซูม) โดยมุมที่ปัดยังครอบรูปเดิม · มวลอาคารจากไฟล์แบบปัดมุมอย่างเดียว ไม่ขยาย (ชิ้นเล็กสุดราว 12 ตร.ม.) · ภาพอาคารที่เปิด (x-ray) ใช้รูปเดียวกัน · การจับคู่หมุด การตัดอาคารซ้ำในชั้นโฟกัส และแผงข้อมูลใช้รูปเดิม (`js/buildings.js#shapeVenueGeometry`)
- **สิ่งที่พบก่อนตั้งกฎ (Observed fact, 7 พ.ย. 2569):** ไทล์ z14 ตัวอย่าง 8 ช่องในหน่วย CityMETER (ปาร์ค บางนา · เอสพลานาด รัชดา · ไลฟ์ รามอินทรา · อุบลฯ · ขอนแก่น · ภูเก็ต · หาดใหญ่ · โคราช) มีอาคาร OSM ที่ ≥ 12 ตร.ม. 9,302 หลัง · 9,055 หลัง (97%) CityMETER Building V4 มีอาคารเดียวกันรูปทรงเดียวกัน (จำนวนจุดเท่ากันเป็นส่วนใหญ่ สัดส่วนพื้นที่มัธยฐาน 1.00 · อาคาร CityMETER ที่ตรวจที่เอสพลานาดระบุแหล่ง `osm_geom`) · 129 หลัง (1.4%) มีใน OSM แต่ CityMETER ไม่มี ซึ่งก่อน 0.1.18 ไม่ถูกวาดเลย เพราะหน่วย CityMETER แทนอาคาร OSM ทั้งหมด · OSM แยกละเอียดกว่าหรือรูปละเอียดกว่า 62 หลัง (0.7%) · อาคารที่มีเฉพาะใน CityMETER มีหลายร้อยถึงหลายพันหลังต่อช่อง (รูปเหลี่ยม · อาคารของไซต์ปาร์ค บางนาเป็นกลุ่มนี้) · อาคาร OSM ในคู่ที่ตรงกัน 95% ใช้ความสูงตั้งต้นของ OpenMapTiles (5 ม.) ส่วน CityMETER มีความสูงจากแบบจำลอง
- **กฎ (`js/building-choice.js` · ใช้กับอาคารบริบทในโฟกัส `js/massing.js` และอาคารที่หมุดตั้งอยู่ `js/pin-buildings.js#matchInUnit`):** ในหน่วย CityMETER ตัดสินทีละอาคาร (1) แหล่งหนึ่งวาดเป็นอาคารเดียว แต่อีกแหล่งมี 2 หลังขึ้นไปที่จุดภายในอยู่ในนั้น และรวมกันอย่างน้อยครึ่งหนึ่งของพื้นที่ → ใช้แหล่งที่มีหลายหลัง · (2) อาคารเดียวกันทั้งสองแหล่ง → ใช้ OSM เมื่อรูปทรงละเอียดกว่า (มุมมากกว่า นับเฉพาะจุดที่แนวผนังเลี้ยวเกิน 10° และพื้นที่ไม่ต่ำกว่าครึ่งของ CityMETER) หรือใหญ่กว่า CityMETER เกิน 2 เท่า ไม่งั้นใช้ CityMETER · (3) มีแหล่งเดียว → ใช้แหล่งนั้น · อาคาร OSM แบบหลายส่วน (LOD2) ตัดสินก่อนและคง OSM · ชิ้นอาคาร OSM ที่ขอบไทล์ตัดไม่ใช้จำนวนมุมตัดสิน และไม่นับในข้อ (1) · อาคารที่เล็กกว่า 12 ตร.ม. ไม่ใช้ตัดสิน · อาคาร OSM ที่วาดแทน CityMETER แต่ความสูงเป็นค่าตั้งต้น 5 ม. ใช้ความสูงของ CityMETER ของอาคารเดียวกัน (ค่าประมาณจากแบบจำลอง) และเครดิต CityMETER Building V4 · “หลักฐานรายช่อง” ของอาคารที่หมุดตั้งอยู่เขียน “ความสูงประมาณจากแบบจำลองของ CityMETER Building V4”
- **ผลที่คาด (Inference จากตัวอย่าง):** รูปทรงส่วนใหญ่ไม่เปลี่ยน · อาคารที่มีเฉพาะใน OSM กลับมาบนแผนที่ · อาคารเหลี่ยมที่มีเฉพาะใน CityMETER ยังเป็น CityMETER แต่มุมมนแล้ว
- **ข้อจำกัด:** “ละเอียดกว่า” วัดจากจำนวนมุมของไทล์ z14 ที่ย่อรูปแล้ว ไม่ใช่รูปทรงเต็มในฐานข้อมูล OSM · 8 ช่องเป็นตัวอย่าง ไม่ใช่การสำรวจทั้งประเทศ · ความสูงเป็นบริบท ไม่ใช่ผลรังวัด
- **ข้อมูลที่แก้รอบนี้ (export 7 พ.ย. 2569 09:16 น.):** เอสพลานาด รัชดา (`VN-7e2155ac67fe96`) เดิมไม่มีพิกัด (`not_collected`) จึงไม่ขึ้นแผนที่ → จุดกลางอาคาร OSM way 160080887 “Esplanade Ratchadapisek” (CityMETER Building V4 รูปทรงเดียวกัน 11,638 ตร.ม.) · ท็อปส์ เอสพลานาด รัชดา (`SC-SM-06659`) หมุดเดิมห่างขอบอาคาร 19 ม. (production ตอบว่าไม่มีอาคารที่จุดนั้น) → จุดภายในอาคารเดียวกันจาก `scripts/site-candidates.mjs` · ทั้งสองจุด `owner_identified_host_building_point_not_field_verified` / `host_building_interior_point_not_entrance` · ไม่ได้ผูกเป็นสถานที่แม่และส่วนประกอบ (คงตามทะเบียน)

- **0.1.19 (export 7 พ.ย. 2569 13:57 น.):** เอสพลานาด งามวงศ์วาน-แคราย (`VN-580b36c73e6e3c`) เดิมจุดของโรงภาพยนตร์ถูกพักไว้ (`held_official_cinema_point_conflicts_with_named_place_evidence`) จึงไม่ขึ้นแผนที่ → จุดกลางอาคารที่ OpenStreetMap ตั้งชื่อ “เอสพลานาด ซีนีเพล็กซ์ งามวงศ์วาน-แคราย” (way 260721380, `amenity=cinema`; CityMETER Building V4 รูปทรงเดียวกัน 7,807 ตร.ม. สูง 23 ม.) · `osm_named_host_building_point_not_field_verified` / `host_building_interior_point_not_entrance` · สถานะ บทบาท และลิงก์แหล่งพิกัดเดิมอยู่ใน `review_reason` (เจ้าของตอบ 11:15 น. “OK ทุกข้อ” ต่อข้อเสนอให้ใส่จุดแบบรัชดา) · มีพิกัด 6,081 → 6,082 (อำเภอเมืองนนทบุรี) ข้อค้นพบแรกไม่เปลี่ยน

### 11.5 ไซต์หลายอาคารรอบสาม: ช่องที่เหลือทั่วประเทศ (0.1.19, 7 พ.ย. 2569 · D31)

เจ้าของสั่ง 7 พ.ย. 2569 08:25 น. ข้อ 5: “ผมอยากให้ทำตามที่พี่แนะนำทั้ง 2 อย่างเลยครับ (ก) ดึงช่องที่เหลือ อีก 1,992 แห่ง ส่วนใหญ่เป็นตลาดต่างจังหวัด ได้ไซต์น้อยต่อการดึงหนึ่งครั้ง หรือ (ข) ให้ทีมวิจัยทำผังโครงการและแปลงที่ดินของศูนย์ใหญ่ที่ยังไม่มีไซต์” — รอบนี้คือข้อ (ก) · ข้อ (ข) ส่งใบสั่งงานให้ทีมวิจัยแล้ว (ภายใน)

- **ขอบเขต:** สถานที่ที่นับได้ มีพิกัด ยังไม่มีไซต์และรูปทรงอาคารที่ตรวจแล้ว อยู่นอก 29 ช่องของรอบสอง 1,992 แห่ง (ตลาด 1,885 · ไฮเปอร์มาร์เก็ตและซูเปอร์มาร์เก็ตที่มีร้านเช่า 89 · ศูนย์การค้า 15 · คอมมูนิตี้มอลล์ 3) · รวมเป็น 67 กล่องขนาด 1° ที่ครอบทั้ง 1,992 แห่ง
- **กรอบพื้นที่จาก OpenStreetMap:** 67 กล่องจาก overpass-api.de ทุกกล่อง ข้อมูล OSM ณ 7 พ.ย. 2569 08:43–11:47 น. (ไม่มีกล่องที่ได้จาก mirror เก่า) · พบรูปพื้นที่ 3,139 รูป คู่หมุด–กรอบ 472 คู่ · เลือกด้วยกฎของรอบสอง ได้ 149 แห่ง (site tag 142 · commercial ที่ชื่อตรง 7) · ร่างได้ 146 แห่ง
- **ตรวจกิจการอื่น:** Overpass 3 คำถาม 219 รายการ จาก overpass-api.de ข้อมูล ณ 7 พ.ย. 2569 12:30–12:33 น. (คำถามแรกของกลุ่มที่ 3 ได้ข้อมูลเก่าจาก mirror ณ 24 ก.ค. 2569 จึงถามใหม่ทั้งชุดก่อนใช้) · ตัดอาคารกิจการอื่น 13 หลัง (จุดโรงแรม 3 · โฮสเทล 3 · แท็ก `apartments` 2 · วัด 2 · ห้องแถว 1 · บ้าน 1 · สถานีบริการน้ำมันในอาคารเล็ก 1 · สถานีขนส่ง 1; อาคารหนึ่งหลังมีสองเหตุผล) · ตัดอาคารที่ส่วนใหญ่อยู่นอกเส้น 6 · เพิ่มอาคารที่ส่วนใหญ่อยู่ในเส้น 9
- **ผล (Claude ตรวจอัตโนมัติ):** 93 ไซต์ 1,137 อาคาร (ตลาด 91 · ศูนย์การค้า 1 · ไฮเปอร์มาร์เก็ตที่มีร้านเช่า 1) ใน 42 จังหวัด · มัธยฐาน 5 อาคาร ใหญ่สุดตลาดดอยเวา 108 อาคาร · ข้าม 56 แห่ง: เหลืออาคารเดียว 34 (รวม SC-C3039 ซึ่งอาคารหนึ่งในสองหลังมีจุดภายในตกขอบ `check` ไม่ผ่าน) · ไม่มีอาคาร CityMETER ในกรอบ 19 · ร่างไม่ได้ 3
- **เขียนแท็บไซต์ `SITE_BOUNDARY_CHECK`:** map หัวตารางและ `venue_id` ใหม่ก่อนเขียน · ต่อท้าย 93 แถว (แถว 556–648, A–Z) · เขียน C–L ของแถว `todo` 1 แถว (แถว 106 โรบินสัน ไลฟ์สไตล์ ชัยภูมิ) · อ่านกลับผ่าน gviz CSV: 94 แถวตรงทุกช่อง (hash ต่อแถว) และแถวเดิมอื่นไม่เปลี่ยน · แถว 647 (SC-C3039) เขียนใหม่เป็น `single_building` หลัง `check` แล้วอ่านกลับตรง
- **`check` ด้วยจุดที่อ่านกลับ:** 93 แถว `checked` ของรอบนี้ผ่านครบ
- **`data/venue-sites.json`:** 392 ไซต์ 5,743 อาคาร (เดิม 299 ไซต์ 4,606 อาคาร) · อ่านจากแท็บ 647 แถว (`site_tab_export`, SHA-256 `dcd0b35d…eb650`)
- **ข้อจำกัด:** เช่นเดียวกับ §11.3 — ขอบเขต OSM ไม่ใช่โฉนด เนื้อที่ หรือกรรมสิทธิ์ · ไม่ได้เทียบผัง ภาพดาวเทียม หรือแปลงโฉนด · ร่างมีเฉพาะอาคาร CityMETER Building V4 · ข้อมูลแผนที่ © OpenStreetMap contributors (ODbL) — การเผยแพร่นอกเดโมควรให้ฝ่ายกฎหมายดูก่อน · หลังรอบนี้ ทุกสถานที่ที่ยังไม่มีไซต์ถูกเทียบกับกรอบ OSM แล้วอย่างน้อยหนึ่งครั้ง (ณ 7 พ.ย. 2569) ที่เหลือคือที่ OSM ไม่มีกรอบ มีอาคารเดียว หรือต้องใช้ผังและโฉนด (ข้อ ข)

### 11.6 OpenStreetMap ก่อนทุกที่ CityMETER เฉพาะที่ OSM ไม่มีอาคาร (0.1.22, 7 พ.ย. 2569 · D35)

เจ้าของสั่ง 7 พ.ย. 2569 16:35: “พวกอาคาร mixed use ตอนนี้ยังดูสับสนอยู่ 3d mass ไม่สมจริง ตอนนี้สามย่านมิตรทาวน์ มี mass หลายก้อนทั้งๆที่ของจริงเป็น podium เดียว แต่มี 2 towers Central world ก็มี building mass เกินมา … หาสาเหตุให้เจอ จะได้แก้เคสแบบเดียวกันนี้ที่เกิดกับอาคารอื่นๆด้วยให้ครบ / เช็คดีๆเรื่องการใช้ 3d building mass จาก OSM ที่ LOD สูงกว่าเป็นหลัก แล้วใช้ จาก CityMETER เป็น fallback เท่านั้น บังคับเรื่องนี้ให้ทั่วทั้งเวบ”

- **สาเหตุ (Observed fact จากไทล์จริง 7 พ.ย. 2569):** (1) กฎ D32 (§11.4) ให้ CityMETER Building V4 ชนะอาคาร OSM ได้ — เมื่อ CityMETER มี 2 ก้อนขึ้นไปในอาคาร OSM หลังเดียว หรือรูปเดียวกันแต่ OSM มุมไม่มากกว่า — และหมุดของไซต์เลือกอาคาร CityMETER ก่อน OSM · ที่สามย่านมิตรทาวน์ OSM วาดโพเดียมหนึ่งหลังกับสองทาวเวอร์เป็นส่วนอาคาร (LOD2) แต่แผนที่วาดก้อน CityMETER 6 ก้อน (15–785 ตร.ม. สูง 31–92 ม.) ห่างโพเดียม 0–17 ม. ซ้อนอยู่ · ในไทล์ z14 เดียวกัน (สามย่าน–เซ็นทรัลเวิลด์) อาคารที่มีเฉพาะใน CityMETER 597 หลัง อยู่ห่างอาคาร OSM ไม่เกิน 20 ม. 469 หลัง (พื้นที่ 103,187 ตร.ม. เทียบ 30,336 ตร.ม. ที่ไกลกว่า) ในนั้นสูงอย่างน้อย 15 ม. บนพื้นที่ไม่ถึง 300 ตร.ม. 262 หลัง — ส่วนใหญ่เป็นเงา ต้นไม้ และชิ้นส่วนของอาคารเดียวกัน · ที่ปาร์ค บางนา 161 จาก 1,312 และไลฟ์ รามอินทรา 54 จาก 5,832 ซึ่ง OSM วาดอาคารน้อยและ CityMETER เติมช่องว่างจริง (2) อาคาร OSM ที่โครงร่างมีความสูงของตัวเองและมีส่วนอาคารสูงกว่า (โพเดียมใต้ทาวเวอร์) ถูกซ่อนทั้งรูป เหลือแต่ส่วนอาคาร โพเดียมจึงหาย
- **กฎใหม่ (`js/building-choice.js` · ใช้กับอาคารบริบทในโฟกัส `js/massing.js` อาคารที่หมุดตั้งอยู่และอาคารของไซต์ `js/pin-buildings.js#matchInUnit` ทั่วทั้งเว็บ):** (1) อาคาร OSM แบบหลายส่วน (LOD2) ใช้ส่วนอาคาร และใช้โครงร่างเป็นโพเดียมเมื่อ OSM ให้ความสูงของโครงร่างเอง (ไม่ใช่ค่าตั้งต้น) ต่ำกว่าส่วนที่สูงสุดเกิน 3 ม. · (2) อาคาร OSM (LOD1) ใช้เสมอ ถ้าความสูงเป็นค่าตั้งต้น 5 ม. (ไม่มีแท็กความสูงหรือชั้น) ใช้ความสูงของ CityMETER ของอาคารเดียวกัน (ค่าประมาณจากแบบจำลอง) · (3) CityMETER ใช้เฉพาะที่ไม่มีอาคาร OSM: ไม่วาดเมื่อจุดภายในของมันอยู่ในอาคาร OSM จุดภายในของอาคาร OSM อยู่ในมัน หรืออาคาร OSM คลุมรอยของมันอย่างน้อย 30% · ในโฟกัสไม่วาดเมื่ออยู่ห่างอาคาร OSM ไม่เกิน 20 ม. (OSM วาดช่วงนั้นแล้ว) · อาคารที่หมุดตั้งอยู่ไม่ถูกตัด (D28) · อาคารของจุดไซต์ที่อยู่ติดอาคาร OSM ถูกตัดเฉพาะเมื่อเป็นชิ้นแปลกปลอมของแบบจำลอง: สูงอย่างน้อย 15 ม. บนพื้นที่ไม่ถึง 300 ตร.ม. หรืออยู่ติดอาคารที่ OSM วาดเป็นส่วนอาคาร
- **ผลที่วัดบนไทล์จริง (อาคารของสถานที่ = อาคารที่หมุดตั้งอยู่และของไซต์, ก่อน → หลัง):** สามย่านมิตรทาวน์ 10 (CityMETER 6) → 1 (อาคาร OSM หนึ่งหลัง: โพเดียมกับสองทาวเวอร์) · เซ็นทรัลเวิลด์ 7 (CityMETER 7) → 6 (OSM ทั้งหมด) · เมกาบางนา 91 (84) → 64 (40) · ตลาดเจริญศรี อุบลฯ 131 (131) → 131 (62) · ตลาดดอยเวา 107 → 103 · ตลาดนัดรถไฟศรีนครินทร์ 97 → 85 · ตลาดคำเที่ยง 90 → 88 · เดอะเซอร์เคิล ราชพฤกษ์ 80 → 73 · อุบลสแควร์ 68 → 65 · ตลาดสดเทศบาลเมืองนราธิวาส 91 → 91 · จุดไซต์เมกาบางนา 89 จุด: OSM 38 · CityMETER 40 · ชิ้นแปลกปลอม 11 (19–281 ตร.ม. สูง 15–46 ม.) · เวลาคำนวณโฟกัสไทล์โคราช 215 มิลลิวินาที
- **แผงสถานที่:** นับอาคารของโครงการตามจุดของไซต์ (หนึ่งจุดต่ออาคาร) ไม่ใช่ตามจำนวนชิ้นที่วาด · เขียนว่า “แสดงอาคารจาก OpenStreetMap ก่อน ใช้ CityMETER Building V4 เฉพาะที่ OpenStreetMap ไม่มีอาคาร”
- **ข้อจำกัด:** ระยะ 20 ม. 30% และ 15 ม./300 ตร.ม. ตั้งจากไทล์ตัวอย่าง (Inference) ไม่ใช่การสำรวจทั้งประเทศ · อาคาร CityMETER จริงที่ OSM ยังไม่วาดแต่ชิดอาคาร OSM ไม่เกิน 20 ม. จะไม่ขึ้นในโฟกัส (ยกเว้นอาคารของสถานที่) · ความสูงจาก OSM เป็นแท็กของผู้ร่วมแก้ไข ความสูงจาก CityMETER เป็นแบบจำลอง ทั้งสองไม่ใช่ผลรังวัด · ข้อมูลแผนที่ © OpenStreetMap contributors (ODbL)

### 11.7 One indexed source building through height annotations (0.1.24, 7 November 2026)

A fresh D35 source replay exposed a duplicate main building at The Promenade. OpenStreetMap height annotations created a new JavaScript object for the same indexed source part on the venue pin and the nearly identical site-main reference. The existing object-identity Set therefore admitted it twice. The private WeakMap now retains the original indexed part through height-only clones; the existing per-venue deduplication uses that origin. Distinct source parts and parking E remain separate. No geometry hash, nearest-building merge, threshold, source coordinate, OSM-first priority or height-estimation rule changes.

The regression fixture reproduces the duplicated main footprint before the correction and keeps one main footprint plus one parking footprint afterwards, with original OSM rings retained. The actual current modules replayed with three fresh public CM/OSM tile responses produce two distinct displayed/drawn geometries, no duplicated geometry and parking E covered once. Seacon Srinakarin remains absent from the research-site file; all 392 sites and 5,743 reference points are unchanged. Source/module replay is separate from live rendered QA and independent physical-building verification.


### 11.8 แยกสถานที่: ไซต์ไม่รวมอาคารของสถานที่อื่น (0.1.29, 8 พ.ย. 2569 · D42)

เจ้าของ 8 พ.ย. 2569 08:22 น. พร้อมภาพหน้าจอเอ็มโพเรียม: “เลือก Emporium แล้วมันขึ้น 2 อาคาร รวม EmQuatier ด้วย ต้องแยกกัน / เช็คว่าเคสนี้เกิดกับ venue อื่นอันไหนอีกบ้าง / วิเคราะห์ว่าเกิดจากสาเหตุอะไร / แก้ไขเคสนี้ทุก venue ทั่วประเทศ”

- **สาเหตุ:** กรอบพื้นที่ OpenStreetMap หนึ่งกรอบอาจครอบหลายสถานที่ (`way/836148999` The Em District ข้ามถนนสุขุมวิทไปถึงเอ็มควอเทียร์) กฎตรวจร่างของ D28 (§11.1, `site-draft.mjs#classifyPin`) ดูเฉพาะหมุดของสถานที่อื่นที่อยู่ในกรอบ หมุดของเอ็มควอเทียร์อยู่นอกอาคารของตัวเอง 19.2 ม. และนอกกรอบ ร่างจึงผ่านเป็น `clean`
- **กฎ (`scripts/separate-sites.py`):** (ก) อาคารของสถานที่อื่น — หมุดของสถานที่อื่นอยู่ในอาคารหรือห่างขอบไม่เกิน 3 ม. (`PIN_TOLERANCE_M` ของหน้าเว็บ) · อาคารกับรอยอาคารที่ตรวจแล้วของสถานที่อื่น (`data/venue-buildings.geojson`, `host_building_footprint_not_shop_unit`) ทับกันตั้งแต่ 30% ของฝั่งใดฝั่งหนึ่ง · หรืออาคารมีจุดของไซต์สถานที่อื่น — ไม่อยู่ในไซต์ สถานที่อื่น = นับได้ หรือเป็นส่วนประกอบของครอบครัวอื่น ไม่ใช่สถานที่แม่ พื้นที่ย่อย พื้นที่ย่อยพี่น้อง แถวที่พักไว้ว่าอาจซ้ำ หรือแถวชื่อเดียวกัน · อาคารที่หมุดของสถานที่เอง รอยอาคารของครอบครัว หรือหมุดของครอบครัวอยู่ ไม่ถูกตัดแม้มีหมุดสถานที่อื่นอยู่ด้วย (อาคารเดียวสองสถานที่) (ข) อาคารที่เหลือของไซต์ที่มีกรณี (ก) ไปอยู่ฝั่งที่ใกล้กว่าตามทางที่สั้นที่สุดผ่านช่องว่างระหว่างอาคาร เสมอกันอยู่กับสถานที่เอง (ค) เหลือไม่ถึงสองอาคารเป็น `single_building` · อาคารอ่านจาก `sites/<venue_id>/candidates.json` ของตัวช่วยไซต์ (CityMETER Building V4 ด้วยโค้ดเดียวกับแผนที่) จุด OpenStreetMap ที่ไม่มีใน CityMETER (4 จุดที่เมกาบางนาและแฟชั่นไอส์แลนด์) ตรวจเป็นวงกลม 1 ม. และไม่มีสถานที่อื่นในระยะ 60 ม.
- **ผลทั่วประเทศ (แท็บไซต์ 7 พ.ย. 2569 12:55 น. · 392 ไซต์ 5,743 อาคาร):** เปลี่ยน 3 ไซต์ ตัด 44 อาคาร — เอ็มโพเรียม `SC-000288` 4 → `single_building` (อาคารที่ทับรอยอาคารของเอ็มควอเทียร์ `SC-001765` + 2 หลังเล็กฝั่งนั้น) · เซ็นทรัล อีสต์วิลล์ `SC-001664` 58 → 28 (อาคารที่หมุดโลตัส รามอินทรา `VN-eabf92ed6535f0` อยู่ + 29 หลังฝั่งนั้น) · มาลินพลาซ่า `SC-015703` 19 → 8 (อาคารที่หมุดตลาดเชียงใหม่คอมเพล็กซ์ `SC-C3221` อยู่ + 10 หลังฝั่งนั้น) · รายการให้ทีมวิจัยตรวจ (`review.csv`, ไม่นำไปใช้): หมุดสถานที่นับได้อื่นห่างอาคารของไซต์ 3–25 ม. — หลังแก้เหลือตลาด 11 คู่ (11.1–23.1 ม.)
- **แท็บไซต์:** Claude ตรวจว่า 3 แถว (89, 118, 471) ตรงกับการอ่านกลับ 7 พ.ย. ทุกช่อง (ผู้ตรวจ Claude; ไฟล์ไม่ถูกแก้ตั้งแต่ 7 พ.ย. 12:55 น.) แล้ววางค่าใหม่ C–L ของแถว 89 และ G–L ของแถว 118 และ 471 · อ่านกลับ A–L ตรงทุกช่อง (36 ช่อง) · อ่านกลับคอลัมน์ที่ build ใช้ทั้งแท็บ 648 แถว SHA-256 `c4d879d6…` ตรงกับไฟล์ที่สร้างจากการอ่านกลับ 7 พ.ย. บวกสามแถวนี้ไบต์ต่อไบต์ · หมายเหตุต่อท้ายเป็นภาษาไทยว่าตัดอะไรเพราะอะไร
- **กันไม่ให้เกิดซ้ำ:** `build-venue-sites.py` หยุดเมื่อจุดของไซต์อยู่ในรอยอาคารที่ตรวจแล้วของสถานที่อื่น หรืออาคารเดียวอยู่ในไซต์ของสองครอบครัว (แท็บ 7 พ.ย. หยุดที่เอ็มโพเรียม) · หน้าเว็บ (`js/site-guard.js`, เรียกจาก `pin-buildings.js` เฉพาะจุดของไซต์ ไม่ใช่อาคารที่หมุดตั้งอยู่) ไม่วาดอาคารของไซต์ที่มีหมุดสถานที่อื่นในระยะ 3 ม. หรือทับรอยอาคารของสถานที่อื่นตั้งแต่ 30% (ตัวอย่าง 6 × 6 จุด) — กับไซต์ 7 พ.ย. ตัด 3 อาคารพอดี กับไซต์ 8 พ.ย. ไม่ตัดเลย · ร่างไซต์ (`site-draft.mjs#otherVenuesAt`) เป็น `shared` เมื่อหมุดสถานที่อื่นอยู่ในกรอบหรือห่างกรอบไม่เกิน 30 ม. (`NEAR_M`) หรือรอยอาคารของสถานที่อื่นอยู่ในกรอบตั้งแต่ 30%
- **ไม่ได้ทำ:** ไม่ได้เทียบผังโครงการ ภาพดาวเทียม หรือแปลงที่ดิน · หมุดสถานที่อื่นในรอยอาคารที่ตรวจแล้วของเซ็นทรัล อุดร 2 แห่ง (ตลาดนัดรถไฟอุดรธานี `SC-014500` นับได้ · ตลาดจริงใจ `SC-014564` ส่วนประกอบ) เป็นอาคารเดียวสองสถานที่ ไม่เปลี่ยน

### 11.9 One Bangkok เป็นสถานที่เดียว จุดของสถานที่อยู่ในอาคาร และหอคอยบนโพเดียมเป็นพื้นหลัง (0.1.30, 8 พ.ย. 2569 · D43)

เจ้าของ 8 พ.ย. 2569 09:17 น.: “สำหรับ One Bangkok ผมเห็นว่าเขาล้มเหลวในการสื่อสารชื่อ podium หลายอัน เพราะไม่มีใครจำได้หรือใครให้ความสำคัญในสังคม ในที่สุดน่าจะเหลือชื่อเดียวคือ One Bangkok นั่นแหละ ควรเอา directory มารวมกันเป็นจุดเดียว / ส่วนอาคารสำนักงาน โรงแรม และที่พัก จะแสดงเป็นอาคารพื้นหลัง / เช็คเคสนี้ว่ามีเกิดขึ้นกับที่อื่นอีกมั้ย หาสาเหตุแล้วแก้พร้อมกัน”

- **ตรวจทั่วประเทศ (หน้าเว็บรุ่น 0.1.29 ในเบราว์เซอร์ · อาคารจากชั้นแผนที่ OpenFreeMap และ CityMETER Building V4 ด้วยโค้ดของหน้าเว็บ · 8 พ.ย. 2569):** สถานที่ที่นับและมีจุด (ไม่รวมตลาดและปั๊ม) ที่จุดไม่อยู่ในอาคารที่หน้าเว็บวาดและไม่ห่างขอบไม่เกิน 3 ม. มี 138 แห่ง — `hoststore` 60 · `community` 43 · `mall` 31 · `other` 3 · `outlet` 1 · สถานะพิกัด `current_citymeter_registry_pin_not_field_verified` 110 · `official_branch_locator_point_not_field_verified` 12 · `provider_venue_pin_identity_matched_not_field_verified` 9 · `official_linked_public_map_point_not_field_verified` 4 · อื่น 3 · ไซต์หลายอาคารแล้ว 15 แห่ง (อาคารอื่นของไซต์ยังขึ้น)
- **สาเหตุ:** จุดเหล่านี้เป็นจุดอ้างอิง ไม่ใช่จุดในอาคาร · กฎหมุด (§11, `js/pin-buildings.js`) วาดเฉพาะอาคารที่จุดตั้งอยู่หรือห่างขอบไม่เกิน 3 ม. ไม่ใช้อาคารที่ใกล้ที่สุด จึงไม่มีอาคารขึ้น · ที่ One Bangkok จุดอยู่บนสนามกลางโครงการ และโซน Parade · The Storeys · Post 1928 เป็นพื้นที่ย่อยที่ไม่มีพิกัด
- **ย้ายจุด (`01_VENUES` M–P และต่อท้าย AV):** จุดของ OpenStreetMap (ชั้น `poi` ของแผนที่ OpenFreeMap ที่หน้าเว็บใช้) ที่ชื่อหรือแบรนด์ตรงกับสถานที่ และตั้งอยู่ในอาคาร → จุดภายในอาคารนั้น (ไม่ทับรอยอาคารอื่นที่วาดซ้อน) · สถานะ `osm_named_host_building_point_not_field_verified` บทบาท `host_building_interior_point_not_entrance` ค่าเดิมต่อท้าย `review_reason` · 26 แห่ง (ห่างจุดเดิม 8–175 ม. มัธยฐาน 68 ม.) — ก่อนเขียนอ่านแถวใหม่และเทียบค่าเดิมทุกช่อง (ไม่มีใครแก้หลัง export) หลังเขียนอ่านกลับผ่าน gviz CSV 130 ช่องตรงทุกช่อง · ไม่ย้าย: จุดชื่ออยู่ไกล 146–229 ม. (5 แห่ง) หรือเป็นป้ายรถเมล์ (สยามสแควร์เป็นย่าน) · 106 แห่งไม่มีจุดชื่อในอาคารใกล้จุด
- **One Bangkok:** จุดย้ายเข้าอาคาร Parade (175 ม.) · แท็บไซต์แถว 17 (`todo` → `checked`, `osm_outline`, หลักฐาน `way/608350816` landuse=commercial ชื่อ One Bangkok): จุดภายในอาคาร 3 หลังที่มีจุด `shop=mall` ชื่อ Parade, Post 1928 (ในรอยอาคารเดียวกันมีจุดโรงแรม The Ritz-Carlton) และ The Storeys (มีจุดโรงแรม ANdAZ) — แต่ละจุดอยู่ในรอยอาคาร OpenStreetMap รอยเดียวและในอาคาร CityMETER (`site-candidates.mjs check` 3/3) · อ่านกลับคอลัมน์ที่ build ใช้ทั้งแท็บ 647 แถวตรงกับไฟล์ที่ประกอบไว้ทุกแถว (หัวคอลัมน์ `building_count` ที่ gviz ไม่ส่งมาเอาจากการอ่านหัวตารางโดยตรง) · `data/venue-sites.json` 392 ไซต์ 5,701 อาคาร · `separate-sites.py` ไม่พบไซต์ที่มีอาคารของสถานที่อื่น
- **ไดเรกทอรี (`build-directory-listings.py`):** แถวของโซนที่ทะเบียนเก็บเป็นพื้นที่ย่อยแสดงที่สถานที่แม่ (เดิม) และขึ้นชื่อโซน (`displayQualifier`) เฉพาะโซนที่มีพิกัดของตัวเอง · One Bangkok 195 แถว (Parade 138 · The Storeys 57) ไม่มีชื่อโซนแล้ว ไม่มีสถานที่อื่นเปลี่ยน
- **ชิ้นอาคารข้ามแผ่นแผนที่ (`pin-buildings.js#continuations`, `#stripFit`):** แผ่น z14 ตัดอาคารด้วยขอบกันชน อาคารที่คร่อมรอยต่อจึงมีชิ้นในทั้งสองแผ่น · ชิ้นในแผ่นข้างเคียงเป็นอาคารเดียวกันเมื่อ (ก) ความสูงและฐานเท่ากัน (ข) ซ้อนกันจริง (`deepOverlap`) (ค) ในแถบที่สองแผ่นมีร่วมกัน ชิ้นนั้นอยู่ในชิ้นของสถานที่อย่างน้อย 90% (ตัวอย่าง 10 × 10 จุด) และ (ง) ไม่ซ้อนชิ้นที่นับแล้วในแผ่นเดียวกัน (ชิ้นของอาคารเดียวไม่ซ้อนกันในแผ่นเดียว) เรียงจากชิ้นที่ทับกันพอดีที่สุดก่อน · เดิมนับทุกชิ้นที่ซ้อนกัน หอคอยที่วาดซ้อนบนโพเดียมจึงถูกวาดเป็นโพเดียมเมื่อโพเดียมคร่อมรอยต่อ · ตรวจกับจุด 268 จุดที่ห่างรอยต่อไม่เกิน 120 ม. (สถานที่ที่ไม่ใช่ตลาดและปั๊มทุกแห่ง 165 · ตลาดสุ่ม 80 · ปั๊มสุ่ม 20 · จุดของ One Bangkok 3) ในแผ่นจริง 8 พ.ย. 2569: เหมือนเดิม 127 · ไม่มีอาคารทั้งสองแบบ 133 · เปลี่ยน 8 (One Bangkok 4 · เดอะ ช็อปปส์ แอท เบลล์ แกรนด์ พระราม 9: หอที่พัก 99–158 ม. 4 หลัง · เซ็นทรัล เอ็มบาสซี: หอ 179 ม. ซึ่งหน้าเว็บใช้รอยอาคารที่ตรวจแล้วแทนอยู่แล้ว · เซ็นทรัล วิลเลจ: อาคารเล็ก 9 หลังใกล้รอยต่อแผ่นที่ซ้อนรอยอาคารใหญ่ของเอาท์เล็ต เดิมขึ้นเพียงเพราะอยู่ใกล้รอยต่อ · ดองกิ มอลล์ ทองหล่อ: เศษ 13 ตร.ม. ที่ชิ้นหลักครอบอยู่) · รอบแรกตัดชิ้นของอาคารที่อยู่ตรงมุมสี่แผ่น (BigC สมุทรสงคราม) จึงจำกัดข้อ (ง) ไว้ในแผ่นเดียวกัน
- **ข้อมูลและใบรับ:** export 7 พ.ย. 23:55 + 12 ช่องของ D41 + 130 ช่องของ D43 (ไม่ได้ดาวน์โหลดใหม่) · core เปลี่ยนเฉพาะ `lat`/`lon` ของ 26 แห่ง ไม่มีแห่งใดย้ายเขต และข้อค้นพบแรกไม่เปลี่ยน · `refresh-tenant-receipt.py` และ `refresh-coverage-receipt.py` (จุดอย่างเดียว) ผูกกับ core ใหม่ · รายชื่อร้านจากชุดข้อมูลแบรนด์ไม่เปลี่ยน
- **ไม่ได้ทำ:** ไม่ได้ตรวจภาคสนาม เทียบผังทางการ หรือภาพดาวเทียม · แผนที่ในอาคาร Mappedin ไม่ได้ใช้เป็นข้อมูล · 112 แห่งยังไม่มีอาคาร (อาคารที่ใกล้ที่สุด ไม่เกิน 10 ม. 37 · 10–50 ม. 46 · 50–200 ม. 27 · ไกลกว่า 2) · รายการร้านจากชุดข้อมูลแบรนด์ที่ One Bangkok ยังมีข้อความยูนิตตามแหล่ง

### 11.10 สยามสแควร์: ทุกอาคารในบล็อกที่เจ้าของกำหนด และจุดของอาคารที่ห่างผนัง (0.1.31, 8 พ.ย. 2569 · D44)

เจ้าของ 8 พ.ย. 2569 11:40 น.: “สยามสแควร์ควรจะแสดง highlight ทุกอาคารภายในกรอบที่เคยแจ้งไปเลยนะ” · กรอบ = บล็อกที่เจ้าของกำหนด 7 พ.ย. 2569 20:58 น. (ระหว่างถนนพระราม 1 ถึงซอยจุฬาฯ 64 และระหว่างถนนพญาไทถึงถนนอังรีดูนังต์ “ในนั้นประกอบด้วยหลายอาคารรวมทั้ง สยามสแควร์วัน สยามสเคป โรงแรมโนโวเทลสยาม etc”)

- **บล็อก:** มุมทั้งสี่เป็นจุดตัดเส้นกลางถนน (ช่องจราจรด้านใน) ในชั้น `transportation_name` ของแผ่น OpenFreeMap ที่หน้าเว็บใช้ — 100.530798,13.746149 · 100.53576,13.745324 · 100.535465,13.743522 · 100.53051,13.744216 (113,365 ตร.ม.) · เป็นมุมชุดเดียวกับที่ใช้วางจุดอ้างอิงของสยามสแควร์ 7 พ.ย.
- **อาคาร:** `node scripts/site-candidates.mjs draft VN-5523fa4482b213 --outline <บล็อก>` → อาคาร CityMETER Building V4 ทุกหลังที่จุดภายในอยู่ในบล็อก 44 หลัง · ตัดหลังเดียวที่อยู่นอกบล็อกเป็นส่วนใหญ่ (1,304 ตร.ม. ที่มุมพระราม 1 × พญาไท อยู่ในบล็อก 38%) → 43 หลัง `check` 43/43 · อาคาร OpenStreetMap ที่ CityMETER ไม่มี (จุดภายในไม่อยู่ในอาคาร CityMETER หลังใด และไม่มีจุดของอาคาร CityMETER อยู่ข้างใน) 2 หลัง (≈274 และ ≈489 ตร.ม.) ตรวจด้วย `scripts/site-osm.mjs#createOsmReader` ในเบราว์เซอร์บนหน้าเว็บของเรา (ตู้ทำงานเข้าแผ่น OpenFreeMap ไม่ได้) · รวม 45 จุด · ชิ้นอาคาร OpenStreetMap ในแผ่นแผนที่ของบล็อก 37 ชิ้น (ทุกขนาด อาคารที่คร่อมรอยต่อแผ่นนับเป็นสองชิ้น) มีจุดของไซต์อยู่ข้างใน · หน้าเว็บจริง (r41) วาดครบทั้ง 37 ชิ้นตามกฎ D35 และอาคาร CityMETER 5 หลังที่ OpenStreetMap ไม่มี ไม่มีอาคารนอกบล็อก · แผงอ่าน “ทั้งโครงการ 38 อาคาร” (หนึ่งอาคารต่อจุดที่พบอาคารของตัวเอง: 33 จุดพบอาคาร OpenStreetMap · 5 จุดพบอาคาร CityMETER · อีก 7 จุดอยู่ในอาคาร OpenStreetMap ที่จุดอื่นวาดแล้ว)
- **ไม่ใช้กฎตัด D28:** เจ้าของสั่งทุกอาคาร และนิยามบล็อกของเจ้าของระบุโรงแรมโนโวเทลไว้เอง · อาคารที่ OpenStreetMap มีจุด Novotel Bangkok (โรงแรม) · Police Support Unit สน.ย่อยจตุรัส (ตำรวจ) · BangkokFA (college) · KPN Music Academy (school) และลานจอดรถ อยู่ในไซต์
- **แหล่ง `owner_block`:** คำในหน้าเว็บ “บล็อกตามที่เจ้าของข้อมูลกำหนด” · `site-candidates.mjs row <venue> --source owner_block --site <บล็อก>` ไม่ต้องมี `--evidence` (หลักฐานคือคำนิยามของเจ้าของ หมายเหตุของแถวยกคำพูดและวันที่) · ใช้เมื่อเจ้าของกำหนดขอบเขตด้วยถนนเท่านั้น ไม่ใช่โฉนดหรือกรรมสิทธิ์
- **แท็บไซต์:** สยามสแควร์ไม่มีแถวในแท็บ → เพิ่มแถว 649 ตาม D31 (แทรกแถวใต้แถว 648 · Name Box ยืนยัน A649 · วางทั้งแถว A–Z จากข้อความที่ตรวจ SHA-256 ในหน้าแล้ว) · อ่านกลับ 26 ช่องตรงทุกช่อง · คอลัมน์ที่ build ใช้ของทั้งแท็บ 648 แถวตรงกับไฟล์อ่านกลับ 8 พ.ย. (647 แถว) บวกแถวใหม่ (เทียบ SHA-256 ของทั้งชุดในหน้า) · `data/venue-sites.json` 393 ไซต์ 5,746 อาคาร · `separate-sites.py`: ไม่เปลี่ยนไซต์ใด คู่ส่งทีมวิจัย 11 คู่เดิม
- **จุดของอาคารในแถว (`scripts/site-draft.mjs#sitePoint`):** จุดที่ตัวช่วยเขียนลงแถวต้องอยู่ในอาคารห่างผนังอย่างน้อย 0.5 ม. หลังปัดทศนิยม 6 ตำแหน่ง · ถ้าจุดภายในของแผนที่ (`interiorPoint`) ไม่ผ่าน ใช้จุดในตาราง 41 × 41 บนกรอบอาคารที่อยู่ในอาคารและห่างผนังมากที่สุด · หน่วยอาคาร (CityMETER หรือ OpenStreetMap) ยังตัดสินด้วยจุดภายในของแผนที่ตามเดิม · สาเหตุ: อาคารที่ล้อมลานกลาง (2,763 ตร.ม.) มีจุดภายในห่างขอบลานกลาง 2 ซม. และจุดที่ปัดแล้วตกในลานกลาง `check` จึงไม่ผ่าน และกฎ D28 เคยทิ้งอาคารแบบนี้เป็น “จุดบนขอบ” · ใกล้สยามสแควร์ใช้จุดสำรอง 2 จาก 157 อาคาร · แถวที่เขียนไปแล้วไม่เปลี่ยน (`check` ตรวจด้วยรูปอาคาร ไม่ใช่จุดเดิม) · ทดสอบ `tests/site-draft.test.js` (อาคารล้อมลานกลาง)
- **ไม่ได้ทำ:** ไม่ได้เทียบผังโครงการ รูปแปลง หรือภาพดาวเทียม · จุดของสยามสแควร์และพื้นที่ย่อยไม่เปลี่ยน (ยังเป็นหนึ่งใน 112 จุดที่ไม่อยู่ในอาคาร แต่อาคารของไซต์ขึ้นแล้ว)

## 12. โลโก้สถานที่

ทะเบียน `10_VENUE_LOGOS` (113 ไฟล์ · 4 บทบาท: โลโก้ของสถานที่โดยตรง, โลโก้โครงการแม่, โลโก้ห้างสรรพสินค้าในเครือ, โลโก้เครือ) ไฟล์ถูกใช้เมื่อ SHA-256 ตรงกับชีตเท่านั้น และคัดลอกไม่แก้ไข รอบนี้ครบ 113 ไฟล์ (ทะเบียนโลโก้ไม่เปลี่ยนจากรอบก่อน) ผูกกับ 108 สถานที่ที่นับได้ ([data/venue-logos.json](data/venue-logos.json)); ถ้ารอบหน้ามีไฟล์ที่ยังไม่มาถึง จะอยู่ใน `meta.pending` และสถานที่นั้นแสดงชื่อโดยไม่มีโลโก้ พื้นรองต่อโลโก้คำนวณจากภาพ (โลโก้โปร่งใสบน `#E5E9E6`, โลโก้สีอ่อนโปร่งใสบน `#182327`, ไฟล์ทึบบน `#FFFFFF`) ค้นด้วย `venue_id` เท่านั้น ชื่อสถานที่ยังเป็นตัวตนหลัก การรวบรวมไฟล์ไม่ใช่ใบอนุญาตเครื่องหมายการค้า

### 12.1 โลโก้แบรนด์ของชุดข้อมูลวิจัยในรายชื่อร้าน (0.1.9–0.1.10, 5 พ.ย. 2569)

เจ้าของสั่ง 5 พ.ย. 2569 00:34: “เช็ค Logo จากแบรนด์ต่างๆใน dataset อื่นๆใน dataset registry ที่มีการ update เมื่อสักครู่นี้ แล้วเพิ่ม logo ให้ครบถ้วน”

- แหล่ง: แท็บ `01_BRANDS` ของ research master ทั้ง 11 ชุด (export 5 พ.ย. 2569 หลังทีมวิจัยเก็บโลโก้เพิ่ม) และแพ็กไฟล์โลโก้ที่ทีมวิจัยทำไว้ใน Drive · ใช้ไฟล์เมื่อไบต์มี SHA-256 ตรงกับ `logo_sha256` ของแบรนด์นั้นเท่านั้น ไม่ใช้ชื่อไฟล์ · คัดลอกไม่แก้ไข (`scripts/collect-research-logos.py`)
- ใช้เฉพาะบทบาท `brand_primary` (โลโก้ของแบรนด์เอง) · banner ร่วมของเครือ โลโก้โครงการแม่ โลโก้เฉพาะสาขา โลโก้บริบท/สำรอง และโลโก้ที่ยังรอตัดสินไม่ใช้ (กติกาเดียวกับ MLA และ Fitness)
- พื้นรอง (0.1.10): ไฟล์ที่พื้นทึบคงโทนพื้นของไฟล์ · ไฟล์พื้นโปร่งใสดูจากขอบของตัวโลโก้ (พิกเซลของโลโก้ที่ติดพื้นโปร่งใส ซึ่งเป็นส่วนเดียวที่แตะพื้นรอง): ใช้พื้นมืด `#182327` เมื่อขอบอย่างน้อย 1 ใน 5 จะแทบหายบนพื้นอ่อน (contrast ต่ำกว่า 2:1 เช่น ขาว เทาอ่อน พาสเทล ทอง) และแทบไม่มีส่วนใดหายบนพื้นมืด (ไม่เกิน 5% เช่น ตัวอักษรดำ เส้นกรมท่า) นอกนั้นใช้พื้นอ่อน `#E5E9E6` · พื้นที่ชีตระบุ (`surface=light|dark`, “พื้นหลัง: พื้นสว่าง/พื้นเข้ม”) ใช้ตามชีต ค่าแบบใช้ได้ทั้งสองพื้น (`light_or_dark`, `any`, “checked on light and dark”) ให้ภาพตัดสิน · ถ้าภาพแสดงว่าโลโก้จะแทบหายบนพื้นที่ชีตระบุ ใช้ผลจากภาพและนับ `surfaceConflict` ให้ทีมวิจัยตรวจ (1 แบรนด์ใน Beauty: ตัวอักษรขาวที่ชีตระบุพื้นสว่าง) · SVG อ่านจากภาพที่ Chromium วาด (`scripts/render-svg-logos.cjs`) · ตรวจด้วยตาจาก contact sheet ทุกไฟล์ก่อนเผยแพร่
- ผล (เว็บรุ่น 0.1.10 · ไฟล์จากแพ็กโลโก้ของทีมวิจัยที่ดาวน์โหลดจาก Drive 5 พ.ย. 2569 ด้วยอนุญาตของเจ้าของ): โลโก้ 293 แบรนด์ใน 10 ชุด (ทุกแบรนด์ที่ชีตมีไฟล์บทบาท `brand_primary`) · รายการที่มีโลโก้ 2,506 จาก 3,032 รายการของ 11 ชุด: Apparel 681/681 · Beauty 1,075/1,075 · Salon & Barber 62/62 · Furniture 106/107 · Sport 303/319 · Playground 92/103 · Car Service 106/147 · Pet 45/58 · Massage & Spa 18/21 · Nail 18/23 · Beauty Clinic 0/436 (ชีตยังไม่มีโลโก้ 49 แบรนด์) · ที่เหลือเป็นแบรนด์ที่ชีตเก็บเฉพาะ banner ร่วมหรือโลโก้บริบท (10 แบรนด์) หรือยังไม่มีโลโก้ (Nail 4 แบรนด์)
- รายชื่อร้าน จำนวนร้าน และสาขาไม่เปลี่ยน (เพิ่มเฉพาะช่อง `logo` ของรายการ) · ผลต่อชุดอยู่ใน `data/tenants/build-report.json#researchLogos`
- การรวบรวมไฟล์ไม่ใช่ใบอนุญาตเครื่องหมายการค้า

## 13. สิ่งที่ตัวเลขพิสูจน์ไม่ได้

- ไม่ใช่สำมะโนศูนย์การค้าหรือสถานที่ค้าปลีกของไทย และรายการที่ยังยืนยันไม่ได้ไม่ถูกนับ
- อาคารที่หมุดตั้งอยู่เป็นรูปทรงจากแผนที่ฐานที่ตำแหน่งหมุด ไม่ได้ยืนยันว่าเป็นอาคารของสถานที่นั้นทั้งหลัง และความสูงเป็นค่าของแผนที่ฐาน
- การผ่านนิยามด้วยกฎรายประเภทของเจ้าของ (ตลาด สถานีบริการน้ำมันที่มีร้านค้า และอื่น ๆ) เป็น Owner-stated ไม่ได้เพิ่มหลักฐานผู้บริหารพื้นที่ร่วมรายเดียวของแต่ละแห่ง
- ผ่านนิยามไม่ยืนยันว่าเปิดวันนี้ สถานะมาจากแหล่ง ไม่ใช่ภาคสนาม
- จุดอ้างอิงไม่ใช่ประตูทางเข้า บางจุดเป็นจุดของร้านหลักในสถานที่ (`retailer_branch_reference_point…`)
- จำนวนสถานที่ไม่ใช่ market share, capacity, footfall, ยอดขาย, ค่าเช่า, อัตราว่าง หรือ occupancy และอันดับพื้นที่ไม่พิสูจน์ช่องว่างตลาด
- ขนาดแบบค่าประมาณเดิมไม่ใช่ GLA ทางการ (GLA ที่รายงานโดยตรงมีน้อยมากในทะเบียน)
- ลิงก์ร้านที่ยืนยันแล้วครอบคลุมเฉพาะบางสถานที่และบางชุดข้อมูล การไม่มีร้านในแผงไม่ได้แปลว่าสถานที่ไม่มีร้าน
- รายการจากไดเรกทอรีของศูนย์ (D38) คือชื่อที่ศูนย์ลงไว้ในวันที่ตรวจ ไม่ใช่การยืนยันว่าร้านเปิดอยู่ ผู้เช่าตามสัญญา หรือจำนวนร้านจริงทั้งศูนย์ และยังไม่ใช่สาขาของแบรนด์จนกว่าจะผูกแบรนด์
- ระยะถึงสถานีรถไฟฟ้าเป็นเส้นตรงระหว่างจุดอ้างอิง ไม่ใช่ระยะเดิน และการอยู่ใกล้สถานีไม่ได้พิสูจน์ผู้เข้าชม ยอดขาย หรือผลของรถไฟฟ้าต่อสถานที่ (D33)
- แบรนด์ในห้างสรรพสินค้า (D40) คือรายชื่อที่ไดเรกทอรีของศูนย์ลงในวันที่ตรวจ ไม่ใช่เคาน์เตอร์ที่ยืนยันหน้างาน และไม่นับเป็นร้าน
- กลุ่ม “ศูนย์การค้า” ของย่านที่มีศูนย์การค้าเป็นพื้นที่ย่อย (D41, สยามสแควร์) เป็นการจัดเพื่อการนำทาง ประเภทในทะเบียนยังเป็นย่านค้าปลีก และขอบเขตบล็อกยังไม่ใช่รูปแปลง
- ไซต์หลายอาคารเป็นกลุ่มอาคารเพื่อแสดงบนแผนที่ ไม่ใช่ขอบเขตกรรมสิทธิ์ · การแยกสถานที่ (D42) วัดจากระยะห่างของอาคาร อาคารเล็กที่ตัดออกบางหลังอาจเป็นของสถานที่เอง

## 14. ความต่างของหลักฐานที่รอเจ้าของตัดสิน (MBB §0.4)

1. **ค่า `historical_*_pending`:** รอบนี้ 5 แถว (`historical_managed_retail_definition_current_scope_pending` 3 · `historical_definition_current_retail_scope_pending` 2) นับเป็นหลักฐานย้อนหลังตามคำขึ้นต้น `historical_` (รอบ 24 ต.ค. ตัวเลขผ่านนิยามต่างจาก 00_README 4 แถวพอดีด้วยเหตุนี้; รอบนี้ไม่ได้ export 00_README จึงยังไม่ได้เทียบใหม่)
2. **ผ่านนิยามแต่ไม่นับแยก 51 รายการ** — นับได้ด้วย D6 6 แห่ง (เซ็นทรัล พาร์ค, วัน แบงค็อก (พื้นที่ค้าปลีก), สามย่านมิตรทาวน์, สีลมคอมเพล็กซ์, อาทาระ มอลล์ ศรีราชา, มหานคร คิวบ์) ส่วนที่ไม่มีโครงการแม่ในชุดที่ผ่านนิยามและยังไม่นับ 41 รายการ: พื้นที่ย่อย 12 (Foodland The Brio Mall Sai 4, ตลาดจริงใจ Farmers’ Market เซ็นทรัลอุดรธานี, mpark มหาราช, PARK11, อาคารผู้โดยสารหลักที่ 1, SinoPark แพรกษา, อาคารยิ่งเจริญพลาซ่า, ตลาดเสรีมาร์เก็ต เดอะไนน์ พระราม 9, กาดนั่งก้อม@หนองกระทิง, กาดอัศวิน, ตลาดรุ่งโรจน์ คลอง4, อาคารโบ๊ท อาเขต) · อาจซ้ำ 16 (เช่น ตลาดมโนรมย์ / ตลาดมโนรมย์ 4, ตลาดดวงแก้วพลาซ่า ×2, ตลาดเอซีสายไหม / ตลาดเอ.ซี.สายไหม, วิคตอรี่ ฮับ, Mayfair Avenue, เจ-พาร์ค ศรีราชา นิฮอน มูระ, ตลาดนัดเซนทริค จันทบุรี, มาร์เก็ตเพลสทองหล่อซอย15, ศูนย์การค้าพาวิลเลี่ยนไนท์บาซาร์ เชียงใหม่, พาเพลิน มาร์เก็ต, Think Park Night Market, ตลาดฟันฟรายเดย์ อเวนิว, สถานีบริการ ปตท. พระราม 2 กม.5) · การนับแยกยังรอตรวจ 12 (บิ๊กซี ฟู้ดเพลส 9 สาขาและบิ๊กซี 3 สาขาที่ผ่านกฎ “ร้านหลักที่มีกิจการอื่นอยู่ด้วย”) · บริบทหลายสถานที่ 1 (ตลาดโรงเกลือ) — รายการเต็มพร้อม `hold` ใน `meta.checks.componentsWithoutParent`
3. **วิคตอรี่ ฮับ (`SC-C3713`)** มีสถานะ `definition_supported_named_property_duplicate_count_held` แต่ `count_role = venue_site_candidate` — ถือตามสถานะว่าอาจซ้ำ (เกี่ยวกับ Victory Mall `SC-C1899`) จึงไม่นับจนกว่าทะเบียนจะตัดสิน
4. **จังหวัดในที่อยู่ต่างจากขอบเขตทางการ 510 รายการทั้งทะเบียน** (ผ่านนิยาม 37 · ยังไม่ผ่านนิยาม 473) ส่วนใหญ่อยู่ในจังหวัดที่ติดกัน (แนวกรุงเทพฯ–สมุทรปราการ–ปทุมธานี และระยอง–ชลบุรี) แต่ 4 รายการที่ผ่านนิยามมีที่อยู่กับจุดอยู่คนละจังหวัดที่ไม่ติดกัน — ตลาดบ้านหนองหล่าย (`SC-000667`, ที่อยู่กรุงเทพฯ จุดอยู่ลำปาง), ตลาดไทยพิทักษ์ สลกบาตร (`SC-002473`, กำแพงเพชร/อุตรดิตถ์), ตลาดเสริมพานิช (`SC-007425`, ปทุมธานี/ชัยนาท), ตลาดโกดังมาร์เก็ต @ มวกเหล็ก (`SC-012746`, สระบุรี/อำนาจเจริญ) — น่าจะเป็นพิกัดหรือที่อยู่ผิดในทะเบียน (Inference) รุ่นนี้นับตามจุดตามกฎเดิมและแสดงที่อยู่คู่กันในแผงสถานที่
5. **5 รายการที่ทะเบียนสรุปว่าไม่ใช่สถานที่แยก (ตรงกับชีต: ไม่เข้าเกณฑ์ 2 + บริบทศูนย์แม่/ผู้เช่า 3):** `individual_tenant_component_not_independent_venue` — PASAYA Premium Outlet Cha Am (`SC-016088`), Villa Market ชิค รีพับบลิค ราชพฤกษ์ (`SC-SM-06783`) · `owner_not_qualifying_retail_venue_scope` — โลตัส ลำลูกกา คลอง 4 (`SC-SM-04133`), โลตัส บ่อสร้าง (`SC-SM-04152`) · `parent_context_retail_child_qualified_separately` — ดุสิต เซ็นทรัล พาร์ค (`SC-C0139`) ไม่แสดงและไม่นับ
6. **ดุสิต เซ็นทรัล พาร์ค** (`SC-C0139`, `parent_context_retail_child_qualified_separately`) — รอบ 15:06 น. นับโครงการแม่แทนห้าง รอบนี้ทำตามสถานะของทะเบียน: โครงการแม่เป็นบริบท ไม่นับ และห้างข้างใน เซ็นทรัล พาร์ค (`SC-001066`, `child_venue`, ประเภท `shopping_center`) นับเป็นสถานที่ของตัวเองตาม D6 — จำนวนรวมเท่าเดิม ตัวเลขผ่านนิยามตรงกับชีต (6,135) และอาคารที่ตรวจแล้วของเซ็นทรัล พาร์ค (โพเดียม 13.6 ม. · ทาวเวอร์ 82 ม.) ขึ้นเป็นสีน้ำเงิน
7. **10 แห่งที่ผ่านนิยามมีจุดนอกขอบเขตเขต/อำเภอ** (ตลาดริมทะเลหรือริมแม่น้ำชายแดน) นับในอุปทานทั้งประเทศ แต่ไม่อยู่ในตัวเลขรายพื้นที่ใด — ไม่จับเข้าพื้นที่ใกล้ที่สุดตามกฎ
8. **ทุกแถวยังมี `release_status` แบบ hold** (ตัวตน รูปทรง สิทธิ์ และฟิลด์ที่เหลือ) — หน้านี้เป็น research demo ที่เจ้าของให้เผยแพร่ ไม่ใช่ production release
9. **ชื่อชุดข้อมูลใน Registry** (“จำนวน พื้นที่เช่า และกลุ่มตลาด”) สัญญาเรื่องพื้นที่เช่าและกลุ่มตลาดเกินข้อมูลรุ่นนี้ หน้านี้ใช้ชื่อบนหน้าจอ “ศูนย์การค้า” / “Shopping centers” (D10) และเก็บชื่อเต็มตาม D2 เป็นชื่อรองใน metadata
10. **ชื่อไทยที่ยังยืนยันไม่ได้ 1,237 รายการ และสถานะเปิดจริง/ผู้บริหารล่าสุดที่หลักฐานยังไม่พอ** แยกรอยืนยันในชีต (Owner-stated 25 ต.ค. 2569) — หน้านี้แสดงตามค่าที่มี และหลักฐานรายช่องบอกฐานของชื่อแต่ละแห่ง
11. **โลโก้ของ เซ็นทรัล พาร์ค (`SC-001066`)** ใน `10_VENUE_LOGOS` ใช้ไฟล์เดียวกับ ดุสิต เซ็นทรัล พาร์ค (`SC-C0139`, key `VL-8a8cd8d752f15540`, role `venue_specific`) คือโลโก้ “DUSIT CENTRAL PARK” ของทั้งโครงการจาก dusitcentralpark.com — เมื่อโครงการแม่เป็นบริบท (D15) โลโก้นี้จึงขึ้นบนห้าง เซ็นทรัล พาร์ค ทั้งในแผงและบนแผนที่ · ใช้ต่อ หรือเพิ่มโลโก้ของห้างเองในทะเบียน (รอเจ้าของตัดสิน)
12. **สยามสแควร์ (D41)** — หมายเหตุวิจัยของแถว `VN-5523fa4482b213` เขียนว่า สยามสแควร์วันเป็นหน่วยธุรกิจแยกของสำนักงานจัดการทรัพย์สิน จุฬาฯ และ “component relations remain pending; no automatic parent for Siam Square One, Centerpoint, Siam Scape or Lido” · เจ้าของตัดสิน 8 พ.ย. 2569 ให้สามแห่งเป็นพื้นที่ย่อย (Lido ไม่มีแถวในทะเบียน) · ใช้คำตัดสินของเจ้าของสำหรับการนับและการแสดงผล และคงข้อเท็จจริงเรื่องการบริหารตามแหล่ง (§9.13)

## Additional dated MLA membership evidence — 26 October 2026

The PARC MLA crosswalk covers the project and15 competitors. Original venue/store source populations remain separate from this additional dated evidence. New venue identities are exact named project matches, never a nearest retailer or market. Current selected points win over older MLA alternatives; the newly selected Bangkok Mall point is a project-site reference, not an entrance or footprint. Dadfa’s leased-retail project supports historical definition with current operation unconfirmed. JAS has primary corporate portfolio and exact component-address evidence; approximately19,850sqm is reported leasable area, not surveyed area. PADDIO remains a future project: construction year, Zone1/2 area and floors do not become an actual opening date or whole-site GFA.

Only80 dated public membership observations pass the strict MLA gate. Each has an actual observation date, public branch/host-specific URL, source authority/hash/row identity and exact canonical host. Current operation remains unconfirmed. Of these,78 create display entries and2 corroborate exact existing outlets without raising primary or displayed shop counts. Nineteen held cases stay outside public files. Source dates, actual reading dates, carried-forward listing identities and reconciliation dates remain distinct. Native Sheets DATE columns retain the workbook’s readable full-year date display.

Logo mappings use13 exact brand/approved-alias relationships to11 original source-qualified files;9 files were already locally verified and newly copied byte-for-byte into the public library. Shared-banner and manufacturer substitutions stay held. The roster covers6 hosts with MLA membership facts and does not establish a current complete directory for all15 competitors. Source/source-qualified display grain and primary9-dataset graph grain remain separate.


## Owner-confirmed tenant follow-up - 26 October 2026

The canonical ledger now contains the owner's replies to all 19 held MLA cases and one distinct replacement concept. The latest native source and review cells were re-read before deriving this release. Owner assertions are dated 26 October 2026 and retain their own authority; they are not new website checks or field observations. Only the scope actually confirmed is promoted: names/aliases and host membership do not by themselves establish current operation.

71 Mookata, ANGPANG and the old Dadfa Ohkajhu are closed according to the owner and excluded from the current roster. LOPIA is not open, planned for February 2027 (month only) and remains explicitly hidden with no automatic release. Grill & Ground by Ohkajhu is a separate owner-confirmed new concept at Dadfa; no exact opening day, legal operator, category or logo is inferred. Gravity coffee remains reviewed-unconfirmed and excluded. Moon/Monn is one identity; MitPlaJum corroborates its existing Lasalle outlet; The Fitness host correction does not assert a relocation or a current opening. Historical observations remain in the private ledger.

The public roster preserves original source-qualified entries and their dates. Dated memberships and owner confirmations remain partial coverage, not a current census. The original nine-dataset graph and all primary venue/map/area totals are unchanged.
