music/AGGRO_THREAT_SYSTEM_DESIGN.md
CANON SUBORDINATION — this document is PROPOSAL-TIER: it serves canon and never outranks it.
The canon: the CVD · the T1 foundation docs · the T0 registries (registries/) · the spine
(docs/spine/CH_*.md) · the region pages (_source/02_Tier_2_Region_Pages/). Authority order:docs/DOC_MAP.md§ 0.
Canon served (scanned from this document's own citations — widen it by hand where it is thin):
T0_Composure_Routing·T0_Creature_Roster·T0_Elite_Modifier·T0_Imprint_Affix· (+1 more t0)
READ THAT CANON FIRST — open it and derive from it before you build anything from this document.
If this document disagrees with canon, CANON WINS and this document is the defect — fix the
document, never the canon. Nothing here is applied until it is ratified into canon.
STATUS: PROPOSAL-TIER (2026-08-05). Design only; no canon flips, no magnitudes.
OWNER OF THE BUILD: the next Source-window engine lane (wave 14 holds Source today).
SCORED BY: harness/qa/comparator_rubrics/aggro_threat.json (gate 51), checks AGG-C1..C16.
Josh, 2026-08-05, verbatim: *"What about the world of warcrsft and Diablo 4 aggro and combat and
Witcher 3 and red dead redemption and monster Hunter wilds feel"*.
The music failure is the reason this document is a spec and not a note. Fourteen themes shipped
scored against proxy metrics with no comparator anchor, and the backstop heard what the proxy
could not. A teacher named in a ruling and never armed as a tooth is decoration. So the three
grammars were emitted into gate 51's roster first, the current build was scored against them
honestly, and this design is written against the axes that came back BELOW or UNMEASURED.
THE GATE-MORATORIUM CLAUSE (the standing law of 2026-08-05 requires a new instrument to name the
shippable artifact it unblocks in the same sentence): the aggro_threat rubric unblocks THIS —
a per-creature engagement layer that makes every non-boss body in the Flores slice a designed
encounter instead of a spawned prop, which is the difference between nine creatures standing in a
field and a zone that can be pulled, fought and escaped. The instrument leg is already spent; what
follows is the creation leg.
THE HONEST STARTING LINE, measured 2026-08-05 and not softened: on the shipped B01 guardian-kill
run, nine enemies were alive, at most two were ever aggroed at any station, and after two of them
were killed at arm's length the aggroed count was zero with seven alive. Nobody answers, nobody
remembers, nobody comes home. Every axis in the aggro_threat rubric scores BELOW or UNMEASURED.
docs/DESIGN_GAP_REGISTER.md entry 1 (Non-boss engagement / aggro spec, MISSING, high) recommends
a solo-scoped engagement spec and says, in terms: No threat table. Josh's ruling names WoW
aggro as a bar. AGG-G1 says a design carrying only the spatial entry test has half a combat loop.
These cannot all be satisfied by ignoring one of them, so they are adjudicated here.
it is what a single-player action RPG usually ships. CON: it fails AGG-G1 outright, and it makes
our own Composure design unreadable to the enemy — a player who breaks a Composure node by
solving an arena interlock deals no damage, so nothing about them is legible to a
proximity-only chooser. The puzzle route becomes tactically invisible.
a raid subsystem into ambient fauna, and 187 roster rows would each need arithmetic no solo
build can tune. The register's objection is correct at this scale.
itself becomes data: threat_model_kind in {proximity, ledger, hybrid}, which is AGG's own
measurable axis and AGG-G10's opt-IN grammar generalised. Ordinary fauna stay PROXIMITY, which
is Diablo's legitimate answer (AGG-G22) and costs nothing. Authored encounters — packs, elites,
bosses, anything the level designer declares a pull unit — carry the LEDGER. The register keeps
its cheapness where it argued for it, Josh's bar is met where the fight is designed, and the
defect AGG-G22 actually warns about (picking NEITHER answer completely) is closed.
THE STRONGEST OBJECTION TO C, stated rather than hidden: two target-selection paths in one build
is two things to debug, and a creature whose family is mis-declared will feel wrong in a way that
reads as a bug rather than a design. The mitigation is that the enum is REQUIRED per family with
no default — an undeclared family fails the gate rather than silently inheriting proximity — and
that the two paths share one target-choice entry point, so only the scoring differs.
The grammar's own split, kept intact:
The three are separable and shippable in that order. Layer 1 alone already changes how the slice
plays; layers 2 and 3 are what make an over-pull a mistake with an exit rather than a death.
ENGINE vs CANON, declared per the standing law: layers 1-3 are ENGINE (a row-keyed engagement
model with a policy gate is game-agnostic and reusable). CANON is the DATA only — which creature
carries which radius, which family is a pull unit, which body may be fought at all.
Today AggroRadius, AggroHalfAngleDeg, DeAggroRadius, LeashRadius and bRequireLineOfSight
are UPROPERTY defaults on AHumanityEnemyCharacter, shared by the whole bestiary
[measured: AGG-C2]. T0_Creature_Roster is 187 rows across 58 columns and carries no aggro,
detection, leash or territory column at all [measured 2026-08-05, positive-controlled sweep].
MINT on T0_Creature_Roster (and mirror into DT_CreatureRoster, which already round-trips at
187/187 with zero drift):
| column | shape | grammar axis | note |
|---|---|---|---|
threat_model_kind | enum {proximity, ledger, hybrid} | AGG-G1, AGG-G22 | required, no default; §1 Option C |
aggro_radius | distance | AGG-G2 | authored per row, never a class default |
aggro_power_slope | distance per power step, signed | AGG-G2 | the alertness dial: a dangerous zone announces itself by being more ALERT before it is harder to kill |
aggro_radius_floor / aggro_radius_ceiling | distance pair | AGG-G2 | floor never below melee reach |
damage_detect_radius | distance | AGG-G4 | the SECOND radius; this is what makes a ranged opener a decision |
detection_channel | set {sight, sound, scent} | gap register 1 | reuse the shipped Cloaking / Ebu-Gogo stalk channels rather than minting a parallel one |
vertical_aggro_weight | multiplier on Z separation | AGG-G3 | greater than 1, so a ledge is cover |
leash_anchor_kind | enum {spawn_point, patrol_route, encounter_volume, none} | AGG-G12 | a patrolling body must not snap to a pin it left minutes ago |
leash_radius | distance | AGG-G12 | per creature, not per class |
assist_radius | distance | AGG-G15, AGG-G16 | DISTINCT from aggro_radius; that distinctness is the point |
assist_delay_ms | duration | AGG-G16 | must be greater than zero — see §6 |
assist_gate_predicate | expression over family / faction / trophic_role | AGG-G15 | probability DECAYS with distance rather than a hard ring |
family_role | enum {swarmer, bruiser, ranged, summoner, exploder, resurrector, buffer, controller, tank} | AGG-G29 | the combat role; trophic_role (156/187) is ECOLOGICAL and is not this |
approach_profile | enum {burrow_ambush, leap_closer, hold_distance, pre_sight_charge, task_locked, shamble} | AGG-G30 | arrival-time variance is the feel; a synchronized charge is the tell of a missing layer |
engagement_flags | bit set: never_aggro, cannot_enter_combat, taunt_immune, obeys_taunt_dr, ignores_threat_drop, is_boss, holds_distance | AGG-G17 | the whole behavioural range as columns, so a hundred creatures ship without a hundred scripts |
THE CARE WIRE, non-negotiable: engagement_flags.never_aggro and cannot_enter_combat are
DERIVED from the existing combat_permission column (70/187) and the care rows behind it, never
authored by taste. The engagement layer may narrow what can be fought; it may never widen it. Gate
52 permission_pairing already owns that asymmetry and this spec adds no path around it.
ENGINE CHANGES, Layer 1: AHumanityEnemyCharacter reads the row instead of its own defaults;
the perception test gains the Z-weight term (AGG-G3) and the second radius (AGG-G4). Both are
small, local, and independently testable.
The ledger instance belongs to the ENCOUNTER, not to the world and not to the pawn. The shipped
AHumanityEncounterVolume is already the right home: it is a placeable, deterministic, roster-keyed
encounter with an authored entry list, and it already refuses to spawn outside CVD Pillar 1's three
declared random systems.
combat start and cleared on combat end [AGG-G5]. The volume's lifetime is the encounter's
lifetime, so the list has no owner problem to solve.
FHumanityEncounterEntry gains linked_pull_set_id and link_symmetry [AGG-G15]. This is thelevel designer's actual encounter unit: a designer-declared set that joins regardless of radius,
and asymmetric links must be expressible (A pulls B while B does not pull A).
AggroMagnet, RiftInstability, HunterTrigger) stay refusingguards. This spec gives a future Aggro Magnet something to READ; it does not build it, and
nothing here spawns.
THE WRITE GRAMMAR, and this is where our design leaves the teachers behind. WoW's ledger converts
damage and healing [AGG-G6]. Ours must convert every verb that can break a Composure node, or the
whole Pillar-8 design is invisible to the thing it is aimed at: a player who breaks the
puzzle_routed node by aligning an arena interlock deals zero damage and would be, to a
damage-only chooser, the safest person in the room.
ability_class row in T0_Composure_Routing carries a threat coefficient alongside theComposure node it already routes to [canon: COMBAT_ENCOUNTER_SYSTEM §5; the table exists and
covers 137 of 185 ability rows today].
rule: a heal or a ward observed by several bodies divides across the observers, which is exactly
why a support player pulls a pack rather than one body.
companions and familiars are the bodies this applies to.
TARGET SWITCHING runs on hysteresis, never a tie [AGG-G8]: a melee steal threshold and a ranged
steal threshold, both above parity, with RANGED STRICTLY GREATER THAN MELEE. Magnitudes are Phase-5M
tuning and are not authored here; the STRICT INEQUALITY is the invariant, and it is the one tooth
that can be armed the day the columns land. Equality collapses the whole dance into a coin flip.
CORRECTION TOOLS: a taunt-analogue is a hard WRITE (set my threat to the current highest) plus a
short forced fixate, leaving the user at PARITY rather than ahead [AGG-G9] — a correction, not a
damage button. Diminishing returns are OPT-IN per creature [AGG-G10]: ordinary world creatures stay
fully answerable and the tax is paid only on authored encounters. A threat ERASE class exists and is
distinct from the reduce class [AGG-G11], because a full drop is what makes the split pull a verb
rather than an exploit.
DEFERRED WITH ITS REASON: the D4 taunt-as-CC-status path [AGG-G22, AGG-G23] is NOT built, because
choosing it would require the whole CC economy in the same wave — multiplicative resistance, a
control-immune conversion, and a player-side clear — and half of it is worse than none. Our
Composure/Stagger machinery is the natural conversion target if the design ever moves that way,
and that is recorded here so the option stays open rather than forgotten.
The leash today is one line: past LeashRadius, steer home. Measured against the four-part
contract [AGG-G12] it scores 1 expressed, 2 vacuous, 1 absent — no aggro list to clear because
none exists, no untargetability or immunity while returning, no out-of-combat regeneration (only
PoiseRegenPerSec, which is always on), and it aggroes nobody en route only because nothing
answers anyway.
Complete all four, plus:
A long pull becomes a skill (keep touching it) instead of an arbitrary wall.
leash_suspend_scope names the space kinds where leashing is off by design [AGG-G14]. Onecreature grammar then reads as "open world escapable, interior committed" without a second
system — and our realm interiors and hard-line spaces are exactly the places that should commit.
exits [AGG-G32]. Today two exist by arithmetic rather than by design (the leash return and the
line-of-sight break), and one of the two is the incomplete contract above. Density without a
named exit is not difficulty, it is noise.
The assist call is DELAYED, not instant, on a radius distinct from the aggro radius [AGG-G16]. That
delay is the entire reason an over-pull is recoverable: it hands the player one beat to break
sight, control a body or commit before the neighbours do. The reference implementation the grammar
cites ships a delay and a wider radius while fleeing; our values are Phase-5M tuning, the SHAPE is
what this spec fixes.
Two mechanisms, not one [AGG-G15]: co-aggro is probabilistic and decays with distance, gated on
shared family or faction; linked aggro is the designer's declared set and ignores radius entirely.
The first is what makes a world feel socially alive; the second is what a level designer actually
places.
Families are ROLE SETS, not reskins [AGG-G29]: a family declares at least three complementary
roles and the kill-priority its own composition teaches. Approach behaviour is a per-archetype
personality [AGG-G30], and the measurable form is arrival-time VARIANCE across one alerted pack —
a synchronized charge is the tell that the layer is missing. Our build already ships two genuine
approach personalities (the timid Flee state and the Ebu-Gogo Stalk standoff), so this is an
extension of a shape that exists rather than a new one.
RANGED ARCHETYPES DO NOT CLOSE of their own accord [AGG-G19]. Without at least one such archetype
per mixed pack, the corner pull is decoration and the terrain is scenery — and our arenas are
authored terrain with a 225-row affordance registry behind them, so this is the cheapest way to
make that registry pay.
Elite affixes are BEHAVIOUR modifiers, not stat modifiers [AGG-G27]: each is a small geometry or
tempo rule carrying its own duration AND cooldown, and stacking a few on one body manufactures a
novel encounter out of an existing monster. It is the cheapest encounter-variety multiplier in the
genre, and for a solo build that is the whole argument.
A CATEGORY CORRECTION, measured rather than assumed: our existing rarity machinery is ITEM-side.
T0_Rarity_Grade (13 rows) is an item rarity ladder and T0_Imprint_Affix (5 rows) is a gear
imprint vocabulary keyed to runes and item tags. Neither is a body-behaviour lane, so the elite
lane is new construction that REUSES the ladder rather than an extension of the affix table.
T0_Elite_Modifier, one row per modifier, every row carrying BOTH a duration and a cooldown (a modifier with no cooldown is a permanent stat, not a behaviour), a geometry_class drawn from
{denies_space, denies_range, repositions_enemy, repositions_player, adds_bodies, adds_hazard,
buffs_neighbours}, and a repricing_class naming which of {kill_order, pull_size, pull_spacing}
it changes [AGG-G21]. A modifier that changes none of the three is decoration and fails.
rarity_token_min FKs to T0_Rarity_Grade.rarity_token, so the elite TIER axis reuses theladder the itemization lanes already ratified instead of minting a second vocabulary. This is
the "elite modifiers via the rarity lanes" wiring, done honestly.
distance is a free win.
durability [AGG-G28]. One silhouette carries the read.
counted enemy-forces target AND a clock in the same mode; we have clocks and no count. This is
endgame-shaped work and it is recorded, not started.
genuinely good fit for our Withdrawal clock and it is a second system; one at a time.
vril_density dial exists and isdisciplined; per-encounter-space density with an owner and a change log is deferred. Note the
live defect it inherits: spawn_rate is blank on the slice roster rows, and the encounter volume
correctly FLAGS that rather than inventing a rate.
restated as ours; our values are authored at Phase-5M tuning behind the firewall.
Sequenced so each step is independently playable and independently scoreable. Each step names the
rubric check it moves off UNMEASURED.
1. THE COLUMN BLOCK. Mint the §3 columns on T0_Creature_Roster, refresh the fidelity baseline in
the same commit, mirror to DT_CreatureRoster. Canon-side, no engine dependency, runnable
before the Source window opens. → arms AGG-C2, AGG-C14, AGG-C15.
2. THE PAWN READS THE ROW. AHumanityEnemyCharacter takes its radii from the row; add the Z-weight
term and damage_detect_radius. → AGG-C3, AGG-C4.
3. THE LEASH CONTRACT COMPLETED, plus the hit-resets-the-clock rule and leash_suspend_scope.
→ AGG-C6.
4. THE ASSIST CALL. Delayed, on its own radius, with the decaying-probability predicate. This is
the highest fun-per-line item in the list and the one the B01 run measured at zero. → AGG-C7.
5. THE LEDGER ON THE VOLUME. Per-NPC lists, the coefficient block including non-damage writes, the
steal hysteresis pair, the taunt-analogue write and the erase class. → AGG-C1, AGG-C5.
6. LINKED PULL SETS on FHumanityEncounterEntry, with asymmetry expressible. → AGG-C8 partially.
7. T0_Elite_Modifier and the elite flag on the encounter entry. → AGG-C10.
Steps 1 and 7 are canon-side and need no Source access at all. Steps 2-6 are the Source window.
The rubric is written so the build makes it go green rather than the reverse. Two invariants are
armable the day their columns land, and both are strict rather than presence checks:
steal_threshold_ranged strictly greater than steal_threshold_melee strictly greater thanparity. Equality is the defect [AGG-C5].
obeys_taunt_dr set on authored encounters only, never globally [AGG-G10, AGG-C5]. A globally-ondiminishing ladder is a defect, not a difficulty setting.
Two more become countable rather than assertable: the four-part leash completeness [AGG-C6] and the
per-space recovery-affordance count [AGG-C13].
Threat, aggro, assist and pull-unit tokens are INTERNAL routing, exactly like the Composure node
and mode tokens. They never reach a player surface, per the standing no-mode-taxonomy rule: the
player meets a creature by name and behaviour, and learns that the loud one brings friends by
watching it happen, never by reading a threat number. The debug HUD is the only place these values
are legible, and a QA verdict that claims a player-legible behaviour off a HUD string is making the
named false-claim this repo already has a tooth for.
docs/FACTORY_CONTINUATION.md.
harness/qa/comparator_rubrics/aggro_threat.json, whose mechanisms array is the citable form
and whose known_limits records that the teacher's seasonal and emulator-derived NUMBERS are
reference shapes, never retail truth. Every tooth here reads a shape.
docs/DESIGN_GAP_REGISTER.md entry 1.AHumanityEnemyCharacter, AHumanityEncounterVolume, T0_Creature_Roster, T0_Composure_Routing, T0_Rarity_Grade,
T0_Imprint_Affix, and the loop-QA enemies_aggroed counter that measured the starting line.
of 2026-08-05 in the game repo's QA/bench/, and a positive-controlled column sweep of all 75
registry CSVs.