mirror of
https://github.com/profullstack/logicsrc.git
synced 2026-10-01 20:33:50 +00:00
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>
87 lines
4.3 KiB
Markdown
87 lines
4.3 KiB
Markdown
# OpenVehicle
|
|
|
|
The vehicle profile of [OpenListing](/docs/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`
|
|
|
|
```json
|
|
"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](/docs/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.
|