AGGRO_THREAT_SYSTEM_DESIGN.md

music/AGGRO_THREAT_SYSTEM_DESIGN.md

The Engagement Ledger — aggro, threat, packs, leash and elites

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.

0. Why this exists, and what it unblocks

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.

1. The adjudication that has to happen first

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.

2. The architecture in three layers

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.

3. Layer 1 — the entry test, as data

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):

columnshapegrammar axisnote
threat_model_kindenum {proximity, ledger, hybrid}AGG-G1, AGG-G22required, no default; §1 Option C
aggro_radiusdistanceAGG-G2authored per row, never a class default
aggro_power_slopedistance per power step, signedAGG-G2the alertness dial: a dangerous zone announces itself by being more ALERT before it is harder to kill
aggro_radius_floor / aggro_radius_ceilingdistance pairAGG-G2floor never below melee reach
damage_detect_radiusdistanceAGG-G4the SECOND radius; this is what makes a ranged opener a decision
detection_channelset {sight, sound, scent}gap register 1reuse the shipped Cloaking / Ebu-Gogo stalk channels rather than minting a parallel one
vertical_aggro_weightmultiplier on Z separationAGG-G3greater than 1, so a ledge is cover
leash_anchor_kindenum {spawn_point, patrol_route, encounter_volume, none}AGG-G12a patrolling body must not snap to a pin it left minutes ago
leash_radiusdistanceAGG-G12per creature, not per class
assist_radiusdistanceAGG-G15, AGG-G16DISTINCT from aggro_radius; that distinctness is the point
assist_delay_msdurationAGG-G16must be greater than zero — see §6
assist_gate_predicateexpression over family / faction / trophic_roleAGG-G15probability DECAYS with distance rather than a hard ring
family_roleenum {swarmer, bruiser, ranged, summoner, exploder, resurrector, buffer, controller, tank}AGG-G29the combat role; trophic_role (156/187) is ECOLOGICAL and is not this
approach_profileenum {burrow_ambush, leap_closer, hold_distance, pre_sight_charge, task_locked, shamble}AGG-G30arrival-time variance is the feel; a synchronized charge is the tell of a missing layer
engagement_flagsbit set: never_aggro, cannot_enter_combat, taunt_immune, obeys_taunt_dr, ignores_threat_drop, is_boss, holds_distanceAGG-G17the 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.

4. Layer 2 — the ledger, on the encounter grammar

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.

level 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).

guards. 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.

Composure 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.

5. Layer 3 — the exit contract

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.

creature 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.

6. Packs — the cheapest fun in the whole spec

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.

7. Elites — a behaviour lane, on the rarity ladder

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.

(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.

ladder 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.

8. What this spec deliberately does NOT build

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.

disciplined; 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.

9. Build order for the next Source window

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.

10. The teeth that arm with it

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:

parity. Equality is the defect [AGG-C5].

diminishing 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].

11. Player-surface discipline

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.

12. Provenance

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.

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.

Generated by harness/site/structure_site.py — the URL path is the repo path. review root