logicsrc/docs/openvehicle.md
Anthony Ettinger 7aeba32908 OpenListing 0.1: one file a seller serves about a thing on offer
A house for sale, an apartment to rent, a car. One document per listing,
on the seller's own origin, so a directory reads the seller's file
instead of licensing somebody else's database or scraping a marketplace
that forbids it.

**The name `OpenRental` was the obvious one and it is taken.** It
already means renting OpenAgent and OpenSwarm members through CoinPay,
with a published schema, SDK, validators and fixtures. Its own document
records surviving one collision already: it was OpenFleet until
2026-09-13. Reusing the name for housing would have broken a shipped
0.1 spec, so the family is OpenListing instead.

Two axes rather than a spec per combination. A house for sale and a
house to rent are the same house; only the offer differs. A house for
sale and a car for sale are the same offer; only the subject differs.
Writing OpenHouseForSale, OpenHouseForRent, OpenCarForSale and the rest
produces one spec per cell of a grid, each repeating most of the others.
So `offer.type` carries sale/rent/lease/auction/free/wanted and
`subject.type` carries property/vehicle, and a subject profile adds only
the fields peculiar to its subject. A reader that knows OpenListing but
not a profile still reads price, location, offer and dates correctly.

`openhouse` is not used as a name: in real estate an open house is a
viewing event, not a kind of listing. An actual one is an entry in
`showings`.

The problem section is grounded rather than asserted: RESO tracks 484
separate MLSs as of August 2026, down from nearly twice that in 2015;
each does publish a RESO Web API feed, and each requires a real estate
licence, a signed per-MLS data agreement and vendor credentials. Four
hundred and eighty-four negotiations for one national view, not
redistributable. Vehicle parts are the same shape with different
letters (ACES/VCdb, TecDoc).

Decisions worth naming. Prices are decimal STRINGS, because 2450.10 is
not representable in binary floating point and a listing is a price.
Absent means unstated, never zero -- with `bedrooms: 0` called out in
the property profile as the one place where zero genuinely differs and a
studio is not an unstated bedroom count. `location.precision` lets a
seller publish a postal code rather than a street for an occupied home,
and forbids a reader from drawing a pin on a building anyway. A closed
listing SHOULD stay served for 90 days with `closed_at`, because a
directory that learns from a 404 cannot tell "sold" from "outage" --
the failure that makes every coupon site a graveyard.

The vehicle profile treats a VIN as a claim rather than a proof, points
readers at NHTSA vPIC (free, keyless, public domain) for decoding rather
than making sellers restate what the VIN encodes, and puts parts fitment
explicitly out of scope: that is ACES/VCdb or TecDoc, and a public spec
cannot restate licensed data.

Registered as one parent and two blocks under it, using the registry's
existing `parent` field the way OpenServer's blocks already do. Flat
slugs rather than nested paths because /docs/[slug] is a single dynamic
segment, not a catch-all -- a nested slug would not have routed at all.

nichedb.dev is named as the reference directory.

50 contract tests pass including spec-discovery and page-metadata.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-25 10:10:21 +00:00

4.3 KiB

OpenVehicle

The vehicle profile of OpenListing. It adds one key, subject.vehicle, describing a car, motorcycle, truck, trailer or boat. Everything else — the offer, the price, the location, the media, the provenance — is the parent specification and is not restated here.

Status: 0.1 draft, alongside the parent.

Slug: openvehicle

When this profile applies

When subject.type is "vehicle".

subject.vehicle

"subject": {
  "type": "vehicle",
  "title": "2021 Jeep Grand Cherokee Overland",
  "vehicle": {
    "kind": "car",
    "year": 2021,
    "make": "Jeep",
    "model": "Grand Cherokee",
    "trim": "Overland",
    "body": "suv",
    "vin": "1C4RJFCG1MC622398",
    "odometer": { "value": 48210, "unit": "mi" },
    "fuel": "gasoline",
    "transmission": "automatic",
    "drive": "4wd",
    "engine": { "displacement_l": 3.6, "cylinders": 6 },
    "exterior_color": "Diamond Black",
    "doors": 4,
    "seats": 5,
    "title_status": "clean",
    "owners": 2
  }
}

kind

car, motorcycle, truck, van, bus, trailer, rv, boat, atv, equipment, other.

Fields

Field Notes
year, make, model, trim As the manufacturer names them, not as a marketplace's dropdown does.
body sedan, suv, coupe, hatchback, wagon, pickup, convertible, minivan.
vin See below.
odometer value + unit (mi, km). A unit is required: fifty thousand of one is not fifty thousand of the other, and a bare number is the commonest way vehicle data goes wrong.
fuel gasoline, diesel, hybrid, phev, electric, lpg, hydrogen.
transmission manual, automatic, cvt, dct.
drive fwd, rwd, awd, 4wd.
engine displacement_l, cylinders, power_kw.
battery For electric and plug-in hybrid: capacity_kwh, range, range_unit.
title_status clean, salvage, rebuilt, lemon, flood, export, unknown.
owners Previous keepers, as an integer.
service_history full, partial, none.
mot_expires / inspection_expires ISO date, where the jurisdiction has one.
features Free-text list.

All optional. Absent means unstated.

The VIN, and what a publisher should think about first

A VIN identifies one specific vehicle for its whole life. Publishing it is normal and useful — it is how a buyer checks the history, and how a reader can resolve the year, make, model and trim independently rather than trusting the listing's own prose.

It is also a durable identifier that ties this listing to every other record about that vehicle, including ones the seller did not intend to connect. A private seller MAY omit it; a dealer usually publishes it. A publisher that omits it SHOULD still give year, make and model.

A reader MUST NOT treat a VIN as proof of anything. It is a claim by the seller like every other field, and a mistyped VIN describes a different car entirely. Readers that verify SHOULD check the ninth-position check digit before relying on one.

Decoding, and what is free

A reader can resolve a VIN to year, make, model, body, engine and plant using NHTSA's vPIC API, which is free, keyless and public domain. That is the intended way to enrich a listing that carries a VIN, and it is why the profile does not require the seller to repeat what the VIN already encodes.

Recalls against a vehicle are likewise free and keyless from NHTSA, per year/make/model. A listing MUST NOT claim recall status — the seller does not know whether a given VIN's recalls were performed, and only the manufacturer's own lookup does.

Fitment and parts are out of scope, and deliberately so. Which parts fit a vehicle is ACES/VCdb from the Auto Care Association or TecDoc in Europe, both subscription; a public specification cannot restate licensed data. A listing describes a vehicle, not what fits it.

What this profile does not do

  • No valuation or book price. The listing says the asking price.
  • No history report. Whether a car was in a crash is a claim from a provider, with a source; OpenOntology is where that belongs.
  • No condition grading. Marketplace grading scales are proprietary and mutually unintelligible. Condition is description text.
  • No parts compatibility. See above.