Mission: Adapters describe your game's stats; the PRI engine normalizes and scores them. Follow this document exactly.
StatLine/
├── HOWTO.md ← this file (top level)
└── statline/
└── core/
└── adapters/
└── defs/
└── example.yaml
Purpose: Identifies and labels the adapter so the PRI engine knows what it represents.
Keys:
-
key(required): unique ID (kebab or snake case). -
version(required): SemVer.- Major: structure overhauls (buckets/metrics/clamps/DSL changes).
- Minor: add metrics/buckets or meaningful clamp shifts.
- Patch: small fixes/tuning.
-
aliases(optional): alternate names. -
title(optional): human‑friendly label.
Example:
key: example_game
version: 0.2.0
aliases: [ex, sample]
title: Example GameUsed for filtering and rollups (e.g., map/role/mode). Values are strict enums.
dimensions:
map: { values: [MapA, MapB, MapC] }
side: { values: [Attack, Defense] }
role: { values: [Carry, Support, Flex] }
mode: { values: [Pro, Ranked, Scrim] }Group metrics into weighted categories. Names are free‑form but must be consistent across weights and penalties.
buckets:
scoring: {}
impact: {}
utility: {}
survival: {}
discipline: {}Each metric:
- belongs to a bucket,
- uses realistic
clamp: [min, max], - optional
invert: truefor penalty metrics (lower is better), - pulls from
source.field.
metrics:
- { key: stat3_count, bucket: utility, clamp: [0, 50], source: { field: stat3_count } }
- { key: mistakes, bucket: discipline, clamp: [0, 25], invert: true, source: { field: mistakes } }Tip: Keep clamps tight and data‑driven. Wildly wide clamps dilute normalization and downstream PRI.
Purpose: Define ratios and derived signals as make/attempt pairs.
New DSL (v2.1.0): write field names or expressions directly (no raw[...]). You may also use numeric constants for attempt.
-
make,attemptaccept:- field names:
stat1_total,rounds_played - expressions:
min(3*hits, max(2*hits, score - penalties)) - numeric constants:
20
- field names:
-
min_den: minimum denominator required to score (guards divide‑by‑low). -
clamp: post‑compute clamp before normalization. -
Supported ops:
+ - * /, parentheses,min(a,b),max(a,b).
Examples:
efficiency:
# Per‑round scoring output
- key: stat1_per_round
bucket: scoring
clamp: [0.00, 2.00]
min_den: 5
make: "stat1_total"
attempt: "rounds_played"
# Impact success rate
- key: stat2_rate
bucket: impact
clamp: [0.00, 1.00]
min_den: 10
make: "stat2_numer"
attempt: "stat2_denom"
# Survival quality (good / total)
- key: stat4_quality
bucket: survival
clamp: [0.00, 1.00]
min_den: 5
make: "stat4_good"
attempt: "stat4_total"
# (Optional) Constant attempt — softly scale a raw signal
- key: pressure_hint
bucket: impact
clamp: [0.00, 1.00]
min_den: 1
make: "entries"
attempt: "20"Guardrails: choose
min_denhigh enough to avoid volatile low‑sample noise; clamp tight to expected domain.
Legacy mapping isn’t needed when you use source.field and the efficiency DSL. Prefer the newer approach.
Assign bucket importance for different presets. They don’t need to sum to 1; the engine normalizes.
weights:
pri:
scoring: 0.30
impact: 0.28
utility: 0.16
survival: 0.16
discipline: 0.10
mvp:
scoring: 0.34
impact: 0.30
utility: 0.12
survival: 0.14
discipline: 0.10
support:
scoring: 0.16
impact: 0.18
utility: 0.40
survival: 0.16
discipline: 0.10Extra downweight by bucket per preset (applies after normalization).
penalties:
pri: { discipline: 0.10 }
mvp: { discipline: 0.12 }
support: { discipline: 0.08 }Headers the engine can use to auto‑select your adapter. Include all fields referenced by metrics and efficiency.
sniff:
require_any_headers:
[stat1_total, rounds_played, stat2_numer, stat2_denom, stat4_good, stat4_total, stat3_count, mistakes]- PRI Scale: fixed 55–99. Do not assume 0–99.
- Percentiles (batch/output): adapters do not define these; they’re computed by the engine per request/dataset window.
- Output toggles: callers may request
show_weights,hide_pri_raw, per‑metric deltas, etc. Adapters should not rely on these. - Batch filters: callers may filter by
position,games_played, and adapter‑defined predicates like{stat, op, value}. - Versioning: any breaking schema change → bump major.
- Every
metric.bucketexists inbuckets. -
clampranges are realistic; penalty metrics useinvert: true. -
efficiency[*].make/attemptreference real fields or valid expressions;min_denis set. - Constant denominators are quoted strings (e.g.,
"20"). -
weightsonly reference existing buckets (engine normalizes totals). -
sniff.require_any_headersincludes all raw fields used bymetrics/efficiency. -
versionfollows SemVer and reflects material changes.
- Metric transforms
- Per‑dimension clamps
- Per‑metric multipliers
- Team‑factor modes
key: example_game
version: 0.2.0
aliases: [ex, sample]
title: Example Game
dimensions:
map: { values: [MapA, MapB, MapC] }
side: { values: [Attack, Defense] }
role: { values: [Carry, Support, Flex] }
mode: { values: [Pro, Ranked, Scrim] }
buckets:
scoring: {}
impact: {}
utility: {}
survival: {}
discipline: {}
metrics:
- { key: stat3_count, bucket: utility, clamp: [0, 50], source: { field: stat3_count } }
- { key: mistakes, bucket: discipline, clamp: [0, 25], invert: true, source: { field: mistakes } }
efficiency:
- key: stat1_per_round
bucket: scoring
clamp: [0.00, 2.00]
min_den: 5
make: "stat1_total"
attempt: "rounds_played"
- key: stat2_rate
bucket: impact
clamp: [0.00, 1.00]
min_den: 10
make: "stat2_numer"
attempt: "stat2_denom"
- key: stat4_quality
bucket: survival
clamp: [0.00, 1.00]
min_den: 5
make: "stat4_good"
attempt: "stat4_total"
weights:
pri:
scoring: 0.30
impact: 0.28
utility: 0.16
survival: 0.16
discipline: 0.10
mvp:
scoring: 0.34
impact: 0.30
utility: 0.12
survival: 0.14
discipline: 0.10
support:
scoring: 0.16
impact: 0.18
utility: 0.40
survival: 0.16
discipline: 0.10
penalties:
pri: { discipline: 0.10 }
mvp: { discipline: 0.12 }
support: { discipline: 0.08 }
sniff:
require_any_headers:
[stat1_total, rounds_played, stat2_numer, stat2_denom, stat4_good, stat4_total, stat3_count, mistakes]- Keep buckets few and meaningful; noisy bucket design destroys interpretability.
- Prefer rates to raw counts; clamp rates in realistic domains.
- Use
min_dento fight small‑sample volatility. - When in doubt, simulate on real match CSVs and check percentile stability.
- Document your adapter’s required columns in repo docs for users.