Skip to main content

Ground truth: feature records

Applies to every fixture directory under packages/ai_dealer_connect/tests/data/code_guides/parser/fixtures/.

CodeGuideFeatureRecord is derived, not transcribed — one record can draw on six different tables. Hand-transcribing all of them is not possible (the RAM 2500 guide yields roughly 20,000 records), so the fixtures split the problem into parts that are each fully checkable:

layerfixturewhat it pins
annotation grammarannotation_corpus.json + expected_rules.jsonevery distinct annotation block a guide contains → its OptionRules. Derived twice, independently, from rule-grammar.md; both reviewers agreed with each other before the parser was run against it.
cell recoveryexpected_grid_p*.jsonone whole STEP #3 page transcribed from the rendered image — every code, price, cell value and P mark
the rubricprojects/ai_stellantis/tests/code_guides/test_extract.py (synthetic)each is_configurable branch, on hand-written primitives, with no PDF in the loop
the joinexpected_features_spotcheck.jsonspecific finished records, each chosen to pin one rubric branch and each traced to a page in its source field
driftmanifest.jsonfeature_countsthe counters, re-derived from the pages after the original figures turned out to have been taken from parser output. A counter the pages do not settle is omitted rather than guessed, so it is simply not asserted. See fixture-verification.md.

expected_features.json — the complete record set

Every fixture now carries the whole record set of its guide rather than a sample: 73,641 records across the ten, with expected_features_provenance.json naming the printed structure and page behind each one. test_parses_every_expected_feature compares the parser's output against it in full — no subset, no count-only check. That is what closed the hole the table above was built around: while only a few dozen records per guide were asserted, the totals were free to drift 10% unnoticed.

Completeness here is derived, and the layers above are what make it checkable. Nobody typed 73,641 records off a page. What was read by eye is the rule behind each class of record — on the pages the judgment calls below cite — plus the grid pages transcribed cell by cell. Each record's provenance entry names the structure and page it came from, so any disagreement can be taken back to the page that claims it.

Provenance strength is not uniform, and the file does not mark which is which. The 1,091 records added 2026-08-21 across the four RAM guides carry citations that were located programmatically: GROUP DETAIL (*) inclusion (784), STEP #3 FLEET ONLY group (214), standalone companion (72), STEP #3 INCLUDED W/ (13), and STEP #2 powertrain (8). The structure named is real and printed and the page is where it sits, but no reader re-read that page to write the line. The classes themselves were established by eye: RAM 2500 p9 for FLEET ONLY contents, p70 for the INCLUDED W/ entry that is not also a column, and RAM 3500 p137 for the (*) fan-out. Each was corroborated by a sibling guide's independent hand read. Read those entries as "the page establishes that this class of record exists here", not as "a person checked this record".

Row identity

One record per (option_code, model_code, model_year, trim_identifier, parent_package_code). parent_package_code is null only where the guide prints the code as a line of its own — a STEP #3 / #4 row, STANDARD EQUIPMENT, a CPP, a powertrain offer. A code named only inside a package's contents gets parented records and no standalone one, so a null parent_package_code does not by itself claim the code is orderable alone; is_orderable_standalone carries that, and is False on a row printed only as P.

A code printed both ways gets both records. RAM 2500 279402 prints XBJ at $495 with only_one_of [XBJ, XF1], and again under p169's XBH GROUP DETAIL header with no price and no rules. Containment goes in parent_package_code, a condition on it goes in rules.

The is_configurable rubric

Configurable means the buyer chooses it — not merely that the vehicle has it.

