CLCTN · TYPE SYSTEM · SUBTYPES · OCTOBER 2026
PROPOSAL
ABSORBS MEDIARULES
A Saturn game is a video game, plus three things.
Each platform has details only its collectors care about. A Saturn game has a spine card. A Neo Geo game is either AES or MVS. An N64 game might need the Expansion Pak. Building a type per platform would split one shelf into forty. Leaving it all in one type means fields that are empty for 95% of items. A subtype inherits the whole type and adds a few fields of its own. That's all a subtype can do.
00 · ONE LEVEL ABOVE · FIELDS EVERY TYPE INHERITS
Some facts apply to any collectible: who signed it, what's inside it. Type → subtype has a parent too: the item. Its fields come for free on wine, vinyl, pins and games. They stay hidden until the item has a value for them, and each one is added with “+ Add” on the item screen. The first case comes from the import (49): a Turtles cart signed by JDG.
ITEM.YML · INHERITED BY EVERY TYPE
fields:
- title | acquired | price | place | story
- key: signed | Signed | object
by: text # "JDG", "Château Musar"
dedication: text? # "pour Max"
date: date?
proof: photo? # photo of the signature,
# certificate, event ticket
- key: contains | Bundle of | list<work>
# empty = a single thing
# 2+ = a bundle: Doom + Doom 2, a 6-bottle
# case, a vinyl box set, a pin set
sealed: bool # still in the bundle?
WHY AN OBJECT, NOT A BOOL
“Signed” alone doesn't say much. Who signed it is what collectors talk about and what buyers ask. A dedication to a named person lowers resale value, while proof raises it. A plain yes/no would throw both away.
What it drives: a “Signed” badge on the shelf tile, a one-of-a-kind entry in the log, and a filter (“everything signed by JDG”). Signed items are never treated as duplicates.
Bundles are also a list, not an is_bundle flag. “Doom + Doom 2” is one object on the shelf but two works. Series sets and “also exists on” (47) must count both, or the Doom tracker misses one. A flag would say “bundle” without saying of what. The bundle is a derived value: contains.length > 1. It renders with the existing case signature, so no new UI is needed.
The rule for this level: a field goes here only if it means the same thing for every type. Signed passes the test. Condition doesn't, because grading a wine and grading a cart are different scales.
01 · THE RULE
The thesis still holds: the app owns the verbs, the type owns the nouns, and a subtype can only add nouns. Item screen, signatures and slots don't change. A subtype is a short list of extra fields and a few presets.
02 · SAME TYPE, DIFFERENT SUBTYPES
Pick a subtype. Grey fields come from the parent type and are identical everywhere. Coloured ones are what the subtype adds. Storage and care are where platforms differ most: a Game Boy cart and a Saturn disc age in completely different ways.
{{ cur.path }}
{{ cur.count }}
FIELDS
ADDED BY {{ cur.name }}
{{ a.l }}
{{ a.k }} · {{ a.kind }}
{{ a.why }}
PRESETS · VALUES THE SUBTYPE FILLS IN OR NARROWS
STORAGE
{{ cur.store }}
CARE · CLOCKS FROM THE LIBRARY
03 · WHAT IT REPLACES
43 used a mediaRules table so that one field could change the clock, lookup and parts. That was already a subtype, just keyed on media instead of platform. Platform is the better key, because it implies the media in nearly every case and collectors already shelve by platform.
VIDEO-GAME.YML · AFTER
type: video-game
fields: [title, platform, region, edition,
condition, saveBattery, playStatus, …]
subtypes:
- key: saturn
label: Sega Saturn
presets:
media: disc
region: [NTSC-J, NTSC-U, PAL]
parts: [case, manual, disc, spineCard]
adds:
- spineCard | Spine card | bool
- ramCart | Needs RAM cart | enum [1MB, 4MB]
- satakore | Satakore ID | text
04 · WHY IT HELPS THE STAGED LAUNCH
You said you'd rather ship a few types that are well tested. Subtypes let that happen at a finer grain.
{{ s.k }}
{{ s.t }}
{{ s.b }}
05 · OPEN QUESTIONS