# BidBrain project status, part 22: Current: Dealer OS shortlist car page and after (September 2026)

Started 2026-09-22 when docs/status-21 passed 60 KB. The standing rules stay in CLAUDE.md, which lists every part of this log. New entries go at the top of this file.

---

- 2026-10-05 (v3.14.154): a MotorCheck history check on the wrong car. Steven, on S77RUU (Motorway): the seller's private plate; Motorway's sellingVrm says the car sells on PF17VYL. Dealer OS's automatic check ran on S77RUU on 3 Oct after the plate had moved, and MotorCheck described a 2025 Mercedes CLA 220, not our 2017 Mercedes A 200 D, flagging that car's finance. Nothing compared the report with the car, and Dealer OS told the Mac about the PDF on 5 Oct, so it was lined up for DealerKit with the car's documents (not sent, the car was not on DealerKit yet). The checks run in Dealer OS (src/lib/motorcheck); the Dealer OS fix checks the plate that stays with the car and compares every report's description (make, model, year) with the car, never announcing a wrong car report and taking back one already announced with a purchase.document carrying withdraw: true. BidBrain's part: apply_document_action sends withdraw to withdraw_document, which drops the file from dealer_os_documents and disk (db.remove_dealer_os_document) and logs it on the car; a car whose documents already went to DealerKit gets a timeline note to remove it there by hand. Touches Mark too, harmlessly: his Mac only gets a withdraw if Dealer OS ran a wrong car check for him.

- 2026-10-05 (v3.14.153): PL66ZZO's lost chip put back. Steven: "i need a record of the chip". An audit of all 71 Motorway "Payment confirmation" emails since 1 August against the live purchase rows found 38 right, 32 that lost a chip the same way (winning bid equal to Motorway's final price, no chip, money correct) and none chipped twice. Steven chose to put right PL66ZZO only (decision card, 16:51 UTC). New `_MOTORWAY_AMENDMENTS_2026_10_05` (Motorway vehicle id, won, amendment, payment date) and `_restore_motorway_amendments`, run from `_migrate` on every start: only while the bid still reads the amended price, it restores the bid and adds a chip "Price amended on Motorway" dated the payment day, who BidBrain, plus a timeline event; an existing chip of the same amount stays and only the bid is restored; any other chip leaves the car alone; a car already on DealerKit is stamped dk_chip_pushed_at so nothing is written there. car_price and all in do not move. The other 31 cars are listed in the project's memory note motorway-price-amendment-lost-chips if Steven ever wants them. 3 new checks (1,845 passing). Touches Mark: no, the vehicle id only exists on Steven's Mac; no setting, no default, no scheduled job, no platform action.

