Skip to content

feat: device identity fields + device_catalog category (no-fabrication import support) - #121

Merged
Seungpyo1007 merged 1 commit into
mainfrom
feat/device-ids-catalog
Oct 6, 2026
Merged

Seungpyo1007 merged 1 commit into
mainfrom
feat/device-ids-catalog

Conversation

@Seungpyo1007

Copy link
Copy Markdown
Member

What / why

TechAPI is about to import Google Play's public supported_devices.csv (brand, marketing name, codename, model number) and a Play Console device-catalog export (RAM, form factor, SoC, GPU, screen, SDK levels). Neither source has battery, weight, brand country, or a reliable launch date. Play's min SDK only gives an upper bound on the launch year. This PR changes the engine so those records can be stored without filling the gaps with guesses.

No-fabrication rule: if a source does not state a value, it stays null (or [] for lists). Nothing is estimated to satisfy a required field.

Changes

Identity fields on smartphone / tablet / watch / pda

  • model_numbers: list[str] (default []), e.g. SM-S938N
  • codenames: list[str] (default []), e.g. pa3q
  • release_date_precision: str | None, one of day | month | year | year_estimated (null = unspecified, which covers all existing records)

These are stored, seeded, serialized in SmartphoneRead / MobileDeviceRead, and dumped.

Relaxed required fields

  • smartphone: battery_mah and weight_g are no longer in PHONE_REQUIRED. null is allowed, and the range checks still run when a value is present. The model and schema are nullable now. If capacity is unknown, the battery sub-score is null (it used to crash).
  • brand: country is optional. A brand without a country lives under brand/unknown/<slug>.json, and the folder is enforced. When a country is present, the ISO alpha-2 check and the folder match still apply.

New category device_catalog (unscored, identity-only)

  • Data: data/device_catalog/<brand>/<slug>.json. There is no year folder, because the release date is unknown by definition. The path check exists for this category only.
  • API: GET /v1/device-catalog (filters: brand, form_factor, base_model_slug; sort: name, android_sdk_min) and GET /v1/device-catalog/{slug}. Dumped as collection device-catalog. A SoC change also re-dumps it, since entries embed a SoC summary.
  • Required: slug, name, brand (FK), source_urls, verified
  • Optional:
    • base_model_slug, model_numbers, codenames, marketing_names
    • form_factor: only when a source states it
    • device_type_guess: explicitly a heuristic guess, same vocabulary as form_factor (phone|tablet|watch|tv|other)
    • Play Console specs: ram_gb, soc (FK slug, null if unresolved), soc_raw, gpu_raw, screen_resolution ("1080x2400"), screen_density_dpi, android_sdk_min, android_sdk_max
    • release_year together with release_year_source (model_code | record): both or neither
    • promoted_to: "<smartphone|tablet|watch|pda>/<slug>"
  • Validation:
    • lists contain unique, non-empty strings
    • form_factor and device_type_guess use the enums above
    • integer fields must be ints within their ranges
    • android_sdk_max >= android_sdk_min
    • screen_resolution must match the WxH format
    • soc and brand must point to existing records
    • promoted_to must be well-formed
    • brand folder and filename must match the record

Registry

CATEGORIES now has 13 entries. The N/N categories scope strings in dump_check and integrity_check now count CATEGORIES instead of hardcoding 12.

Validation results (local, against TechAPI develop data)

  • ruff check app tests: pass
  • mypy app: pass (115 files)
  • python -m app.validate: pass
  • pytest --cov=app --cov-fail-under=60: all tests pass, 78.1% coverage
  • New tests:
    • tests/unit/test_validate_identity.py: field rules, catalog path/required/enum/range rules, brand with country null or omitted
    • tests/integration/test_device_catalog.py: endpoints, plus a self-contained validate → seed → API → dump round trip covering a country-less brand, a phone with null battery/weight, a tablet with identity fields, and catalog entries with and without a SoC
  • The OpenAPI contract test now expects nullable battery_mah / weight_g on SmartphoneRead.

Follow-ups (outside this PR)

  • TechAPI's own app/validate.py mirror needs the same relaxations and the new rules. A ready diff is prepared separately for the TechAPI side.
  • The verify layer sees device_catalog as a category with no domain rules, so those entries are never scored green (domain_rules_unavailable).

… battery/weight and brand country

Prepares the engine for the Google Play supported-devices / device-catalog
import without inventing values: anything a source does not state stays null.

- smartphone, tablet, watch, pda: optional model_numbers, codenames
  (lists of unique non-empty strings) and release_date_precision
  (day|month|year|year_estimated, null = unspecified), stored, seeded,
  serialized and dumped.
- smartphone: battery_mah and weight_g are no longer required (null allowed,
  range checks kept when present); the battery score is null when the
  capacity is unknown.
- brand: country is optional; a brand without one lives under brand/unknown/.
- new unscored category device_catalog (data/device_catalog/<brand>/<slug>.json,
  no year folder), served at /v1/device-catalog: identity fields, optional
  Play Console specs (ram_gb, soc FK, soc_raw, gpu_raw, screen_resolution,
  screen_density_dpi, android_sdk_min/max), release_year only together with
  release_year_source, form_factor vs device_type_guess, promoted_to.
- category registry is now 13 entries; scope strings derive the count.
@Seungpyo1007 Seungpyo1007 added the enhancement New feature or request label Oct 6, 2026
@Seungpyo1007
Seungpyo1007 merged commit c276c2e into main Oct 6, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants