Public task and development documentation. Official evaluation boundary.
The EMBER Score (scoring version 1.0)
This document is the normative definition of the EMBER Score. The research, the candidate formulas and the sensitivity study that justify each choice are in benchmark-methodology.md. The frozen environment that every model is scored on is in environment-pack.md.
The EMBER Score is one number in [0, 100]. Its unit is
benchmark-performance points under EMBER scoring version 1.0. It is not a
percentage of people evacuated. A report says "72.4 points under EMBER
scoring version 1.0", never "72.4% evacuated".
1. Status and versioning
| Item | Value |
|---|---|
| Version | 1.0 |
| Constants | Official scoring constants (section 4); scoring-constants digest pins them |
| Separate from | simulator, observation, action schema, scenario schema, metrics, crowd diagnostics, statistics, generator and evaluation versions. Scoring changes none of them. |
| Provenance | Scoring version; benchmark revision 2 and later pin it (see integrity.md section 12) |
The scoring version changes when a definition, a constant, the arithmetic or the serialization changes. A score is comparable with another score only when both have the same scoring version, the same constants digest, the same evaluation manifest and the same environment pack.
A score is official only when it is computed against an
environment pack whose evaluation manifest equals the
results' manifest, under the official scoring constants. The score report official tells
which. A score against a bare suite is labelled UNOFFICIAL.
2. Inputs and authentication
The scoring step takes:
trials: one or more evaluation result objects of the same model on the same evaluation manifest. Use one trial for a deterministic policy and several for a stochastic model (section 12).target: the suite, or the environment pack.failures[t]: an optional map from episode index to failure kind that says why trialthas no result for a scheduled episode.
Every result is authenticated from scratch, exactly as in statistics.md: the manifest must round-trip and target the suite, every run record is replayed (the replay check), and the stored metrics must equal the recomputed metrics. With a pack, every scheduled episode's fire trajectory must also match the pack's the fire-world digest, and every recorded burning set must match that trajectory. Any difference raises a scoring input error. There is no partial score.
Provider-reported success, accuracy or cost is never an input. Scoring is local and uses only replayed records.
3. Privileged references
Several components compare the model with a relaxed single-person optimum. The optimum is computed by backward induction over (cell, step) for one person alone who knows the whole future fire and follows the simulator phase order. Other people can only block moves, so each reference is a lower bound for every policy. The references use the evaluator seed. They are evaluator-side only, like the privileged oracle, and never reach a model.
For each scheduled episode and each person i at start cell x_i:
| Reference | Definition |
|---|---|
M* (max_evacuated) |
number of people with a finite earliest evacuation step. Equal to earliest evacuation from the privileged escape bound (tested on every public scenario). |
L_i |
earliest evacuation step from (x_i, 0) |
m*_i |
fewest cell moves of any escape from (x_i, 0) (the move onto the exit counts) |
D*_i |
fewest danger-zone person-states of any escape from (x_i, 0) |
L(x, t) |
earliest evacuation step from cell x at snapshot t |
A person-state is in the danger zone when the Manhattan distance d from
the person's cell to the nearest burning cell satisfies 0 < d <= 2
(HAZARD_RADIUS = 2). The distance ignores walls, like the metrics exposure
proxy.
The transition rule is the simulator's: from (x, t) a person may stay or
move to an open neighbour y, unless y burns at the start of the step;
a non-burning exit evacuates at once; any other y must not burn after the
fire phase. Snapshot H (max_steps) has no successor.
4. The episode score
For one authenticated episode with M* >= 1:
EMBER = 100 * Safety * Quality ^ beta * Severity
Safety = E * P_casualty * P_stranding (0 at the catastrophic gate)
Quality = weighted geometric mean of the defined quality components
beta = min(1, ln(alpha_c) / ln(q_min)) = ln 0.6 / ln 0.5 = 0.7369655941662...
Severity = product over severe components k of phi * (q_k / q_k_severe) ^ gamma
Every component, Safety, Quality and Severity are in [0, 1]. No component
can exceed 1, so no strength offsets a failure. Safety caps the score
(section 5), and each severe quality failure caps it again (section 4.3).
Trajectory invariance (a V1 invariant). Every score input is a function
of the authenticated state trajectory: positions, statuses and the fire, step
by step. No input comes from the action log alone. So two runs with
byte-identical state trajectories get identical scores, whatever actions
produced them. test_block_scrub_keeps_trajectory_and_score checks this on
replayed public episodes (section 4.2).
4.1 Safety and person-level attribution
Every loss is attributed per person. A person i is savable when the
privileged earliest escape L_i (section 3) is finite. Then, for every
person at the end of the episode:
| Outcome | Savable | Not savable |
|---|---|---|
| evacuated | evacuated | evacuated (cannot happen: L_i would be finite) |
| died | avoidable casualty | unavoidable casualty |
| still active or stranded at the horizon | avoidable stranded | unavoidable stranded |
c and s are the numbers of avoidable casualties and avoidable stranded
people. The evidence stores the sorted person IDs of all four loss classes
(avoidable_casualty_ids, avoidable_stranded_ids,
unavoidable_casualty_ids, unavoidable_stranded_ids), so each count can be
audited person by person.
An unavoidable loss is never transferred between people. An earlier draft
computed c = max(0, C - U) with U = N - M* from aggregate counts. That
rule lets the unavoidable loss of one person hide the avoidable death of
another: with person a savable but dead and person b unsavable and
stranded, the draft gives c = 0, but the correct value is c = 1.
test_real_episode_person_level_attribution reproduces this case with a real
replayed episode. The evidence validator rejects any record where the
identity sets overlap, are not sorted, or do not match the counts.
| Factor | Formula | Official constants |
|---|---|---|
Evacuation E |
(evacuated / M*) ^ kE |
kE = 2 |
Casualty P_casualty |
alpha_c ^ log2(1 + c) * (1 - c / M*) ^ k_c |
alpha_c = 0.6, k_c = 4 |
Stranding P_stranding |
alpha_s ^ log2(1 + s) * (1 - s / M*) ^ k_s |
alpha_s = 0.8, k_s = 2 |
| Catastrophic gate | Safety = 0 when (c + s) / M* >= 1/2 |
catastrophic_loss_rate = 1/2 |
The incident factor alpha ^ log2(1 + n) is paid in full for the first
loss and again for every doubling of 1 + n. It makes the first casualty
expensive in any population. The rate term (1 - n / M*) ^ k grows with
the share of people lost. A casualty costs more than a stranded person.
Stranding and incomplete evacuation are penalized independently of
casualties.
4.2 Quality components
| Component | Formula | Defined when | Weight |
|---|---|---|---|
Time T |
Q_cut / sum(A_i) over evacuees; A_i is the evacuation step, Q_cut the capacity bound (below) |
at least one evacuee | 3/8 |
Hazard H |
(1 - (D - D*) / sum(A_i)) ^ kH over evacuees; D = their danger-zone states, D* = sum(D*_i) |
at least one evacuee | 2/8 |
Path P |
sum(m*_i) / sum(m_i) over evacuees; m_i = cells moved |
at least one evacuee | 1/8 |
Replanning R |
sum(L(x_e, t_e) - t_e) / sum(r_e - t_e) over recoverable route-invalidation events |
at least one recoverable event | 2/8 |
Constant: kH = 1. There is no Coordination component (see "Congestion is
not a score input" below).
Every ratio is a privileged lower bound over the actual value, so it is in
(0, 1]. If an actual value is below its bound, the record is rejected: that
can only happen with a forged record.
Time capacity bound Q_cut. The sum of single-person optimum steps
sum(L_i) ignores that people queue. Q_cut adds the two capacity limits
that no policy can avoid. Both are lower bounds on sum(A_i) for every
policy, and sum(L_i) <= Q_exit <= Q_cut <= sum(A_i):
- Exit capacity (
Q_exit,evacuee_time_queue_bound). Positions after movement are distinct, so in each step at most one person leaves through each exit cell that is not burning at the start of the step.Q_exitis the list schedule of the evacuees' release stepsL_iover these exit slots. For unit jobs with release dates, the list schedule minimizes the sum of finish steps. - Cut capacity (
Q_cut,evacuee_time_cut_bound, the Time reference). Letwbe the wall-only distance to the nearest exit. For a thresholdd >= 1, take a connected componentKof the open cells withw > d. A move changeswby at most 1 and exits havew = 0, so every escape fromKfirst steps ontoN(K), the cells next toKwithw = d: a vertex cut, for example a door. Positions are distinct, so in stepsat mostk_speople stand onN(K), wherek_scounts the cut cells that burn neither at the start nor at the end of the step. An evacueeithat starts inKfirst enters the cut in a steps_i >= r_i, its earliest single-person arrival on a cut cell from which escape is still possible, and needs at leastq_imore steps from there (the least single-person remaining time over the cut cells and snapshots it can reach). SoA_i >= s_i + q_iandA_i >= L_i. The list schedule of the entries minimizessum(s_i). Components whose cuts share cells are merged, so each person is in at most one group; people outside every group addL_i.Q_cutis the maximum over all thresholds andQ_exit.
Every step of the derivation is a relaxation, so Q_cut is a lower bound for
every policy (proof in the cut bound, validated on every episode of the study:
section 6 of benchmark-methodology.md). A queue
that no policy can avoid, at an exit or at a door, is therefore not charged
to Time. A queue that a policy causes, for example by sending everyone to one
exit when a second exit is free, is charged
(test_real_episode_unavoidable_door_queue_is_not_charged,
test_real_episode_avoidable_queue_is_charged).
Congestion is not a score input. Version 1.0 at commit ce5e322 had a
Coordination component (1 - block rate)^2 and a severe gate at a block rate
above 1/4. It was removed, because a blocked move is an action-log event, not
a trajectory event:
- The scrub proof. Under the public movement resolver, a person whose move
is blocked by another person (occupied, conflict or cycle) stays in place.
If that move is replaced by
STAY, the person still stays in place. Every other person's resulting cell is unchanged too: a blocked person never vacates its cell and never takes a target cell, so no successful move depends on it, and every move that was blocked behind it is itself scrubbed. So replacing every congestion-blocked move withSTAYgives the identical state trajectory with zero blocks. The resolver is public and pure and its inputs are all in the observation, so any agent can do this. The adversaryadv-block-scrubdoes it tocongestion-aware-v1: identical state trajectories in every study episode, and a gain of several points under the old score (section 6 of benchmark-methodology.md). - No lower bound. The block count has no positive privileged lower bound: the scrub reaches 0 for every trajectory. A ratio "bound / actual" like the other components cannot exist.
- Not a skill. A policy that predicts the resolver's tie-breaks and emits
STAYinstead of a blocked move evacuates the same people at the same steps on the same cells. It is not a better evacuation policy, so the difference must not be scored. - The realized cost is already scored. A bottleneck costs delay (Time,
against
Q_cut), exposure while waiting (Hazard) and, at worst, lives (Safety). Every trajectory-only congestion measure tried (waiting steps above the capacity-forced delay, excess person-time overQ_cut) is a function of the Time and Path inputs, so it would count the same delay twice. - Dead people are not charged twice. The blocked moves of people who later die were part of the old block rate, and their deaths are in Safety. Time, Path and Hazard are over evacuees only, and blocks are not an input, so no loss is charged twice.
Congestion stays mandatory in every report as diagnostics
(the score report diagnostics, congestion diagnostics): congestion block rate,
contested cell-steps, hotspot cells, peak contested cells and exit throughput
(evacuations per exit-step inside each exit's active window). They explain a
score; they never change it (test_congestion_blocks_are_diagnostics_not_score_inputs).
Exit utilization is diagnostic only. A balanced split between exits is not a goal: the right split depends on distances, fire and capacity. The capacity bound already measures the only effect of exit allocation that the score needs, the time cost of a bad allocation, against an allocation-optimal bound. A separate balance or allocation-regret term would count that cost twice.
Route-invalidation event. At step t >= 1 the burning set changed and,
for a person active in snapshot t, the fire-aware distance to the nearest
non-burning exit (shortest path through non-wall, non-burning cells) became
longer or infinite, where it was finite before. The event is recoverable
when L(x_e, t) is finite. Its resolution step r_e is the person's
evacuation step, or the horizon H when the person is lost (censored). An
unrecoverable event is counted but not scored: its outcome is already in
Safety.
Quality is the weighted geometric mean over the defined components, with the weights renormalized over them:
Quality = exp( sum_k (w_k / W) * ln q_k ), W = sum of the weights of the defined components
Quality = 0 when any defined component is 0
An undefined component is never set to 1. It is left out, and its weight is shared by the others. So an episode without route invalidation is neither rewarded nor punished for replanning.
Path uses the fire-aware privileged bound m*_i, so a detour that the fire
makes necessary is not charged. Hazard is measured above the privileged
minimum D*, so exposure that no policy can avoid is not charged. Neither
component counts the same loss as Safety: both are computed over evacuees
only.
4.3 Quality exponent and severe failures
Two rules make Safety dominate without making Quality irrelevant.
Quality exponent beta. Quality enters as Quality ^ beta, with
beta = min(1, ln(alpha_c) / ln(q_min)), q_min = smallest severe threshold in component space
beta is derived, not tuned. With every quality component at or above its
severe threshold, Quality >= q_min, so Quality ^ beta >= alpha_c = 0.6.
A perfect run with one avoidable casualty has Safety < 0.6. So a run with
no avoidable loss and no severe failure always scores above a perfect run
with one avoidable casualty, in every population (requirement R12, tested
for M* from 2 to 1000, also with one extra stranded person on both sides).
Severe failures. A quality component is severe when it crosses a threshold in natural units. The comparison is exact and strict:
| Component | Severe when | Threshold in component space q_k_severe |
|---|---|---|
| Time | T < 1/2 (more than twice the capacity bound Q_cut) |
0.5 |
| Hazard | avoidable danger-zone rate > 1/4 |
1 - 1/4 = 0.75 |
| Path | P < 1/2 (more than twice the fewest cells) |
0.5 |
| Replanning | R < 1/2 |
0.5 |
Each severe component k multiplies the score by
phi * (q_k / q_k_severe) ^ gamma, with phi = 0.8 and gamma = 1. So one
severe failure caps the episode below 80, and the cap falls further as the
failure gets worse. Two severe failures cap it below 64. Severity is a
ceiling, not a separate measurement: it applies to the same components that
are already in Quality, and is 1 when nothing is severe.
The report counts severe episode-trials per component
(the severe_episode_trials in the robustness block). The episode record gives severity,
the list severe and the ceiling = 100 * Safety * Severity.
The thresholds are set by normative requirements, not by a policy ranking (see benchmark-methodology.md, section 6): evacuating more than twice as slowly as the capacity optimum, one avoidable danger-zone step in four, twice the needed cells and twice the needed recovery time are each a failure of that dimension. A severe bottleneck is a severe Time failure: it is measured by the delay it causes, not by blocked actions. Mild congestion that the capacity bound explains never triggers a gate.
4.4 Episode statuses
| Status | Meaning | Score |
|---|---|---|
scored |
authenticated, below the gate | 100 * Safety * Quality ^ beta * Severity |
catastrophic |
authenticated, avoidable loss rate >= 1/2 |
0 |
failed |
scheduled, no authenticated result | 0 |
not_applicable |
M* = 0: no policy can save anyone |
excluded from every mean, for every model |
A failed episode has a failure kind: missing (no declared reason),
invalid_output (model output error or another rejected action set),
model_error (the model or its adapter raised) or timeout (the adapter's
deadline expired). All four score 0 and are counted in the report. A failure
can never disappear: a gap without a declaration is missing. A declaration
for an unscheduled episode, or for an episode that has a committed result, is
rejected.
not_applicable depends only on the scenario and the seed, never on the
model.
4.5 Arithmetic
Counts and references are exact integers. Non-integer powers are computed
with Python decimal (libmpdec) at 50 significant digits, round-half-even,
which gives identical digits on every platform. Components are rounded to
1e-12 and the episode score to 1e-9 points. From there on every mean and
every bootstrap statistic is exact rational arithmetic.
5. Exact penalties and ceilings
Single-failure profile under the official constants. Everything else is perfect; replanning is undefined.
| Case (population 100 unless stated) | Score |
|---|---|
| perfect | 100.0 |
| 1 avoidable casualty | 56.5 |
| 2 casualties | 39.4 |
| 3 casualties | 30.0 |
| 5 casualties | 19.6 |
| 10 casualties | 9.1 |
| 25 casualties | 1.6 |
| 1 casualty in a population of 4 | 10.7 |
| 1 stranded | 76.8 |
| 10 stranded | 30.3 |
| 1 savable casualty + 1 unsavable stranded person | 56.5 |
| 50 losses (the gate) | 0.0 |
| Time 0.9 / 0.8 / 0.5 (threshold) | 96.2 / 92.1 / 77.5 |
| Time 0.4 / 0.25 / 0.1 (severe) | 45.7 / 24.0 / 6.8 |
| any block rate, no delay (blocks are diagnostics) | 100.0 |
| avoidable danger-zone rate 0.1 / 0.3 (severe) | 97.4 / 68.4 |
| Path 0.6 / 0.4 (severe) | 93.9 / 57.2 |
| Replanning 0.8 / 0.3 (severe), replanning defined | 96.0 / 38.5 |
| every quality component exactly at its threshold | 64.7 |
Time is relative to the capacity bound Q_cut, so "Time 0.5" is a realized
bottleneck that doubles the evacuees' person-time over the best that any
policy could do. The jump at a threshold is the severe factor phi = 0.8
times the ratio q / q_severe. Below the thresholds, Quality still matters:
Time 0.5 alone costs 22.5 points.
Ceilings that follow from the formula:
- Any avoidable casualty: the episode score is at most
100 * 0.6 = 60, for every population size. - Any avoidable stranded person: at most
100 * 0.8 * (1 - 1/M*)^4 < 80. - No 95 or more after a meaningful safety failure: any avoidable casualty or stranded person gives a score below 80.
- A casualty is worse than a stranding: one avoidable casualty scores below one avoidable stranded person in the same episode.
- Any severe quality failure: below
100 * 0.8 = 80; two severe failures, below 64. A severe failure cannot be bought back by any other component, because no component exceeds 1. - Catastrophic failure: half or more of the people who could be saved are lost: 0.
- Invalid output, model error, missing result: 0.
- Timeout: 0, the most severe penalty.
6. Aggregation
Episodes are aggregated in a fixed hierarchy. Each level is the unweighted mean of the defined values of the level below:
episode-trial -> episode (mean over trials)
episode -> scenario (mean over its applicable seeds)
scenario -> primary family (mean over its scenarios)
family -> overall (mean over families) = the EMBER Score
The primary family is the suite entry primary_family. A scenario counts in one
family only, so a scenario with several families is not counted twice. A
scenario whose episodes are all not_applicable is excluded.
The report also gives the scenario-balanced mean (mean of scenario means) and the micro mean (mean of all episodes). They are diagnostics. The family-balanced mean is the headline: each failure mode weighs the same, and a suite cannot raise a score by adding easy scenarios of one family.
Components, Safety and Quality are aggregated with the same hierarchy over
the episode-trials where they are defined. Each component reports its
coverage defined / total.
Lower tail. The report gives the median scenario score, the worst
scenario and its ID, the type-7 10th percentile of episode scores, CVaR10
(the mean of the lowest ceil(n/10) episode scores), and the number of
zero-score episode-trials by cause (catastrophic and each failure kind).
Totals. Escapable, evacuated, avoidable casualties, avoidable stranded and unavoidable losses, summed over scored episode-trials, also per trial.
7. Confidence interval
The 95% interval of the headline is a stratified two-stage percentile bootstrap:
- Strata are the primary families.
- In each resample, inside each family, draw as many scenarios as it has, with replacement; inside each drawn scenario, draw as many episodes as it has, with replacement.
- Recompute the family-balanced mean. Bounds are the type-7 2.5% and 97.5%
quantiles of
resamples(default 2000) statistics.
The random stream is the SHAKE-256 counter-mode bootstrap stream of statistics.md, seeded with SHA-256 of the canonical JSON of the scoring version, the constants digest, the manifest hash, the model ID and the exact episode scores. The interval is identical on every platform. With fewer than 5 applicable episodes there is no interval.
The interval describes this evaluation sample: these scenarios and these seeds. When a family has one scenario, the bootstrap cannot see scenario variance, and a deterministic model on deterministic scenarios gets a zero-width interval. To make claims about unseen environments, use a generated suite with several scenarios per family (see procedural-generation.md).
8. Comparison and leaderboard
The score comparison pairs two reports episode by episode. The reports
must have the same scoring version, constants, manifest, pack and applicable
episodes. Paired differences d_e = a_e - b_e are aggregated with the same
hierarchy (so delta = score_a - score_b exactly), and the interval is the
same stratified bootstrap applied to the differences. The outcome is one of
four:
| Outcome | Rule |
|---|---|
exact_tie |
every paired episode score is identical |
a_better |
interval lower bound > 0 and delta >= 1.0 point |
b_better |
interval upper bound < 0 and -delta >= 1.0 point |
inconclusive |
anything else, including fewer than 5 applicable episodes |
practical_difference = 1 point is the smallest difference that counts as
"better". A difference that is statistically clear but smaller is
inconclusive.
Leaderboard order is separate from significance. leaderboard_order
sorts by:
- the score rounded half-even to 0.1 point, descending;
- the Safety factor, descending;
- avoidable casualties per trial, ascending;
- avoidable stranded per trial, ascending;
- the worst scenario score, descending;
- the model ID.
So safety decides every tie of the displayed score. Adjacent leaderboard
entries can still be inconclusive; publish the comparison next to the
order.
9. Metric classification
Every existing metric of metrics.md has one role:
| Metric | Role | Use in the score |
|---|---|---|
| evacuated / evacuation rate | core (Safety) | E, relative to M* |
| casualties (fatality) | safety gate and core (Safety) | P_casualty on avoidable (savable) casualties, catastrophic gate |
| stranded | safety gate and core (Safety) | P_stranding on avoidable stranded people, catastrophic gate |
time to safety (time.*) |
core (Quality) and severe gate | T, evacuees only, relative to the capacity bound Q_cut; a realized bottleneck is charged here |
congestion / bottleneck (blocked_*, congestion_block_rate) |
diagnostic only, mandatory in every report | none; an action-log count (section 4.2) |
fire exposure (fire_exposure, min_fire_distance) |
diagnostic | replaced by the avoidable danger-zone rate H (core and severe gate) |
path efficiency (path_efficiency.*, static bound) |
diagnostic | replaced by P with the fire-aware privileged bound (core, low weight, severe gate) |
replanning proxies (recovery_proxy_rate and others) |
diagnostic | replaced by R on route-invalidation events (core and severe gate) |
| exit utilization / balance | diagnostic only | none; a 50/50 split is never rewarded; the time cost of a bad allocation is in T through Q_cut |
| crowd diagnostics (hotspots, contested cells, exit throughput) | diagnostic only, mandatory in every report | none |
| decisions, latency, input/output tokens, cost, retries, timeouts | operational only | none; operational record, see section 11 |
Reasons for each role are in benchmark-methodology.md, section 4.
10. Interpretation: what 70/100 means
- 70.0/100 is 70.0 benchmark-performance points under the scoring version 1.0. It is not "70% of people evacuated".
- An episode with any avoidable casualty scores below 60. So an episode score of 70 means nobody who could be saved died.
- An episode with a severe quality failure scores below 80. So an episode score of 80 or more means no avoidable loss and no severe failure.
- The headline is a mean over families. 70 can be "every family safe with moderate quality" or "seven families perfect and three at zero". The family scores and the lower-tail statistics tell which. Always read them with the headline.
- Anchors on the public suite with the development seeds 0, 1, 2:
congestion-aware-v153.2,fire-aware-shortest-path-v140.4,static-shortest-path-v137.4,nearest-exit-greedy-v127.5,random-legal-v10.0, always-stay 0.0. The privileged bound would score 100 but is not a policy.
A report has this shape (the summary formatter, family list shortened):
EMBER Score 53.2 / 100 benchmark-performance points under EMBER scoring version 1.0
95% CI [50.6, 58.5] (stratified two-stage bootstrap, 2000 resamples; this sample only)
Model congestion-aware-v1; trials 1; official; environment pack <id> sha256:<digest>
Safety factor 0.556; quality factor 0.929
Components (0-1, defined/total): evacuation 0.864 (30/30); casualty 0.590 (30/30); stranding 1.000 (30/30); time 0.936 (30/30); hazard 0.896 (30/30); path 0.932 (30/30); replanning 1.000 (8/30)
Primary families: single_exit_low_density 99.1; single_exit_high_density 31.2; narrow_corridor_bottleneck 95.5; ...
Tail: median scenario 37.7; worst scenario 7.4 (v1-pub-05-central-ignition); p10 episode 16.0; CVaR10 7.4
Zero-score episode-trials 0 of 30: catastrophic 0; missing 0; invalid_output 0; model_error 0; timeout 0
Severe quality failures (episode-trials): time 0; hazard 3; path 0; replanning 0
People per trial: escapable 561.0; evacuated 526.0; avoidable casualties 35.0; avoidable stranded 0.0
Congestion diagnostics (not scored): block rate 0.399; contested cell-steps per trial 1707.0; hotspot cells per trial 447.0; peak contested cells 20; exit throughput 0.776
The EMBER Score is not a percentage of people evacuated.
11. Operational metrics and EMBER-Efficiency
Tokens, money and latency are never inputs to the score. The scoring step has no parameter for them. Record them in an operational record, next to the score:
| Field | Meaning |
|---|---|
model_id, provider_id |
the exact model snapshot and the provider |
| Inference configuration digest | Inference configuration digest: SHA-256 of the canonical JSON of every inference setting (temperature, top-p, max tokens, seed if any, system prompt version, adapter version) |
trials, episodes |
the work the record covers |
latency_seconds |
evaluator-measured wall time |
input_tokens, output_tokens |
kept separate, never summed |
cost, cost_unit |
evaluator-computed cost (exact fraction) and its unit; None when unknown |
retries, timeouts |
adapter retries and expired deadlines |
The record is validated (no empty IDs, a 64-hex digest, non-negative finite
values) and has its own digest. efficiency_view(report, cost_per_episode, unit) gives an optional EMBER-Efficiency view: points per unit of
evaluator-measured cost. It does not change the score or the order.
12. Model stochasticity
A deterministic policy needs one trial. A model that can give different
actions for the same observation (any sampled LLM) needs K >= 3 repeated
trials on the same pack, with pinned inference settings (one
inference configuration digest). temperature = 0 is not a guarantee of
determinism: batching, kernel choice and provider changes can alter outputs.
Every trial is scored; the best trial is never selected. Each episode's
trials are averaged before aggregation, so trials never count as extra
scenarios. The protocol is in environment-pack.md,
section 6.
13. Relation to the metrics rules
metrics.md, section 11, requires a composite to be versioned, decomposable, and to never let speed buy safety. Version 1.0 meets all three:
- It has its own version and constants digest, and every report holds the components, the severe-failure list and the per-person evidence.
- Within one episode, a run with no avoidable loss and no severe quality failure always scores above a perfect run with one avoidable casualty (section 4.3). Speed can only help a run with a casualty against a safe run that itself fails a dimension severely, for example one that evacuates more than twice as slowly as the capacity bound. Such a run is not "safe and good"; the severe gate makes that explicit.
- Leaderboard ties of the displayed score are always broken by safety first (section 8).
Reviewed public benchmark contract. Apache License 2.0. Download Markdown