Commit Graph
2 Commits
Author SHA1 Message Date
ckochandClaude Opus 5 d5a0e42fed Add collector fields, including market value
Rating, notes, condition, region, purchase price and date, plus a market
value carrying the timestamp and source that make it interpretable.

Condition is load-bearing rather than cosmetic: price feeds quote per
condition, so it selects which quoted price applies to a copy. Market value
records when it was captured and where it came from — a collection total is
only as good as its staleness — and an edit to an unrelated field leaves
that timestamp alone, so a stale price cannot start looking freshly checked.

Two storage decisions worth naming:

  * Money is stored as integer minor units. SQLite has no decimal type and
    EF Core maps decimal to TEXT, which compares lexically: "9.00" sorts
    above "10.00" and SUM is unavailable. A value converter keeps decimals
    in C# while ordering and totalling work. A test pins the ordering.
  * Enums serialise as names. The default is ordinals, which meant the API
    rejected the browser's {"condition":"Cib"} with a 400 while the C# tests
    passed, because they round-tripped ints and never spoke the client's
    dialect. The tests now share the API's serializer options.

Also fixes a data-loss bug in the Python tools. Both built their PUT body
from a hardcoded list of field names, so any column added to the model was
omitted and therefore nulled. Adding collector fields meant the next art or
enrichment run would have erased every rating, note, condition, price and
valuation in the library. Payloads are now built by excluding the handful of
server-owned fields, so new columns carry through by default.

The migration was rehearsed against a copy of the live database before being
applied: 105 rows, descriptions and developers intact.

67 backend tests, 8 frontend.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 13:29:48 -04:00
ckochandClaude Opus 5 771b34bb4b Fill developer, publisher, year and description from Wikipedia
The library carried titles, systems and genres but almost nothing else:
developer was 3.8% filled, publisher 2.9%, description 0%. These are columns
the app has always had and never been able to populate.

enrich_metadata.py reads them off the same articles the cover fetcher
locates. Only empty fields are touched unless --overwrite is given.

  year         79%  -> 96%
  developer   3.8%  -> 95%
  publisher   2.9%  -> 96%
  description   0%  -> 96%

Parsing infoboxes needed several guards, each found by checking output
rather than trusting the first pass:

  * "Infobox video game" is a substring of "Infobox video game series", so
    the loose test resolved Banjo-Kazooie to the series overview. Now
    rejected, which also fixes the cover fetcher's article resolution.
  * An article spans every release and its date block leads with the
    original, so year is only filled when the article covers that platform.
    Otherwise a DS port inherits the SNES original's year.
  * A search hit that neither covers the platform nor closely matches the
    title is discarded: "Dragon Ball Z Budokai" surfaces "Shin Budokai", a
    different game on a different console. Left blank instead.
  * Values are grouped under bold platform headings, tagged with region
    codes, annotated with the platform in parentheses, and wrapped in
    templates whose named parameters leak through. Each of those read as
    the developer or publisher before being handled.

Developer, publisher and year are facts and written verbatim. Descriptions
are article summaries under CC BY-SA, stored with an attribution line.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 12:34:55 -04:00