QDG Knowledge Base Read-only viewer QWebHub
general

Report Files and Outputs

Version 3 · Added the browser-based five-generation QWebHub pedigree output and distinguished it from JSON/DOCX report families.

Report Files and Outputs

What the project produces

The project has two output families:

  1. 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.
  2. Meeting data-QA reports from breeding_report. These write JSON result envelopes for operational checking; they do not currently use the V3 document renderer.
  3. QWebHub five-generation pedigree reports from gary_breeding_web. These are interactive browser/print reports populated directly from qdb.breeding; they do not produce the V3 JSON/DOCX contract.

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.

QWebHub pedigree output

Production version: v1.0.0. Route: qdb.qdatasite.com/breeding-reports/.

The user searches for an existing horse, selects the country/year/sex-qualified identity, and chooses Fill in Pedigree. The page resolves the selected qdb.breeding.id and returns up to 62 positions across five generations. Each populated cell is a button that opens that horse's own pedigree. Browser printing is the output mechanism; there is no generated JSON, DOCX or PDF file for this page.

WINX is resolved specifically as WINX / AUS / 2011. Ancestors come only from breeding.sire_id and breeding.dam_id; missing links remain blank. qdb.country supplies display codes only.

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.json and .docx
  • odin_validation/brutal_seasonal.json and .docx

validate_group_bc_against_odin.bat generates:

  • brutal_sire_progeny.json and .docx
  • brutal_order_of_foal.json and .docx
  • brutal_damsire_timeform.json and .docx
  • brutal_dam_sire_report.json and .docx
  • brutal_sire_forensic.json and .docx
  • brutal_bs_breeding.json and .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 positions
  • criteria_groups: sire, progeny, dam-line, cross, matrix, ranking and other score groups
  • matrix: matrix values, report flags, and _chromosome
  • rankings: Australian sire and broodmare-sire tables
  • lot: Stats1 and Stats2 catalogue rows
  • total_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 All column 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_progeny
  • order_of_foal_report
  • damsire_timeform_stats
  • sire_forensic_report
  • dam_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 extra values 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 DetailedStats and SiblingSales objects 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 identity
  • MedianMatrix: median-versus-median breakdown
  • PeakMatrix: 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 summary
  • DamPeakByOrder: order-of-foal results grouped by dam peak-rating band
  • DamMedianByOrder: 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, and extra.SireDam
  • DamSires: one summary row per dam sire
  • DamSireHorses: 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

  • sireId
  • foalYear
  • fromDate
  • toDate
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 records
  • AvgTF: average Timeform analysis
  • RacedPercent: 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 rows
  • extra.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 Data
  • DamSire: Cross Data
  • Dam: Dam Data
  • DamDam: 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/*.pdf
  • examples/brutal_kissmoon.json
  • breeding_report_v3/renderer/sample_report.json
  • matrix CSVs
  • tests and source files
  • schema and legacy-source references

Do not commit

  • root report.json and report_benchmark.json
  • root brutal_sire.* and brutal_seasonal.*
  • odin_validation/
  • group_bc_validation/
  • breeding_report_v3/_generated_sql.txt
  • sync_log.txt
  • renderer out/
  • caches, credentials, local environment files, and dependency directories
Updated by Robert on Sept. 6, 2026, 3:44 a.m. · Task: Promote QDB pedigree workflow to v1.0.0 production · Commit: b9c4aa1cf