- 2026-10-05 (v3.14.152): a chip put through Motorway was lost. Steven, on PL66ZZO: won at £6,456 (Motorway's "Purchase confirmed" email), chipped £200 through Motorway at collection, and Purchases showed £6,256 as the winning bid with no chip, so Donna adding the £200 would have taken it off twice. Checked live, read only (every non GET request blocked after sign in): the purchase summary page still says "Estimated breakdown" after payment and shows only "Vehicle price £6,256", no amendment line; only the payment confirmation email lists "Vehicle winning bid", "Vehicle price amendment" and "Vehicle final price". An estimated breakdown is replaced wholesale on every read (2026-08-21), so the lower figure overwrote the bid. `record_purchases` now keeps the existing `winning_bid` when a re read breakdown's bid drops by more than £1.01 and inserts a chip for the drop (reason "Price amended on <platform>", who BidBrain, bid_before the bid as won) plus a chip timeline event, in the same connection. The chip then locks the payment block through the 2026-08-27 double count guard, and Dealer OS's CollectGate already shows a chip on file and asks for a tick before the same amount is entered twice. A rise is still taken as read. PL66ZZO itself is not healed: the £6,456 was overwritten before this fix, its net £6,256 and all in £6,650.80 are right. 6 new checks (1,842 passing). Touches Mark: yes, his Motorway and Carwow purchases are read the same way; no setting, no default, no scheduled job, no platform action.

- 2026-10-04 (v3.14.151): Carwow cars seen twice today. Steven, on LC66AZW in Dealer OS's Seen tab: a Today row for the car on sale and a second "Today" row, "reserve not read, Sun 4 Oct, first seen". Checked live, read only, through Dealer OS: the list was for 2026-10-05 and 54 of its 80 Carwow cars carried a Carwow sighting dated 2026-10-04, against 2 to 7 on any other day; Motorway had 3, all with a different reserve. Carwow sells Monday to Saturday (its dealer help pages), so sale_day_for's next calendar day after Saturday's 15:30 close stamped Saturday evening's read of Monday's lots as Sunday, and Sunday's run then saw the same lots as a Sunday sale gone by. The weekend before shows the same pairs (09-27 and 09-28). Motorway sells every day, which the 3 changed reserves bear out. New `db.NO_SUNDAY_SALE` ("Carwow") and pure `db.platform_sale_day`; `record_sightings` files a Carwow Sunday under the Monday, and `_move_sunday_sightings` (run from `_migrate` on every start) refiles old Carwow Sunday rows onto Monday, merging into a Monday twin and keeping any reserve or CAP clean only the Sunday row had. The queries need no change: everything compares sale dates with `<`, so a Carwow lot filed under Monday never shows as earlier than a Saturday evening list for Sunday. The list wide sale date is unchanged, Motorway needs it. Also fixed the date bound "old sales are pruned" check, red since 1 October because its rows are dated 2026-09-17. 7 new checks, 1,835 passing. Touches Mark: yes, his Carwow sightings move the same way; no setting, no default, no scheduled job, no platform action.

- 2026-09-29 (v3.14.150): seller notes from Carwow and Motorway. Steven, on FY16BHD (Carwow): the seller wrote "Clutch pedal squeaks, rattle coming from the airbag area" and nothing in BidBrain said so. `car.notes` (shown as the "Seller notes:" flag, which Dealer OS already draws as its Seller notes section) was only ever filled by Auction4Cars and DealerWay. Checked live, read only. Carwow: `div.listing__seller-notes-text` holds one `p.preserve-newline` starting "Seller notes: " with the seller's line breaks, clipped on screen behind View more, so it is read from the markup; new pure `carwow.seller_notes_from_html` (each line ends in a full stop), called in `enrich_from_detail`, which now always takes `page.content()`. Motorway: `conditionAndDamage.additionalDetails` is the ticked extras on one line ("Rips, Tears or Burns, Parcel shelf included"), then free text after a blank line; "OP: <plate>" lines are the original plate; `relistDetails` is `{name, info}` ("Seller Readiness", why it came back). New pure `motorway.seller_notes`, called in `gate_details`: "Seller ticked: ..." without the parcel shelf, each free paragraph, then "Relisted, name: info". Proven on three live Carwow and three live Motorway cars. Dealer OS in the same pass (#1405): the amber mark covers fault words, and the closed fold shows the first worrying note. Cars already on the shortlist get their notes on the next run. 4 new checks (1,829 passing). Touches Mark: yes, same readers on his copy; no setting, no default, no scheduled job, no platform action.

- 2026-09-29 (v3.14.149): Carwow cars showed a distance and no town. Steven, on SA18AJX in Dealer OS's Location and Delivery panel ("186 miles", "372 miles round trip", no place). Dealer OS shows `location` and `distance_miles` as pushed; for Carwow `location` was always empty because the list card only prints "N miles away" and `enrich_from_detail` never read the town. Checked live (read only, every non GET request blocked after sign in): the car's own page has a Location section, "Location", "Location", "Elton, Bury (134 m)", "Exact location provided after sale is confirmed", "Estimated delivery". New pure `carwow.location_from_lines` takes the first place shaped line with the miles in brackets within three lines of a "Location" line, so the tab strip's own "Location" word never reads as a town; `enrich_from_detail` fills `car.location` from it when empty. Side effect worth knowing: `pricing.ferry_crossing` now has a place to check on Carwow cars. `allowed_locations` is per platform and not set for Carwow, so nothing new is enforced there. The cockpit's location filter scope is unchanged (Carwow cars off the shortlist never get a page visit, so most still have no town). DealerWay's list card is the same shape (distance only) and was not checked in this pass. Same pass, Steven on the same car: the Owners panel listed only the current owner. Checked live (read only): Motorway's `details.previousOwners.keepers` already gives every start date and `from_motorway` already reads them (proven on four live cars); Carwow's page has an "Ownership history" section ("Current owner", "06 Jan 2020 \u2013 Present", "6 years and 8 months", "2nd owner", ...) that `from_carwow` never read, taking only "Start of current keeper". New pure `deep_read.carwow_keepers` reads it oldest first; the old single keeper stays as the fallback. Dealer OS's `ownerLines` also now lists earlier owners as "Dates not given" when the deep read has fewer owners than the count, which covers cars read before this. 6 new checks in test_pricing.py (1,825 passing). Touches Mark: yes, same Carwow reader on his copy; no setting, no default, no scheduled job, no platform action.

- 2026-09-28 (v3.14.148): S30NNT on Carwow read as never seen. Steven was sure he had seen it before. Checked the live list through Dealer OS (read only): the car's `reg` was empty, its `selling_vrm` S30NNT came off its own page's plate transfer field, and it carried `is_new: true` and no sightings. `db.record_sightings` skips a car with no listing plate, and the list read runs before the detail pages, so a car Carwow shows without a readable plate was never logged on any day, and `repeat_summary` of an empty reg returned no history, which `daily_run` read as new. Six Carwow cars on the 28 September list had no listing plate, five with an original plate. The fix: `record_sightings` files a plate less car under `selling_vrm`, and `_read_carwow` logs those cars again once their pages are read (INSERT OR IGNORE keeps it one row a day). New `db.sighting_plates(reg)` takes one plate or several and adds the other half of any `plate_pairs` row; `repeat_summary`, `sighting_history` and `reserve_history` all look up by it, and every caller passes `daily_run._car_plates(car)` (listing plate, then original plate). `repeat_summary` now also returns `known`, false when there is no plate at all, and `_is_new` needs it, so a plate less car is never called new or given the Top picks boost for it. If S30NNT had no listing plate on its earlier days too, those days were never logged and its card only starts counting from today; if its private plate was read on any of them, the plate pair now joins them up. 8 new checks in test_pricing.py (1,819 passing). Touches Mark: yes, same tracker on his copy; no setting, no default, no scheduled job, no platform action.

- 2026-09-25 (v3.14.147): Steven ran the deep read on all 8 shortlist cars and still saw "Not read yet". Checked against the live pages (read only). Two causes. Carwow MOT: from_carwow looked for "MOT expiry" and "MOT result", labels Carwow never prints, so both Carwow cars (PH58EEE, BL18YCN) had no MOT at all. Carwow lays it out as "Latest MOT", date, result, then "Expiry Date" and "N advisories" followed by those lines; carwow_mot reads that, with the "Last MOT" strip at the top as a fallback. Wheels and tyres: Motorway gives no tread depths, only the wheelsAndTyres Yes/No block that already became tyre_notes, and Dealer OS threw tyre_notes away (its toDeepRead only kept tyres_mm), so all 8 cars read unread; that half is fixed in Dealer OS. Carwow's "Wheels & Extras" panel is now read into tyre_notes too (carwow_wheels), and a clear block on either platform now says "No problems declared" (NO_WHEEL_PROBLEMS) so clear is never mistaken for unread. "No information" on Carwow is not a no.

- 2026-09-22 (v3.14.146): a freshly won Motorway car's purchase price was about £400 too cheap. Steven: "the purchase price of BC17OXN has came over into DOS totally incorrect". Dealer OS showed £7,636 on a car he bid £8,066 for, and an all in of £8,066.80 rather than £8,496.80. Nothing wrong on the Dealer OS side: it draws `car_price` straight from the push, and the Mac had worked that figure out wrong. `db.provisional_motorway_bid` treated Motorway's purchases list figure as the all in total on every car and derived the bid by taking off the banded fee and its VAT. Motorway shows two different figures there: while a car is still going through (Awaiting confirmation, Reviewing documents) there is no payment breakdown and no fee worked out, so the list shows the bid itself; once the checks are complete the fee and VAT are added and the list shows the total. The derivation was proven in September on eight *confirmed* purchases, which is why it looked right, and a car heals itself as soon as the breakdown page appears, which is why it was never caught. Proven by reading Motorway's own "Your bid" sale recap emails for every car bought 10 to 21 September against the stored rows: every car with `total_price` on file matched to the pound, and every car without it was short by exactly its own fee plus VAT. The fix: a new `db.motorway_fee_in_list_price(status)` (true from Checks complete onwards, and an unread or blank status counts as still going through, so nothing is taken off a figure we cannot vouch for), `provisional_motorway_bid` takes the status and only derives when the fee is genuinely in the figure, `purchases_run.estimated_fee` passes it through so the banded fee is worked out on the real bid, and `list_purchases` builds `all_in` up from `car_price` plus the fees on a car still going through instead of using the list figure as the total. Seven live cars were wrong (PX68YBB, SB66LFP, HN17AOG, CU67OCO, BC17OXN, YF17YVJ, KP67DSX, none chipped, none pushed to DealerKit yet); they correct themselves on the next purchases run because a payment block still marked estimated is replaced wholesale on every read, proven on a throwaway database. 10 new checks in test_pricing.py (1,797 passing). Touches Mark: yes, this is Motorway's own behaviour and his copy reads the same cars the same way; no setting, no default, no scheduled job, no platform action.

- 2026-09-22 (v3.14.145): modifications on the shortlist car card. Steven, on the new one at a time car page in Dealer OS v4.5.22 (built to his signed off prototype, which listed nine facts plus Modifications), asked why Modifications was not on the card. The answer was that the Mac never read it: `deep_read.FIELDS` had no such field, so `from_motorway` and `from_carwow` never looked, and Dealer OS had nothing to show. He said yes to adding it. New contract field `modifications` (a string or null) on the deep block, between `warning_lights` and `history_check`; `empty()` and `_clean` carry it like the rest. The words are made in one pure helper, `modifications_text(flag, desc)`: a description as written, joined to one line; a No with nothing said is "None declared"; a Yes with nothing said is "Modified, the seller gave no details"; neither on the page is None (golden rule 4, a page that did not say is not a page that said no). Motorway: `motorway_modifications(data, lines)` tries the names Motorway would plausibly use (`hasModifications`, `hasBeenModified`, `isModified`, `hasModifiedParts`, `vehicleModified` for the flag; `modificationsDesc`, `modificationDesc`, `modificationsDescription`, `modificationDetails`, `modificationsDetails`, `modificationsText` for the words; a plain `modifications` key as a string, a list, a bool or a small dict), then the page's own words ("Modifications" / "Modified" / "Has the car been modified" as a label line). The real name has NOT been seen live, there was no logged in browser in the hosted session, so `motorway_key_notes` now also writes every path with "modif" in it to data/logs/deep_read.log on the first read of a run; the next session should read that log off the Mac before assuming anything. Carwow: the "Modifications" label line through the same helper, nothing else changed. DealerWay and Auction4Cars give null. 3 new checks in test_pricing.py (1,781 passing). Dealer OS side in the same pass (v4.5.26): `modifications` added to the deep read schema, type and mapping, `carFacts` puts it after Keys and before Paperwork as Steven's prototype ordered, "Not read yet" until the Mac has read the car, and the contract document names it as additive, schema still 1. Touches Mark: yes, his Mac reads the same line on the cars he stars; no setting, no default, no scheduled job, no platform action.
