1# Data dictionary — WP3823Generated by `src/reports/data_dictionary.py` from the parquet schemas. Raw snapshot fields are described in `reports/00_source_audit.md`.45## `data/interim/listings_clean.parquet` — 390 108 rows × 56 columns67| column | dtype | non-null | description |8|---|---|---:|---|9| `uid` | object | 1.000 | Fabri-Ka listing id (hash of store + platform product id); stable across syncs |10| `store_id` | object | 1.000 | canonical store domain (merchant identifier) |11| `external_id` | object | 1.000 | platform-local product id (not unique across stores) |12| `url` | object | 1.000 | canonical product URL on the merchant site |13| `title` | object | 1.000 | listing title as published |14| `description_head` | object | 1.000 | first 600 characters of the merchant description |15| `description_len` | int64 | 1.000 | length of the full description (chars) |16| `price` | float64 | 0.962 | listed price = MINIMUM variant price at the snapshot (merchant currency) |17| `price_max` | float64 | 0.962 | maximum variant price |18| `compare_at_price` | float64 | 0.146 | merchant strike-through price (on-sale indicator) |19| `currency` | object | 1.000 | merchant currency code |20| `category` | object | 1.000 | Fabri-Ka canonical category (20 keys, rule-based inference; audited in reports/phase2_data_audit.md) |21| `product_type` | object | 1.000 | merchant's own product type |22| `vendor` | object | 1.000 | merchant's brand/vendor field (often the store's own name) |23| `available` | Int64 | 0.987 | merchant availability flag (1 in stock, 0 sold out, NULL unknown) |24| `content_hash` | object | 1.000 | hash of listing content used by the platform's upsert |25| `first_seen` | float64 | 1.000 | epoch seconds of first observation |26| `last_seen` | float64 | 1.000 | epoch seconds of last observation |27| `active` | int64 | 1.000 | 1 if seen in the last two syncs |28| `miss_count` | int64 | 1.000 | consecutive misses (0–2) |29| `listing_status` | object | 1.000 | published | excluded:<reason> | quarantine:<reason> (platform rules) |30| `price_on_request` | int64 | 1.000 | 1 if the merchant shows no price |31| `n_variants` | float64 | 0.756 | number of variants (Shopify/Woo/Wix details) |32| `has_sku` | bool | 1.000 | a merchant SKU is present |33| `sku` | object | 0.769 | first merchant SKU (64 chars max) |34| `grams` | float64 | 0.427 | variant weight in grams (Shopify grams or Woo kg×1000) — first variant |35| `n_options` | float64 | 0.472 | number of option dimensions |36| `variant_prices_min` | float64 | 0.697 | min of variant prices in details |37| `variant_prices_max` | float64 | 0.697 | max of variant prices in details |38| `n_variant_prices` | float64 | 0.697 | number of variant prices |39| `on_sale_flag` | object | 0.085 | Shopify on_sale flag |40| `merchant_categories` | object | 0.184 | merchant's own category path (Woo/Wix) |41| `published_at` | object | 0.701 | Shopify published_at |42| `created_at` | object | 0.701 | Shopify created_at |43| `n_images` | int64 | 1.000 | number of images |44| `tags_list` | object | 1.000 | merchant tags (JSON list) |45| `n_tags` | int64 | 1.000 | number of tags |46| `first_seen_utc` | datetime64[ns, UTC] | 1.000 | first observation (UTC) |47| `last_seen_utc` | datetime64[ns, UTC] | 1.000 | last observation (UTC) |48| `f_published` | bool | 1.000 | active = 1 and listing_status = 'published' |49| `f_live_store` | bool | 1.000 | store enabled with >= 1 published listing |50| `store_kind` | object | 1.000 | standard | revendeur | collectif | hors_mission |51| `f_hors_mission` | bool | 1.000 | store flagged out of mission by the platform |52| `title_norm` | object | 1.000 | ASCII-folded, lower-cased, punctuation-stripped title |53| `dup_group_size` | int64 | 1.000 | number of listings with the same normalised title in the store |54| `f_dup_in_store` | bool | 1.000 | duplicated title within store |55| `f_dup_rep` | bool | 1.000 | representative (first-seen) listing of its (store, title) group |56| `f_sibling_dup` | bool | 1.000 | store is a non-representative mirror domain of another store |57| `f_analysis_assort` | bool | 1.000 | ASSORTMENT SAMPLE membership |58| `store_cad_share` | float64 | 1.000 | share of the store's listings priced in CAD |59| `f_cad` | bool | 1.000 | CAD listing in a CAD store (>= 95 %) |60| `f_price_ok` | bool | 1.000 | 0 < price <= 50 000, not on request |61| `f_analysis_price` | bool | 1.000 | PRICE SAMPLE membership |62| `log_price` | float64 | 0.962 | natural log of price (price sample) |63| `on_sale` | bool | 1.000 | compare_at_price > price |64| `has_variants` | bool | 1.000 | price_max > price or n_variants > 1 |6566## `data/interim/stores_master.parquet` — 1 569 rows × 43 columns6768| column | dtype | non-null | description |69|---|---|---:|---|70| `id` | object | 1.000 | store domain |71| `name` | object | 1.000 | store name |72| `platform` | object | 1.000 | e-commerce platform (connector) |73| `city` | object | 1.000 | city/sector label from the FSA centroid or directory |74| `region_db` | object | 0.779 | Fabri-Ka region (directory / site / FSA map) |75| `region_pip` | object | 0.797 | region containing the FSA centroid (official MERN layer, point-in-polygon) |76| `region_city` | object | 0.250 | |77| `region_pipfirst` | object | 1.000 | |78| `mrc_pip` | object | 0.797 | |79| `region_final` | object | 1.000 | region_db, else region_pip, else 'Inconnue' |80| `region_source` | object | 1.000 | db | pip | unknown |81| `region_final_vs_polygon` | bool | 1.000 | |82| `region_conflict` | bool | 1.000 | region_db ≠ region_pip (both present) |83| `has_geo` | bool | 1.000 | FSA centroid available |84| `lat` | float64 | 0.797 | FSA centroid latitude |85| `lng` | float64 | 0.797 | FSA centroid longitude |86| `postal_prefix` | object | 0.824 | forward sortation area (first 3 characters) |87| `phone_shared` | bool | 1.000 | phone shared by >= 3 stores (directory contamination; never used) |88| `origin_class` | object | 1.000 | store-level origin class A/C/E assigned by the platform from discovery-source priors + site signals (NOT product provenance) |89| `origin_confidence` | float64 | 1.000 | platform confidence in origin_class |90| `origin_evidence` | object | 1.000 | retained textual evidence for origin_class |91| `certified` | bool | 1.000 | store carries >= 1 structured third-party certification |92| `cert_adq` | bool | 1.000 | Aliments du Québec member |93| `cert_lpq` | bool | 1.000 | Les Produits du Québec certified |94| `cert_bio` | bool | 1.000 | CARTV organic |95| `cert_labels` | object | 1.000 | certification labels |96| `store_kind` | object | 1.000 | standard | revendeur | collectif | hors_mission |97| `language` | object | 1.000 | site language |98| `n_sources` | int64 | 1.000 | number of discovery sources |99| `first_source` | object | 1.000 | first discovery source |100| `reg_status` | object | 1.000 | registry verification status (verified/probable) |101| `product_count` | int64 | 1.000 | platform's published count |102| `n_listings` | int64 | 1.000 | assortment-sample listings |103| `n_categories` | float64 | 0.992 | distinct categories in the assortment sample |104| `share_autre` | float64 | 0.992 | share of 'autre' |105| `median_price` | float64 | 0.953 | median listed price (CAD) |106| `share_available` | float64 | 0.985 | share available = 1 |107| `share_on_sale` | float64 | 0.992 | share on sale |108| `main_category` | object | 0.992 | modal category |109| `first_listing_utc` | datetime64[ns, UTC] | 0.992 | earliest first_seen |110| `last_listing_utc` | datetime64[ns, UTC] | 0.992 | latest first_seen |111| `last_sync_utc` | datetime64[ns, UTC] | 1.000 | last sync |112| `fail_streak` | int64 | 1.000 | consecutive failed syncs |113114## `data/interim/sibling_stores.parquet` — 22 rows × 5 columns115116| column | dtype | non-null | description |117|---|---|---:|---|118| `sibling_group` | int64 | 1.000 | mirror-domain group id |119| `id` | object | 1.000 | store domain |120| `sibling_rep` | object | 1.000 | representative store of the group |121| `is_rep` | bool | 1.000 | is the representative |122| `n_titles` | int64 | 1.000 | distinct titles |123124## `data/interim/match_pairs.parquet` — 5 453 rows × 16 columns125126| column | dtype | non-null | description |127|---|---|---:|---|128| `uid_a` | object | 1.000 | listing a |129| `uid_b` | object | 1.000 | listing b |130| `tier` | object | 1.000 | matching tier A/B/C/D |131| `score` | float64 | 1.000 | rapidfuzz score |132| `store_a` | object | 1.000 | |133| `price_a` | float64 | 1.000 | |134| `nv_a` | int64 | 1.000 | |135| `grams_a` | float64 | 0.469 | |136| `cat_a` | object | 1.000 | |137| `store_b` | object | 1.000 | |138| `price_b` | float64 | 1.000 | |139| `nv_b` | int64 | 1.000 | |140| `grams_b` | float64 | 0.484 | |141| `cat_b` | object | 1.000 | |142| `comparable` | bool | 1.000 | variant-structure comparability flag |143| `log_gap` | float64 | 1.000 | |log price a − log price b| |144145## `data/interim/match_groups.parquet` — 4 832 rows × 11 columns146147| column | dtype | non-null | description |148|---|---|---:|---|149| `group_id` | int64 | 1.000 | match group (connected component over tiers A–C) |150| `uid` | object | 1.000 | Fabri-Ka listing id (hash of store + platform product id); stable across syncs |151| `store_id` | object | 1.000 | canonical store domain (merchant identifier) |152| `price` | float64 | 1.000 | listed price = MINIMUM variant price at the snapshot (merchant currency) |153| `category` | object | 1.000 | Fabri-Ka canonical category (20 keys, rule-based inference; audited in reports/phase2_data_audit.md) |154| `nv` | int64 | 1.000 | variant count |155| `grams` | float64 | 0.542 | variant weight in grams (Shopify grams or Woo kg×1000) — first variant |156| `vendor_norm` | object | 1.000 | normalised brand |157| `n` | int64 | 1.000 | group size |158| `n_stores` | int64 | 1.000 | stores in group |159| `n_cat` | int64 | 1.000 | categories in group |160161## `data/interim/sync_log.parquet` — 577 773 rows × 8 columns162163| column | dtype | non-null | description |164|---|---|---:|---|165| `ts` | float64 | 1.000 | epoch |166| `store_id` | object | 1.000 | canonical store domain (merchant identifier) |167| `found` | int64 | 1.000 | listings found in the sync |168| `added` | int64 | 1.000 | added |169| `updated` | int64 | 1.000 | updated |170| `removed` | int64 | 1.000 | removed |171| `status` | object | 1.000 | ok | error | presumed_closed |172| `ts_utc` | datetime64[ns, UTC] | 1.000 | UTC time |173