sourceconfigurable when
CPP codes (STEP #2)the trim has more than one CPP; a lone CPP is not a choice
powertrain codes (STEP #2)the trim offers more than one engine / transmission of that kind
PACKAGE CONTENT (STEP #2)never — bundled into the package
STEP #3 gridsthe row prints its own code in some column (orderable). A row that is only ever P is packaged; blank everywhere is not offered and is skipped
STEP #4 color & trimalways, unless every variant that applies to the trim is FLEET ONLY
GROUP DETAIL items, and the STEP #3 "Included in Equipment Groups" listwherever the group is itself configurable for that (model_code, trim) — never fanned out blindly
STANDARD EQUIPMENTnever — fitted, not chosen

When a record exists at all

The table above says when a source marks something configurable. It also decides whether a record is emitted, and the two are not the same question:

  • GROUP DETAIL and "Included in Equipment Groups" items produce a record for every (model_code, trim) pair where the trim has the group — not only where the group is configurable. A trim has the group three ways: its STEP #3 cell prints the group's own code (a buyer's choice), or prints P (packaged — the trim has the content without choosing it), or the group arrives as standard content of that trim's quick order package. is_configurable is True only in the first case.

    The narrower reading — a record only where the group itself is configurable — deletes options the guide prints. RAM 1500 p6 lists ESD 6.2L SUPERCHARGED HEMI V8 SRT ENGINE with bullets BA7, JLW, MZP, NMX, MJC; p2 puts ESD in the SRT column against CPP 29G. ESD is that trim's engine, delivered by the package, so its five items exist on trim G. BA7 MZP NMX MJC MGT MGG JPE CFN appear nowhere else in the guide, so the narrow reading loses eight option codes outright.

    An option still unreachable on a trim has no record there: a blank STEP #3 cell where the group is listed means no record, even if the group is E-marked for the model code.

  • A group's own E mark counts as evidence that it is configurable there. GROUP DETAIL marks each group header with E against the model codes that can order it at extra cost, and that is the guide stating the group is a choice on those codes. Color and seat groups (TX, V9, X3, XN, AL …) are evidenced only that way — they never appear as a STEP #3 orderable row — so requiring an earlier source drops every one of their items. Requiring the E mark is what keeps this from being a blind fan-out: an unmarked model code still gets no record.

  • A STEP #3 / STEP #4 row produces a record only for the trims whose column actually offers it. A blank cell means no record, not a record marked unavailable.

  • STANDARD EQUIPMENT and PACKAGE CONTENT do emit records everywhere they are marked; they are simply never configurable.

  • A paint-type box emits no record of its own. MONOTONE PAINT - APA, LOWER TWO TONE PAINT - APD and their kin are boxed labels that scope the color table printed beneath them — the same structural role as MOPAR OPTIONS and FLEET ONLY. Measured, the box is x 50.6 → 329.2 on every guide in the set, stopping short of the $FWP edge at 356.2: no price cell, no trim cell, nothing to extract. The paint code itself gets its records from STANDARD EQUIPMENT, where it is marked.

    What the box contributes is two implicit rules on every color row in its block: requires_one_of [the box's code], because choosing a color from that table means choosing that paint type; and an only_one_of across the paint-type codes of the section, because only one paint type can be selected. Neither is printed on the color rows; both follow from the block structure.

Which record carries the rules

An annotated row's OptionRules go on the record for the row's own code. The standalone companion of a parented record does not inherit them, and a group's items do not inherit the group's rules — an item carries only the rules printed against the item itself.

Clauses bind the row whose cell they sit in, and only that row's printed codes. They do not fall through to later rows, and they do not rise to the block. On RAM 279402 p10's PRIMARY COLOR table, CERAMIC GREY CLEAR COAT carries M/H ASH; M/H -X9 and HYDRO BLUE PEARL COAT carries M/H ASH. Both rows are blank in the left code column, so each set of clauses attaches to a single code (PDN, PBJ). BRIGHT WHITE CLEAR COAT, DIAMOND BLACK CRYSTAL P/C and the rest carry none.

A paint-type box is a cell of exactly this kind, so the clauses printed inside it — on RAM 279402 p10, M/H A7K OR A7M; N/A W/A7A; N/A W/A7J; N/A W/A7L; N/A W/AL9 — bind the box's own row and do not distribute to the colors beneath it.

Merging: True beats False; the first non-null description and MSRP win; rules union and de-duplicate. Two overrides run last:

  1. codes beginning 5U / 5V are shipping/routing codes and are forced non-configurable;
  2. a code bundled by PACKAGE CONTENT outranks a GROUP DETAIL "configurable" mark — but a real orderable / CPP / color signal still wins.

Judgment calls (deliberate, flag if you disagree)

  1. STEP #3 columns mean different things in different guides. The RAM guide heads them with equipment-group tiers (BASE, A7B, A7C, A7D) that apply to every trim of the model code, so a row is scoped to the model code and availability is aggregated across the tiers. A row is orderable if its own code is printed anywhere, and packaged if it is only ever P. The Jeep guide heads them with LLP designators (2_E), so each column is a trim and is read on its own. Grid.columns_are_trims decides which.

  2. N/C is a price of 0.0, not None. None means the guide printed no price at all. A credit prints in parentheses and becomes negative — (400)-400.0.

    A price answers "what does this option cost in this record's context", and a parented record's context is inside that package. A row prices itself once on its own and again for the packages that include it, the second band naming them in its qualifier. RAM 2500 p27 prints BLIND SPOT AND CROSS PATH DETECTION (XAN) at 640 / 695 unqualified, then a band qualified W/AAN OR AAU OR A7G OR A7H at N/C; the annotation beside it reads INCLUDED W/AAN OR AAU OR A7G OR A7H; N/A W/XBC. So XAN costs 695 on its own and 0.0 under any of those four. The same row structure gives DSA 495 on its own and 0.0 under A7E/A7F/A7G/A7H.

    This is what distinguishes the three values, and all three are readings of the page:

    valuethe guide prints
    Noneno price for that context — a GROUP DETAIL, PACKAGE CONTENT or STANDARD EQUIPMENT item, where none is printed at all
    0.0N/C for that context
    a figurethat figure for that context

    The transcriptions gave three different answers for one row: XAN bare 695 (right), XAN under A7G/A7H 695 (the standalone price on a packaged record), and XAN under AAN/AAU None (which claims nothing was printed). 460 records across the three RAM heavy-duty guides were corrected to the band the page prints for them, each checked against that row's own bands.

  3. A sales code is the last parenthesis of an item's name, not the first. UCONNECT 5 NAV W 12.0" DISPLAY (USA) (UBQ) is coded UBQ, and 8-SPD AUTO 880RE TRANS (MAKE) (DC1) is coded DC1. Taking the first parenthesis silently yields USA and MAKE, both of which validate as option codes, so nothing downstream would have complained.

  4. A row's MSRP is its first variant that applies to the trim. Rows carry several price sub-rows: a base price then discounted or fleet-only alternates, each tagged with a qualifier like W/XBC, FLEET ONLY or W/2_A. The first sub-row whose qualifier does not exclude the trim is that trim's price. This is what makes V9X9 cost $410 fleet-only on trim A and nothing on trim C — one printed row, two genuinely different answers.

  5. FLEET ONLY makes a row non-configurable for the trims it covers: it is not a retail-buyer choice. is_orderable_standalone stays True — the code is still a real standalone order code.

  6. (*) Package X includes package Y content fans Y's items under X, wherever X is configurable. Y's own configurability is irrelevant to the fanned-out copies.

  7. Trailing W/<CPP> on a rule scopes it to one trim (see rule-grammar.md); rules scoped to a trim that the row does not belong to are dropped, not kept and ignored.

  8. A powertrain matrix clause belongs to the CPP, not to the engine or transmission. The clause is printed inside a trim's cell beneath the CPP code — 29E over M/H WRE. Grand Wagoneer p17 settles which record carries it: one powertrain row (EL2 / DCD) spans three CPP columns, 24Q, 24Z and 24K, and only 24K is marked M/H RJA. The engine and transmission are the same in all three cells, so nothing about them can be what the clause qualifies. It goes on the (trim, CPP) record.

  9. AP9 SPECIAL PAINT PROCEDURE scopes a color table but is not a paint type. On the Charger it heads a block exactly as APA and APP do, so a color printed under it does require it and appears in that color's requires_one_of. It is held out of the only_one_of rule, which states that only one paint type may be chosen: a special-order procedure is not an alternative to monotone or two-tone paint. Flag this if you read it differently — it is the one paint code in the set whose treatment is not mechanical.

  10. short_description needs a precedence rule, because the guide prints several names for one option. Of the 110 distinct disagreements between the ten transcriptions and the parser, 88 are cases where both texts are printed, in different places:

  • RAM 279402 names ESL ENGINE - 6.4L V8 HEMI HD ENGINE (ESL) in STANDARD EQUIPMENT on p172 and 6.4L V8 HEMI HD ENGINE (ESL) in the STEP#2 powertrain cell.
  • APA is MONOTONE PAINT - APA in the STEP#4 box and MONOTONE PAINT (APA) in STANDARD EQUIPMENT on p174.
  • Grand Cherokee L prints POWER SUNROOF in a STEP#3 row and POWER SUNROOF (GWA) in PACKAGE CONTENT.

There is no fact of the matter to read off the page — only a choice — and the ten readers made it inconsistently, including within a single fixture.

The rule: STANDARD EQUIPMENT's name wins where it names the option, because that table is the guide's own alphabetical catalog of equipment names, and because a code like APA has a record at all only by being marked there. Otherwise the first source to name it stands.

This is the one field where the fixtures were aligned to a stated rule rather than to a unique printed string, and it is recorded here because that is a weaker kind of ground truth than the rest of this document rests on. 11. A CPP's price is the FWP/MSRP cell its powertrain maps to. One powertrain per package, so the CPP printed in a trim's cell on a POWERTRAIN AVAILABILITY row maps to exactly one (prefix row × trim column) of the price tables beneath it. RAM 1500 p2 puts 25Y in the RUMBLE BEE column of the EZH / DFR row, and p4's 25- row of that column reads 56,156 / 59,995. Both figures are captured. The same page also prints NET PACKAGE VALUE PRICE — 0 / 9,200 / 18,400 / 32,200 — which is what the package is worth, not what the CPP costs. One transcription took that row and was corrected. 12. A paint-type box contributes to a record, it does not create one. Following from the ruling above that the box emits nothing of its own: its heading and its clauses merge into whatever record another source makes for that code, and where none does the box adds nothing at all. RAM 279402 p125 boxes MONOTONE PAINT - APA inside DJ7X91's section, and STANDARD EQUIPMENT does not mark APA on DJ7X91, so that model code has no APA record. 36 such records across six guides were removed. The heading only fills a description that is otherwise empty; STANDARD EQUIPMENT's catalog name still wins. 13. A (*) includes package row's marks govern the fan-out, narrowed by the item's own where they overlap. The row is marked in the model columns like any other. RAM 2500 p162 fans AAU into A7S. Several AAU item rows are marked only on the L- and H-series, while A7S is offered on the M-series, so the row's marks stand there. RAM 3500 p137/p138 marks (*) Package A82 includes package A81 content on all four L-series codes but A81's WD4 and WMG rows only on the two …92s, so A82 brings those two wheels on the 92s alone. Intersecting unconditionally loses 1,284 records; ignoring the item's marks invents 8. This is the one place two sets of marks combine rather than one governing. 14. A row whose qualifier names no trim may still name one in its note. RAM 1500 p5 heads its STEP#4 color table with a single BLACK column — no column is a trim — and prices CLOTH BUCKET SEATS (C5X9) under (S), with Included on Rumble Bee (2TY) beneath. The 2Tx reading is corroborated on the same page: the two rows below carry both a note and an LLP designator and they agree, (2T1) with W/2_1 and (2T2) with W/2_2_. 15. Where the columns are trims, a row can price them by position. The Charger p23 prints TRACK PACKAGE on two bands, ANN under 2_S at 4,995 and under 2_F at 4,495, neither band qualified. The band that belongs to a trim is the one marking that trim's column. 16. Two PACKAGE CONTENT rows for one code: the permissive row wins. GC 2-row p2 prints 115V AUXILIARY POWER OUTLET (JKV) twice, once plain and once with W/O ABD set flush right, marking different trims. Where a trim is marked on both, it has the item unconditionally, and the qualified sibling constrains nothing, so the record carries no rule. Where a trim is marked only on the qualified row — LAREDO ALTITUDE on p4 — the rule applies. The record cannot hold the two rows apart, so unioning their rules would attach excludes [ABD] to an availability that does not depend on it. Same principle as True beating False on is_configurable.

A decision that looked open and was not

is_configurable for an item of a group evidenced only by its GROUP DETAIL E marks — TX, V9, X3, XN and the other seat/color families, which never appear as a STEP #3 orderable row.

Pacifica p23 marks -X3 with E under exactly five model codes and -XN under two. The item rows carry no marks at all, and neither group appears anywhere else in the guide except as M/H -X3 annotations and inside STEP #4 codes (SJX3, ULXN). The E marks are the only evidence there is, so the rule stated above — a group's own E mark counts as evidence that it is configurable there — is what the guide supports. Records exist and are configurable: five CXT, two CEG, which is what the parser produces.

A judgment call cannot move a total

Both defensible positions above still emit the record, so the decision can only move the configurable counter — never total, with_parent or with_rules. Where those moved, it was a defect every time. Six rules were read off the pages and the parser was corrected against them; fixture-verification.md records the rules and what was wrong.

The feature_counts fixture was one of the casualties: it had been taken from parser output rather than from the pages, so it enshrined the parser's own errors — the Pacifica total was 1,653 where the page gives 1,607. It now lists only counters the pages settle.

What is not covered

  • No fixture transcribes the RAM guide's ~20,000 records; correctness rests on the layered argument above, not on a single golden file.
  • GROUP DETAIL does not repeat every equipment group's contents, so the STEP #3 "Included in Equipment Groups" table is read as a source in its own right. UBQ (UCONNECT 5 NAV W 12.0" DISPLAY (USA) (UBQ)) appears only there.
  • is_fleet_only is decided per price variant. A row whose variants disagree resolves per trim, which is right for STEP #4 but has no test case in STEP #3, where it does not occur.