Report Files and Outputs
Version 2 · Added exact output basenames, complete CLI calls, sire/dam master-list ID meanings, required pedigree positions, options, cutoff behavior, canonical BRUTAL/KISS MOON IDs, Bloodstock cross dependency, and validation filenames.
Historical versionReport Files and Outputs
What the project produces
The project has two output families:
- Breeding and pedigree reports from
breeding_report_v3. Each run writes a structured JSON file. The Node renderer can turn that JSON into DOCX and optionally PDF. - Meeting data-QA reports from
breeding_report. These write JSON result envelopes for operational checking; they do not currently use the V3 document renderer.
Original PDFs under examples/golden/ are reference inputs used for comparison. They are not generated output and remain tracked in Git. Generated reports and validation folders are ignored by Git.
V3 file lifecycle
1. JSON data file
Every V3 builder serialises a ReportModel to the path supplied with --out.
python -m breeding_report_v3 <report arguments> --out report.json
The JSON is the authoritative handoff between data/business logic and presentation. Common top-level fields are:
| Field | Meaning |
|---|---|
report_type |
Selects the renderer and identifies the report contract |
label |
Human-readable sire/dam/report label |
sex |
Requested foal sex where applicable |
generated_at |
UTC generation timestamp |
parents |
Full RSParent objects keyed by pedigree position |
criteria_groups |
Scored Foal Index criteria and computed group scores |
matrix |
Matrix-model values, display flags, and chromosome map |
rankings |
Australian sire and broodmare-sire ranking data |
lot |
Catalogue-style Stats1 and Stats2 data |
tables |
Named SQL result sets for generic table reports |
extra |
Report-specific scalar details and supplemental values |
bs_parents |
Bloodstock BSParent objects keyed by position |
total_score |
Sum of all criterion-group scores |
Datetimes and dates are ISO formatted. Decimal values become JSON numbers. If the same parent object appears more than once, later occurrences may be represented as {"_ref": "...", "HorseID": ...} to prevent recursive or duplicated structures.
The JSON keeps all rows returned by the builder. Any display limit described below applies only to DOCX rendering.
2. Word document
The Node renderer reads JSON and writes the requested DOCX path:
node breeding_report_v3\renderer\render.js --report report.json --out out\report.docx
The renderer does not connect to MySQL. It chooses the document layout from report_type. DOCX is the editable presentation output.
3. PDF document
Add --pdf to render DOCX and then invoke LibreOffice headlessly:
node breeding_report_v3\renderer\render.js --report report.json --out out\report.docx --pdf
The PDF is written beside the DOCX with the same base filename. On Windows the renderer tries soffice and then libreoffice; on other platforms it tries the reverse order. LibreOffice must be installed and available on PATH.
Filenames
The code does not impose a business filename. The caller supplies both JSON and DOCX filenames. Batch scripts use stable names such as brutal_sire.json and brutal_sire.docx.
Exact input and file-name reference
What an ID represents
Horse names are not accepted by the current CLI. Calls use master-list IDs from the legacy rs schema:
- a sire/stallion position uses
rs.tblsiremasterlist.MSLID; - a dam/mare position uses
rs.tbldammasterlist.DMSLID.
The parameter name describes the pedigree path from the proposed mating. For example, sireDamDamId is the proposed sire's dam's dam, while damDamSireId is the proposed dam's dam's sire.
| Parameter | Pedigree position | Master-list key |
|---|---|---|
sireId |
proposed sire | tblsiremasterlist.MSLID |
sireSireId |
sire's sire | tblsiremasterlist.MSLID |
sireSireDamId |
sire's sire's dam | tbldammasterlist.DMSLID |
sireSireDamDamId |
sire's sire's dam's dam | tbldammasterlist.DMSLID |
sireDamId |
sire's dam | tbldammasterlist.DMSLID |
sireDamDamId |
sire's dam's dam | tbldammasterlist.DMSLID |
sireDamDamDamId |
sire's dam's dam's dam | tbldammasterlist.DMSLID |
damId |
proposed dam | tbldammasterlist.DMSLID |
damSireId |
dam's sire / broodmare sire | tblsiremasterlist.MSLID |
damSireDamId |
dam sire's dam | tbldammasterlist.DMSLID |
damSireDamDamId |
dam sire's dam's dam | tbldammasterlist.DMSLID |
damDamId |
dam's dam / second dam | tbldammasterlist.DMSLID |
damDamSireId |
dam's dam's sire | tblsiremasterlist.MSLID |
damDamDamId |
dam's dam's dam / third dam | tbldammasterlist.DMSLID |
damDamDamDamId |
dam's dam's dam's dam / fourth dam | tbldammasterlist.DMSLID |
PedigreeInput.from_params() accepts these camel-case keys case-insensitively. Database resolution from one horse ID is not implemented, so callers must currently supply the required lineage IDs.
Required inputs and recommended output names
The “complete report input” column describes the information needed for the expected full document. The full pedigree builder technically skips positions whose IDs are zero, but that produces an incomplete report.
| CLI report | Recommended base filename | Complete report input | Optional input |
|---|---|---|---|
dam_index |
foal_index |
12 canonical lineage IDs plus sex |
description, includeOwner, export, statsBefore, foalYear |
breeding_v3 |
breeding_v3 |
sireId, sireSireId, damId, damSireId, damDamId, damDamSireId, damDamDamId, and sex |
description, includeOwner, export, statsBefore, foalYear |
sire_report_v2 |
sire_report |
one sire MSLID |
stats-before |
seasonal_stats |
seasonal_stats |
one sire MSLID |
stats-before |
sire_progeny |
new_sire_breakdown |
one sire MSLID |
none used by the builder |
order_of_foal_report |
order_of_foal |
one sire MSLID |
none used by the builder |
damsire_timeform_stats |
damsire_timeform |
one sire MSLID; this is the sire whose foals' broodmare sires are analysed |
none used by the builder |
sire_forensic_report |
sire_forensic |
one sire MSLID, foalYear, fromDate, and toDate |
stats-before is accepted but the query uses fromDate/toDate |
dam_sire_report |
individual_damsire |
one dam-sire MSLID, passed through --sire-id or damSireId in JSON |
none used by the builder |
bs_breeding_report |
bloodstock_dam |
for all four sections: sireId, damSireId, damId, and damDamId |
includeOwner, sireCountries; partial reports may omit positions |
Each base name normally produces:
<base>.json Python data and business-logic output
<base>.docx editable Word report
<base>.pdf optional LibreOffice conversion
Sex and report options
| Option | Use |
|---|---|
sex |
For scored mating reports, supply Filly or Colt. Do not omit it for production scoring; the current generic-sex calculation otherwise follows the female path. |
statsBefore / --stats-before |
Deterministic cutoff used by dam_index, breeding_v3, sire_report_v2, and seasonal_stats. The CLI flag takes precedence over a value inside pedigree JSON. |
description |
Free-text mating/report description carried into the full report model. |
includeOwner |
Includes owner-related race information where supported; default is false. |
export |
Legacy endpoint compatibility flag retained in PedigreeInput; output format is controlled by the renderer command. |
foalYear |
General pedigree option and a mandatory cohort selector for sire_forensic_report. |
sireCountries |
Bloodstock Dam-only comma-separated country IDs used to filter/describe sire sales information. |
The Group B/C CLI accepts --stats-before for a consistent interface, but the current table/BS builders do not apply it. Sire Forensic uses its explicit fromDate and toDate window.
Complete canonical calls
The following examples use BRUTAL and KISS MOON. Run them from the repository root.
Foal Index with a fixture
python -m breeding_report_v3 --report dam_index --pedigree examples\brutal_kissmoon.json --stats-before 2026-02-01 --out out\foal_index.json
node breeding_report_v3\renderer\render.js --report out\foal_index.json --out out\foal_index.docx --pdf
Foal Index with explicit IDs
$foalIndexParams = '{"sireId":93686,"sireSireId":4006,"sireSireDamId":18993,"sireSireDamDamId":38720,"sireDamId":182832,"sireDamDamId":89670,"sireDamDamDamId":1173,"damId":531529,"damSireId":16790,"damSireDamId":237404,"damDamId":170769,"damDamDamId":152911,"sex":"Filly","export":true}'
python -m breeding_report_v3 --report dam_index --params $foalIndexParams --stats-before 2026-02-01 --out out\foal_index.json
Bloodstock Print New V2
$breedingV3Params = '{"sireId":93686,"sireSireId":4006,"damId":531529,"damSireId":16790,"damDamId":170769,"damDamSireId":16818,"damDamDamId":152911,"sex":"Filly","export":true}'
python -m breeding_report_v3 --report breeding_v3 --params $breedingV3Params --stats-before 2026-02-01 --out out\breeding_v3.json
node breeding_report_v3\renderer\render.js --report out\breeding_v3.json --out out\breeding_v3.docx --pdf
Single-sire reports
python -m breeding_report_v3 --report sire_report_v2 --sire-id 93686 --stats-before 2026-02-01 --out out\sire_report.json
python -m breeding_report_v3 --report seasonal_stats --sire-id 93686 --stats-before 2026-02-01 --out out\seasonal_stats.json
python -m breeding_report_v3 --report sire_progeny --sire-id 93686 --out out\new_sire_breakdown.json
python -m breeding_report_v3 --report order_of_foal_report --sire-id 93686 --out out\order_of_foal.json
python -m breeding_report_v3 --report damsire_timeform_stats --sire-id 93686 --out out\damsire_timeform.json
Sire Forensic and Individual DamSire reports
python -m breeding_report_v3 --report sire_forensic_report --params '{"sireId":93686,"foalYear":2021,"fromDate":"2022-01-01","toDate":"2026-02-01"}' --out out\sire_forensic.json
python -m breeding_report_v3 --report dam_sire_report --sire-id 16790 --out out\individual_damsire.json
For Sire Forensic, foal year 2021 and the displayed date range are validation assumptions and still require business confirmation.
Bloodstock Dam
$bloodstockParams = '{"sireId":93686,"damId":531529,"damSireId":16790,"damDamId":170769}'
python -m breeding_report_v3 --report bs_breeding_report --params $bloodstockParams --out out\bloodstock_dam.json
node breeding_report_v3\renderer\render.js --report out\bloodstock_dam.json --out out\bloodstock_dam.docx --pdf
For this report, damSireId is a cross filter and only creates the Cross Data section when sireId is also present. damId and damDamId can be generated independently. Calling the report with no IDs succeeds but produces an empty document, so supply at least one meaningful position.
Canonical BRUTAL/KISS MOON identity map
| Position | ID | Name |
|---|---|---|
| Sire | 93686 | BRUTAL (NZ) |
| Sire's sire | 4006 | O'REILLY (NZ) |
| Dam | 531529 | KISS MOON (USA) |
| Dam sire | 16790 | MALIBU MOON (USA) |
| Dam's dam | 170769 | KISS THE DEVIL (USA) |
| Dam's dam's sire | 16818 | KRIS S (USA) |
| Dam's dam's dam | 152911 | DEVIL'S NELL (USA) |
Additional Foal Index chromosome IDs are held in examples/brutal_kissmoon.json.
Validation batch filenames
validate_against_odin.bat generates:
odin_validation/brutal_sire.jsonand.docxodin_validation/brutal_seasonal.jsonand.docx
validate_group_bc_against_odin.bat generates:
brutal_sire_progeny.jsonand.docxbrutal_order_of_foal.jsonand.docxbrutal_damsire_timeform.jsonand.docxbrutal_dam_sire_report.jsonand.docxbrutal_sire_forensic.jsonand.docxbrutal_bs_breeding.jsonand.docx
The Group B/C files are written beneath group_bc_validation/.
Supported V3 reports
| CLI report | Business name | Main input | Renderer |
|---|---|---|---|
dam_index |
Foal Index / Dam Index | Full deep pedigree | Full pedigree/scoring |
breeding_v3 |
Bloodstock Print New V2 / BreedingReportV3WithIndex | Full pedigree | Currently full pedigree/scoring |
sire_report_v2 |
Sire Report V2 | Sire ID | Dedicated sire layout |
seasonal_stats |
Seasonal Stats | Sire ID | Dedicated seasonal layout |
sire_progeny |
New Sire Breakdown | Sire ID | Generic table layout |
order_of_foal_report |
Order of Foal Stats | Sire ID | Generic table layout |
damsire_timeform_stats |
DamSire Timeform Stats | Sire ID | Generic table layout |
sire_forensic_report |
Sire Forensic Report | Sire ID, foal year, date range | Generic table layout |
dam_sire_report |
Individual DamSire Statistics | Dam-sire ID | Generic table layout |
bs_breeding_report |
Bloodstock Dam | Up to four parent IDs | Dedicated Bloodstock layout |
1. Foal Index / Dam Index
CLI name: dam_index
JSON report_type: dam_index
Purpose
Produces the scored Foal Index for a proposed sire/dam mating. It assembles deep sire-line and dam-line pedigree positions, cross performance, rankings, matrix-model values, chromosome ancestry, catalogue statistics, and scoring criteria.
Inputs
Supply either a pedigree fixture or inline parameter JSON. The canonical fixture is examples/brutal_kissmoon.json.
python -m breeding_report_v3 --report dam_index \
--pedigree examples\brutal_kissmoon.json \
--stats-before 2026-02-01 \
--out out\foal_index.json
The fixture contains the sire, sire ancestors, dam, dam sire, dam ancestors, sex, description, and other legacy endpoint parameters. --no-score can build the data without scoring.
JSON content
parents: sire, dam-line, sire/dam-sire cross, and related pedigree positionscriteria_groups: sire, progeny, dam-line, cross, matrix, ranking and other score groupsmatrix: matrix values, report flags, and_chromosomerankings: Australian sire and broodmare-sire tableslot: Stats1 and Stats2 catalogue rowstotal_score: grand total
DOCX/PDF content
- report title and generated timestamp
- mating label
- total score and total excluding the progeny group
- Pedigree Score table with group totals and individual criteria
- Matrix Model Value criteria
- four-generation XX Chromosome Pathway grid
- Australian sire ranking table
- Australian broodmare-sire ranking table
Validation
Parent data, matrix values, ranking behavior, key scoring blocks, and the renderer sample have been checked against the BRUTAL x KISS MOON references. A final live end-to-end grand-total reconciliation remains open because historical notes contain both 985/990 and 935/920 reference totals.
2. Bloodstock Print New V2
CLI name: breeding_v3
JSON report_type: breeding_report_v3_with_index
Purpose
Builds the legacy BreedingReportV3WithIndex data contract using the same full pedigree orchestrator as Foal Index, with its own report type and view flags.
Inputs
Supply the seven lineage IDs and sex shown in the exact call reference above, either through --params or the breeding_report_v3_with_index section of a compatible fixture. The canonical call uses BRUTAL, O'REILLY, KISS MOON, MALIBU MOON, KISS THE DEVIL, KRIS S, and DEVIL'S NELL.
Current presentation
The renderer currently falls through to the same scoring/chromosome/ranking document used by Foal Index. The dedicated redesigned Bloodstock layout has not yet been implemented. Treat the JSON as the richer and more stable output until that presentation work is complete.
Validation
Underlying parent/scoring components have targeted validation. Full live total reconciliation and dedicated layout validation remain open.
3. Sire Report V2
CLI name and JSON report_type: sire_report_v2
Purpose
Produces a detailed report for one sire without Foal Index scoring.
python -m breeding_report_v3 --report sire_report_v2 \
--sire-id 93686 --stats-before 2026-02-01 \
--out out\sire_report.json
Document content
- Overview Data and sire identity
- pedigree: sire, dam, dam's sire, foal date, description, and age at conception
- racing information: race record, strike rates, last race, trainer, winning distances
- Group/Listed stake wins and placings
- top and median Timeform ratings
- male and female progeny rated 100+, including sex, year, dam sire, 2YO winner flag, rating, and last race
- Seasonal Stats, including the
Allcolumn when returned - progeny by age: starts, individual starters/winners, wins, win/place rates, median TF, and average winning distance
Validation
Live rerun confirmed cutoff handling, date rendering, description composition, Seasonal Stats, and agreement between embedded and standalone seasonal values.
4. Seasonal Stats
CLI name and JSON report_type: seasonal_stats
Purpose
Produces a compact season-by-season sire performance report. It intentionally loads basic sire identity plus seasonal statistics rather than the full parent model.
python -m breeding_report_v3 --report seasonal_stats \
--sire-id 93686 --stats-before 2026-02-01 \
--out out\seasonal_stats.json
Document content
Columns are displayed from oldest to newest even though the query returns newest first. Rows include:
- individual progeny runners and winners
- individual 100+ TF runners and new 100+ TF runners
- individual stake, Group, and Group 1 winners
- stake wins
- median TF across all runs
- median TF for individual runners
- average winning distance
- individual Saturday metropolitan winners
- R&S disclaimer text
Validation
Fully rerun against live data. The cutoff correctly removes the later 26/27 season from the canonical February 2026 check.
Generic table-report behavior
The following five reports use a shared renderer:
sire_progenyorder_of_foal_reportdamsire_timeform_statssire_forensic_reportdam_sire_report
For each named result set, the renderer:
- derives columns from the first row's keys;
- humanises camel-case and underscore column names;
- prints one titled section per non-empty table;
- renders scalar
extravalues in a Details section; - shows “No rows returned” when all tables are empty;
- displays at most 200 rows per table in DOCX and adds an omission note;
- leaves every returned row intact in JSON;
- omits nested
DetailedStatsandSiblingSalesobjects from the generic table because they are not scalar cells.
These layouts are functional first-pass ports, not bespoke copies of every legacy PDF.
5. New Sire Breakdown
CLI name and JSON report_type: sire_progeny
Purpose
Runs legacy stored query 247 for one sire and presents progeny rating matrices.
Result tables
SireName: selected sire identityMedianMatrix: median-versus-median breakdownPeakMatrix: peak-versus-peak breakdown
python -m breeding_report_v3 --report sire_progeny \
--sire-id 93686 --out out\new_sire_breakdown.json
Validation
Builder wiring and serialisation are checked. Live query and rendered-document review remain required.
6. Order of Foal Stats
CLI name and JSON report_type: order_of_foal_report
Purpose
Analyses the sire's progeny performance by the dam's order of foal. The query builds temporary tables, calculates sire and foal ratings, and bands dams by peak and median rating.
Result tables
SireMedian: sire identity and median summaryDamPeakByOrder: order-of-foal results grouped by dam peak-rating bandDamMedianByOrder: order-of-foal results grouped by dam median-rating band
python -m breeding_report_v3 --report order_of_foal_report \
--sire-id 93686 --out out\order_of_foal.json
Validation
The multi-result wiring is checked; live temp-table execution and DOCX review remain required.
7. DamSire Timeform Stats
CLI name and JSON report_type: damsire_timeform_stats
Purpose
For a selected sire, ranks the broodmare sires behind that sire's foals by Timeform performance, then retrieves the individual foals associated with the leading dam-sire rows.
Result data
extra.SireName,extra.SireSire, andextra.SireDamDamSires: one summary row per dam sireDamSireHorses: individual progeny behind the returned leading dam sires
python -m breeding_report_v3 --report damsire_timeform_stats \
--sire-id 93686 --out out\damsire_timeform.json
Validation
Python flow is checked; live two-stage query and output review remain required.
8. Sire Forensic Report
CLI name and JSON report_type: sire_forensic_report
Purpose
Examines a sire cohort selected by foal year over an explicit race-date window. This report cannot be generated from a sire ID alone.
Required inputs
sireIdfoalYearfromDatetoDate
python -m breeding_report_v3 --report sire_forensic_report \
--params '{"sireId":93686,"foalYear":2021,"fromDate":"2022-01-01","toDate":"2026-02-01"}' \
--out out\sire_forensic.json
Result tables
Runs: qualifying run-level/cohort recordsAvgTF: average Timeform analysisRacedPercent: percentage of the cohort that raced
The JSON extra block records sire data, title, foal year, and date range.
Validation
The values in the example are assumptions used by the batch script, not confirmed BRUTAL business parameters. Live execution and parameter confirmation remain required.
9. Individual DamSire Statistics
CLI name and JSON report_type: dam_sire_report
Purpose
For one dam sire, returns one row per sire whose Australian/New Zealand foals share that broodmare sire, including summary, sibling peak-TF ranking, and male/female median statistics.
Input caveat
The generic CLI flag is --sire-id, but for this report the value is a dam-sire ID.
python -m breeding_report_v3 --report dam_sire_report \
--sire-id 16790 --out out\individual_damsire.json
Result data
Sires: all returned sire rowsextra.Sire: the selected dam-sire master record- title: Individual DamSire Statistics
Validation
Builder and renderer wiring are checked. Live query and visual review remain required.
10. Bloodstock Dam
CLI name and JSON report_type: bs_breeding_report
Purpose
Produces a Bloodstock parent report using the narrower BSParent data model. It can assemble up to four positions:
Sire: Sire DataDamSire: Cross DataDam: Dam DataDamDam: Grand-Dam Data
At least one useful parent ID must be supplied.
python -m breeding_report_v3 --report bs_breeding_report \
--params '{"sireId":93686,"damId":531529,"damSireId":16790,"damDamId":170769}' \
--out out\bloodstock_dam.json
Data differences from RSParent
- own-race queries do not apply the RSParent jumps-race filter;
- top-20 and rolling-12-month Timeform lists are used;
- Dam includes gear-worn analysis;
- DamSire includes group summary and MPC breakdown;
- sire/dam-sire positions include leading trainer data;
- parent-specific progeny surface, age, distance, stake, top-rating, and related-parent data is available in JSON.
Current document content
For each available position, the DOCX renders:
- identity and pedigree/racing information
- 100+ TF progeny where available
- first bred and foal counts
- raced foals and winners
- stake winners
- Asian performance
- average and median progeny TF
- highest-rated runner
- progeny by surface/going
- progeny by age
The JSON contains additional BSParent fields that the first-pass DOCX does not yet display.
The high-yearling-sales/sibling convenience merge is non-fatal. If it fails, the report still builds and records HighYearlingSalesError in extra.
Validation
Fake-runner construction and serialisation are checked. Live SQL and rendered output have not yet been validated.
Validation batch outputs
Group A
validate_against_odin.bat writes JSON, DOCX, optional PDF, and run.log under odin_validation/ for Sire Report V2 and Seasonal Stats.
Group B/C
validate_group_bc_against_odin.bat writes the six newer reports under group_bc_validation/:
- New Sire Breakdown
- Order of Foal Stats
- DamSire Timeform Stats
- Sire Forensic Report
- Individual DamSire Statistics
- Bloodstock Dam
Both directories are reproducible local output and are ignored by Git.
Meeting data-QA JSON reports
The breeding_report package produces JSON only:
python -m breeding_report --report missing_breeding \
--meeting-id 123 --out out\missing_breeding_LOT123.json
Its envelope is separate from the V3 ReportModel contract:
| Field | Meaning |
|---|---|
report_type |
QA report name |
meeting_id |
Meeting identifier where relevant |
success |
Operation status |
message |
Human-readable outcome |
result.Total |
Total matching rows |
result.RefIds |
Reference IDs |
result.Names |
Affected runner names |
result.Duplicates |
Duplicate group data |
result.Data |
Full result rows |
Supported QA output names are meeting_info, missing_breeding, missing_brand, missing_microchip, missing_lifenumber, and overwrite_check.
Reference files versus generated files
Keep in Git
examples/golden/*.pdfexamples/brutal_kissmoon.jsonbreeding_report_v3/renderer/sample_report.json- matrix CSVs
- tests and source files
- schema and legacy-source references
Do not commit
- root
report.jsonandreport_benchmark.json - root
brutal_sire.*andbrutal_seasonal.* odin_validation/group_bc_validation/breeding_report_v3/_generated_sql.txtsync_log.txt- renderer
out/ - caches, credentials, local environment files, and dependency directories