FORKB_ANALYSIS_ENGINE_SCHEMA_2026-07-27.md

pipelines/FORKB_ANALYSIS_ENGINE_SCHEMA_2026-07-27.md

FORK B — ENGINE + SCHEMA + QA AXIS

The death-choice direction (Josh, 2026-07-27): what is ACTUALLY required

Read-only deep dive. Canon repo C:/dev/humanity-forgotten, game repo C:/dev/Humanity/Humanity.

Every claim below is positive-controlled: an absence-claim is stated only where a search that COULD

have matched returned zero, and the control hit is named.

---

0. HEADLINE: the direction is 80% ALREADY CANON and 0% ENGINE

Two findings dominate everything else in this analysis.

FINDING 1 — the resurrection capability is ALREADY RATIFIED CANON. It was never absent.

registries/T0_Ability_Tree_Registry [ACTIVE v0.1]/Sheet1.csv (185 rows) carries three revival rows

and five healing rows today:

ability_idnameclassbandtierprereqcostEAM
A_A_009Breath of LiferevivalL15.0 PhilosophusVril Healing T5 PhilosophushighEAM-on-bonded-Heart
A_C_003Vril RevivalrevivalL1,L25.0 PhilosophusVril Healing 70-99 PhilosophushighEAM-on-bonded-Crown
A_C_004Vril Mass Revivalrevival_aoeL17.0 Adeptus_MajorVril Revival 100 Adeptus MinorextremeEAM-on-bonded-Crown
A_C_002Vril HealinghealingL1,L24.0 PracticusCh_06 Sri Lankamedium
A_W_007 / A_W_014 / C_P_003 / C_V_004healing lanehealing / healing_aoeL1 or L1,L23.0-7.0

Prose authority: _source/01_Tier_1_Foundation/T1_Ability_Tree [ACTIVE v1.4].md L848 (Breath of Life),

L922 (Vril Revival), L924 (Vril Mass Revival), L936 (Collective Surge). All three revival entries read

the same shape: *"restores a downed ally to combat consciousness with reduced vitality."*

Consequences that must be carried into any brief:

zero engine representation and zero player-side representation today.

a contradiction, it is a second direction of the same verb — but the two directions carry *different

rules* (canon revival is explicitly IN-combat: "returns to combat consciousness"; Josh's ally→player

revival is OUT-of-combat only). If the schema does not express the asymmetry, a future author will

collapse them and silently legalise in-combat player rez.

invention, it is a Phase-5M magnitude on an existing ruled shape.

needs minting is the **caster-eligibility dimension, the downed-player state, the choice surface,

the ledger, and the out-of-combat detector** — not the ability.

FINDING 2 — there is NO ALLY RUNTIME. Not partial. Zero.

Positive control over C:/dev/Humanity/Humanity/Source/Humanity (.h + .cpp, Intermediate excluded):

6 in Private/Quest/GeneratedWorldstateSchema.cpp (the WS_companion_roster_state /

WS_companion_loyalty_transition_events gameplay tags + schema entries),

Public/Data/ChapterIndexRow.h:31 companions_present,

Public/Data/InscriptionSpineRow.h:31 companion_modality,

and the two tag declarations in Public/Quest/GeneratedWorldstateSchema.h:44-45.

~20 hits and not one of them is a companion creature. They are all the boss **composure node

named "Familiar"** — Ability.Mode.Familiar (a verb mode), Composure_Familiar (an attribute on

UHumanityAttributeSet), Boss.Composure.Node.Familiar.Broken, UHumanityFamiliarAbility (a verb

ability class). An agent grepping "Familiar" in Source will conclude familiars are built. They are

not. Nothing about the 22-slot familiar roster exists in the engine.

a bare AAIController whose header states its only jobs are to exist and offer a nav passthrough) and

AHumanityBossCharacter. There is no ally pawn, no ally ASC, no ally AI, no party frame, no order channel.

canon side is rich; the engine side is empty. The search was capable of matching.

So: the direction is a CANON ACTIVATION on one side and a GREENFIELD SUBSYSTEM on the other.

The revive is not "a feature on top of companions" — companions are the feature, and revive is one

consumer of them.

---

1. THE SHIPPED DEATH SHELL — read line by line

Source/Humanity/Private/Core/HumanityCharacter.cpp, Public/Core/HumanityCharacter.h.

Binding (.cpp L216-232, in the possession path, guarded by bDeathDelegateBound because the

method runs on BOTH PossessedBy and OnRep_PlayerState): a Health-change delegate; Health ≤ 0 →

HandlePlayerDeath(). RespawnFallbackLocation captures the spawn point.

HandlePlayerDeath() (L280):

1. bPlayerDead = true.

2. PendingDeathConsolation = ResolveActiveFightConsolation() (L236) — iterates AHumanityBossCharacter

actors, returns the active boss's death_reward line if !Boss->IsDefeated() OR

Driver->IsCurrentSubBossEncounterStaged(). Logged to UCombatTelemetrySubsystem as

player_death_consolation.

3. StartCameraFade(0→1, DeathFadeSeconds, Black, bHoldWhenFinished=true).

4. SetTimer(RespawnTimerHandle, &RespawnAtNearestSite, DeathFadeSeconds + RespawnHoldSeconds).

RespawnAtNearestSite() (L321):

1. TActorIterator<AHumanitySiteMarker>nearest by squared distanceGetArrivalPoint(),

else RespawnFallbackLocation. SetActorLocation(..., ETeleportType::TeleportPhysics).

2. AttributeSet->SetHealth(GetMaxHealth()) — the comment literally reads

*"Restore Health to full (direct set -- the resurrection, not a GE)."*

3. Fade back in; bPlayerDead = false; arm ConsolationShownUntil for ConsolationDisplaySeconds.

Constants (all declared ILLUSTRATIVE under the Phase-5M tuning firewall, TODO_CANON L231/L242):

DeathFadeSeconds = 0.55, RespawnHoldSeconds = 0.9, ConsolationDisplaySeconds = 6.0.

Total blackout ≈ 1.45 s, no input accepted.

What the shell therefore does NOT have

Required by the directionReality todayControl
A checkpointNone. grep -rn "Checkpoint" over Source → 0 hits. Respawn target is the nearest arrival monument (AHumanitySiteMarker, a quest-beat trigger), picked by distance.grep, 0
A save on deathNone. UWorldStateSubsystem::SaveAsync/SaveSync/LoadSync and UQuestSaveGame exist and work — HumanityCharacter.cpp calls none of them.grep `SetValue\Save` in HumanityCharacter.cpp → 0
A world delta on death ("death ADVANCES the world")None written. Boss state "persists" only because nothing resets it — that is session scope, not persistence. VOL2 SL-1 specifies a graduated ws.* delta on death; it is unbuilt.grep death in Private/Quest + Private/WorldState → 0
Any player choice at HP 0None. A timer, not a prompt.code read
A downed state distinct from deadNone. HP 0 → full-health teleport, one path.code read
A 1-HP protected clamp on the PLAYERNone. The clamp is on AHumanityBossCharacter only (IsDefeatProtectedFromData(), IsCanonDefeatProtected()). A protected chapter today still kills the player.header read

The blocking realisation: "revive at last checkpoint" has no checkpoint to revive at. The

checkpoint system is a prerequisite of the direction, not a detail of it — and it is BUILD-NOW-sized.

---

2. THE OUT-OF-COMBAT DETECTOR — the hardest engineering problem here

There is no global combat state. grep -rn "bInCombat\|IsInCombat\|CombatActive\|AnyEnemyAggroed"

over Source → 0 hits. Combat is an emergent property of per-pawn state today. Every available

signal, and every defect it carries for *this* use:

AHumanityEnemyCharacter (Public/Core/HumanityEnemyCharacter.h L49-93):

enum class EHumanityEnemyState : uint8 { Idle, Patrol, Pursue, Attack, Flee, Return, Stalk };
bool IsAggroed() const { return bPerceivedThisFrame || State == Pursue || State == Attack || State == Flee; }

"combat" open indefinitely. A revive-wait gated on !IsAggroed() would never resolve near timid fauna.

at a standoff reads as out of combat. That is precisely the horror beat where a revive window is

most wrong — and it would open.

already uses DeAggroRadius hysteresis for its own state; the detector needs its own).

AHumanityBossCharacter: IsDefeated(), IsSubdued(), WasFreed(), IsLockOnTargetable(),

IsComposureBroken(), IsDefeatProtectedFromData().

AHumanityEncounterVolume: the resolution signal ("all staged enemies defeated") already binds the

sub-boss beat; UHumanityQuestSliceDriver::IsCurrentSubBossEncounterStaged() is the quest-side read.

BUG-0018's teardown semantics — the emptiness-provenance trap

Public/Combat/HumanityEncounterVolume.h L86 + L139, Private/…EncounterVolume.cpp L114,

QA/bugs/INDEX.md BUG-0018 (minor / fixed / WS-7). The fix, verbatim from the header:

retire THIS volume's OWN spawned set and disarm the spawn guard … Ownership-scoped by construction
— it walks only the weak refs this volume recorded in SpawnEncounter, so a sibling station's actors
are never touched (a class-wide actor sweep would kill them) … Called from EndPlay … **Deliberately
does NOT touch resolution/meter state** — ResetTransientMeterForCapture owns that.

The trap for a revive-wait window: teardown makes the world *empty of hostiles* without any hostile

having been *defeated*. A naive detector (no live aggroed enemies → out of combat → revive eligible)

flips to ELIGIBLE because the level unloaded, not because the fight ended. A wait window that

survives a scene/level transition would resolve into a revive in a world that no longer contains the

fight. The detector must carry provenance: EmptyBecauseDefeated vs EmptyBecauseRetired vs

EmptyBecauseLeashed. GuardianTeardownOnEndPlayTest already exists as the fixture to extend.

The design consequence nobody can engineer around

Josh's constraint presupposes that combat continues while the player is down. Today it cannot:

enemies steer toward the player pawn every Tick. With the player down there is no target, so every

hostile de-aggros or leashes home within seconds, and "out of combat only" becomes nearly free

the constraint costs the player almost nothing and the drama it is supposed to create does not exist.

Making the constraint MEAN something requires party combat that continues after the player falls:

allies as valid enemy targets, allies that can themselves go down, a fight that can be lost while you

watch. That is subsystem B2 below and it is the true cost centre of this direction.

Recommendation: ship the constraint NOW anyway (it is correct, it is cheap, and retrofitting it

later is expensive), but do not describe it as meaningful until B2 lands. Register-honest reporting.

---

3. THE STATE MACHINE — the full required spec

S0  ALIVE
     │ Health ≤ 0  (existing delegate, HumanityCharacter.cpp L229)
     ▼
S1  HP0_LATCH                      [NEW · atomic, one frame]
     ├─ protected-chapter check → if protected: clamp Health to 1, WITHDRAW, return to S0
     │                             (player-side clamp DOES NOT EXIST today — see §1)
     ├─ capture context: consolation line (existing ResolveActiveFightConsolation),
     │  encounter context, combat-state reading + PROVENANCE, ally roster snapshot,
     │  world position, chapter/site refs
     ├─ enter the DOWNED PAWN CONTRACT (§4)
     └─ append the defeat-ledger row, outcome = PENDING     [NEW · idempotent, once per death]
     ▼
S2  DOWNED_CHOICE                  [NEW · the surface Josh's direction is about]
     │  no timer runs. Input accepted. Strings resolve from data (§5), natural-voice, diegetic.
     ├── choice: RETURN  ─────────────────────────────► S3a
     └── choice: WAIT    ─────────────────────────────► S3b
          (WAIT offered only when eligibility is not provably zero — see the CONTESTED list)
     ▼
S3a CHECKPOINT_RETURN
     fade → teleport to the CHECKPOINT ANCHOR (not "nearest marker by distance")
     → restore vitality → write the WORLD-ADVANCE delta (the Hades loop)
     → arm the consolation window (existing) → ledger outcome = checkpoint_return → S0

S3b WAIT_WATCH                     [NEW · the novel branch]
     │
     ├─ W1 IN_COMBAT_HOLD    combat-state reading = live, provenance ≠ Retired.
     │                       The window PERSISTS and CANNOT resolve. Player may still
     │                       fall back to RETURN at any time (no-dead-end floor).
     │
     ├─ W2 ELIGIBLE          out-of-combat reached (provenance = Defeated | Leashed)
     │                       AND ∃ ally: alive ∧ present ∧ in range
     │                                   ∧ holds a revival capability (§5)
     │                                   ∧ integrity band satisfies the capability's band lock
     │                                   ∧ vril ≥ the cost class
     │                                   ∧ INT tier high enough to NOTICE and ACT (§12 axis)
     │
     ├─ W3 CASTING           ally paths to the body → casts → presentation
     │
     ├─ W4 REVIVED           restore at REDUCED VITALITY (canon: "with reduced vitality")
     │                       → relationship/bond delta on the reviver
     │                       → ledger outcome = ally_revive → S0 IN PLACE (no teleport)
     │
     ├─ W5 EXPIRED/DECLINED  player elects to stop waiting, or the window closes → S3a
     │
     └─ W6 IMPOSSIBLE        provably no eligible ally can ever qualify (all dead/departed/
                             out of range/no capability/band-locked out).
                             MUST fail FAST and honestly — never run a timer out on a
                             player who was never going to be revived. → S3a

The state edges that will actually break, ranked

1. W1 never ends / W1 ends instantly. Both are live today: instantly (§2 — no party combat, so

hostiles disengage) or never (Defect A, a fleeing macaque). Both make the branch a lie.

2. Boss fights make W2 unreachable forever. IsDefeated() persists across respawn by the graduated-

persistence doctrine; a live boss means permanent W1. Players will sit in a dead wait at every boss.

This is probably the *correct* rule (the boss loop must stay a Hades loop) but it must be **stated

and surfaced**, not discovered. Recommend: in a boss encounter WAIT is refused at S2, diegetically.

3. AP_0001 fires on a corpse. T0_Ally_Behavior_Policy row AP_0001 is

ws.integrity_level in [L1,L2] & flag(local.player_health_at_or_below_50)interpose,

autonomy_band=autonomous. A player at HP 0 satisfies "at or below 50." The moment a downed

state exists, the L1/L2 familiar interposes for a dead player forever. Real latent defect; the

downed state must be excluded from the health-fraction predicates, or AP_0001/AP_0002 must be

re-scoped in the same commit.

4. Double-fire on the death delegate. It binds from both PossessedBy and OnRep_PlayerState,

guarded only by bDeathDelegateBound. Any ledger append must be idempotent per death, or a

re-possession produces two rows and the "death advances the world" delta applies twice.

5. Teardown fakes out-of-combat (BUG-0018, §2).

6. The two branches are currently indistinguishable in world state — because nothing is written on

death at all. If both produce the same delta, the choice is cosmetic. A cosmetic choice on a death

screen is meta-collapse (§10 doctrine) applied to the defeat axis.

Recommendation: different CURRENCIES, not different magnitudes. RETURN carries the world-advance

delta (the Hades loop economy, already ruled). ALLY REVIVE carries a relationship/bond delta

instead — the ally spent vril, risk and standing for you, and that is remembered. Neither dominates;

both are real. This is the anti-meta-collapse shape for this surface.

---

4. THE DOWNED PAWN CONTRACT (new, small, load-bearing)

Without it, S2/S3b is a corpse-beating bug. The player pawn while downed must:

enemy and boss already implement the alive-gated form — this is a one-line pattern match),

.cpp L288-295) so hostiles disengage rather than flail,

Declare it ENGINE (reusable) per the engine-vs-canon reuse doctrine every header in this project

already carries.

---

5. SCHEMA — what must be minted, and where each row actually goes

5.1 Capability — NO new ability rows for the L1/L2 lane

A_A_009 / A_C_003 / A_C_004 already exist and are ratified. What is missing is the

caster-eligibility dimension: nothing in the 35 columns of T0_Ability_Tree_Registry says whether

an ALLY may hold an ability. Two options:

(protagonist | ally | both), landed as a Vector-C extension in the

docs/registry_extensions.json idiom the WS7 wiring already established. Cheap, declarative,

positive-controllable, and it makes the player→ally / ally→player asymmetry expressible in one place

alongside a revival_direction_scope (to_ally | to_protagonist | both) and an

out_of_combat_only boolean. The asymmetry MUST be schema-expressed or it will be collapsed.

5.2 The "trained or taught" state — canon already has the ladder

Josh's phrase "may have been trained or taught" lands exactly on existing canon:

_source/03_Tier_3_Characters/T3_Familiars_Named [ACTIVE v1.0].md L55 —

*"Familiars do not possess vril capabilities at initial bond; vril-integration develops as the player

teaches and imbues the familiar through bonding and training."*

And the Family-B mint already designs WS_012.vril_integration_state = latent | developing | integrated.

Additions:

taught_capability_refs (array → T0_Ability_Tree_Registry.ability_id) and a derived

revival_readiness. Reuse ally_stat_block / int_tier unchanged — **INT gates whether the ally

NOTICES the player is down and acts**, which is the §12 AI axis made load-bearing on a surface the

player will feel. That is the single best argument for this direction: it gives the ruled INT axis

its most legible consequence.

already the teaching ladder.

(grants_class=active). BLOCKER: these rows are COPY-ONLY from T3_Familiars_Named §1.6 —

a revival rung cannot be invented in the registry. It must come from a living-source edit to T3 or a

Josh ruling. Gate 29 tooth B2 (bond-ladder coverage, 22 × 5 = 110) already polices the shape.

5.3 The behavior — T0_Ally_Behavior_Policy is the exact home

21 columns, seed rows AP_0001..AP_0004 live. A revive policy row is a natural fit:

ally_kind, role_tag=ROLE_SINGLE_HEAL (exists in T0_Role_Axis_Registry), a domain value

(today's rows use proactivity / awareness — recommend a new revival value or reuse proactivity),

condition_expr reading the new downed-state key, action_ref=revive_protagonist, int_tier /

unlock_int_min as the §12 gate, autonomy_band=autonomous (Josh's "wait to SEE IF" is explicitly

NOT a player command — it is the ally's own agency, which is thematically the entire point).

policy_source must be canon_seed — Gate 29 tooth B5(ii) makes a player-authored policy row

unspellable by design.

5.4 Worldstate — a LEDGER, following the WS_044 idiom exactly

WS_027 sub-fields are the wrong home for a per-death EVENT. The right shape is the append-only

ledger idiom Family A already ratified for WS_044 bonus_respec_ledger:

<next free WS id>  defeat_resolution_ledger   Family ?   append-only
{ event_id, chapter_ref, site_ref, encounter_ref,
  outcome ∈ {checkpoint_return, ally_revive, ally_revive_unavailable},
  reviver_ref, capability_ref, vril_paid_ref, wait_duration_ref,
  combat_end_provenance ∈ {defeated, leashed, retired},
  world_delta_ref, relationship_delta_ref }

NAMED LANDMINE: MINT_APPLY_CRITIC_2026-07-27.md §A found the applier's APPEND_LEGAL_IDS

frozenset holds twelve ids (`WS_008, WS_010, WS_012, WS_018, WS_019, WS_020, WS_021, WS_026,

WS_027, WS_028, WS_031, WS_034) and that WS_044/WS_046` were landed outside it, with the

deviation self-declared in the rows' own notes. A defeat-ledger row hits the identical wall.

Extend APPEND_LEGAL_IDS in the same commit or the finding repeats verbatim.

(Superseded draft ids to avoid: WS_043/WS_045 per the mint's own supersession record.)

5.5 Build-space — no new axis, but a real balance hazard

ROLE_SINGLE_HEAL / ROLE_GROUP_HEAL and SPEC_VRIL_HEAL_PERSONAL / SPEC_VRIL_HEAL_AREA already

exist (arena=both). Revive is a build inside those axes, not a new axis. But:

**If the ally revive is strictly better than the checkpoint return, every party takes a healer.
That is META-COLLAPSE — the exact failure mode §10 bans — landing on the most emotionally
load-bearing surface in the game.**

The §5.5 sidegrade recommendation (different currencies) is the structural mitigation, and it must be

enrolled in the sweeps (§7) so it is measured, not asserted.

5.6 THE HOLE — the L3/L4/L5 revival lane is canon-declared and EMPTY

T1_Ability_Tree L848, verbatim: *"The integrity gate enforces canonical path discipline; **the L4 and

L5 evil paths access alternate revival mechanics through different element routing.**"*

Enumerated across all 185 rows: heal/revival rows = 8, bands L1 or L1,L2, zero at L3/L4/L5.

Meanwhile 13 L3 rows and 7 L4,L5 rows exist in other classes — so the registry *can* express those

bands and the search was capable of matching. The absence is real.

Three bands wide, not two: L3 Drifting has no healing lane either, and L848 does not even mention L3.

This is a no-dead-end violation waiting to ship. The moment the ally revive becomes a real

affordance, L3/L4/L5 players get a strictly worse defeat loop with no alternative route — a

band-shaped dead end on the death screen. Canon already supplies the mechanism to fix it:

T1_Story_Spine L114 familiar_bond_canonical_framework — *"Familiar bonds form across all integrity

paths. The path determines the bond's nature, not its existence. Abilities are functional across all

paths at chapter-appropriate tier … bad_aligned: … Higher vril-cost for ability access; karmic-debt

residue may accumulate."* The evil-lane revive exists, costs more, and accrues karmic debt. That is a

better design than the good-path version, and it is already canon-shaped. It just has no rows.

---

6. QA TEETH — a Tier-1 test per state edge

Baseline (positive-controlled). 55 UE automation tests exist across

Source/Humanity/Private/QA/*.cpp. The death-adjacent ones are FHumanityDefeatAxisTest,

FHumanityDefeatProtectedDataTest, FHumanitySubdueFreedPathTest, FHumanityEnemyAggroLeashTest,

FHumanityGuardianTeardownOnEndPlayTest. Every one of them asserts BOSS defeat.

There is ZERO player-death test coverage today — the shipped player death shell is untested.

Tools/run_soak.py loops the CAPTURE drive (render/teardown/memory) and has no death-loop coverage

(grep death run_soak.py → 1 hit, unrelated to player death).

New UE Tier-1 tests (one per edge, existing latent-command idiom)

#TestEdge assertedMust-not-fire twin
T1Humanity.Defeat.PlayerDeathChoiceOfferedHP 0 → S2; input acceptedthe 1.45 s auto-respawn timer must NOT be armed
T2Humanity.Defeat.CheckpointReturnPathS3a lands at the CHECKPOINT anchor, not nearest-marker-by-distancea marker nearer than the checkpoint must NOT win
T3Humanity.Defeat.WaitBlockedInCombatW1 cannot resolve with a live aggroed hostile, over REAL ticks
T4Humanity.Defeat.WaitResolvesOutOfCombathostile defeated/leashed → W2 → W3 → W4
T5Humanity.Defeat.WaitImpossibleFailsFastzero eligible allies → W6 → S3a immediatelymust NOT run a timer out
T6Humanity.Defeat.BossFightWaitRefusedWAIT refused/unresolvable in a live boss fight; both killable and protected classes
T7Humanity.Defeat.DownedPawnContractnot lock-on targetable; holds no aggro; does NOT satisfy AP_0001's ≤50% predicatean ALIVE player at 40% HP MUST still satisfy it
T8Humanity.Defeat.TeardownDoesNotFakeOutOfCombatBUG-0018 EndPlay must not flip W1→W2extend GuardianTeardownOnEndPlay
T9Humanity.Defeat.LedgerAppendOnceexactly one ledger row per death, both branches, idempotent under re-possessiona double-bind must NOT produce two
T10Humanity.Defeat.ProtectedChapterNoDeathSurfaceprotected chapter clamps player to 1 HP; S2 never opens
T11Humanity.Defeat.StringsAreDataevery player-facing string resolves from a rowextend FHumanityCH02SpoilerSafeStringsTest

Canon-gate teeth

harness/condition_expr.py (B3), obey disposition legality (B4), and — B5(i) — its condition_expr

must not read a loyalty ws key (behavior quality is a BUILD property, never an integrity property,

§8.11.8). policy_source=canon_seed (B5(ii)).

T0_Ability_Tree_Registry row with ability_class ∈ {revival, revival_aoe} and a satisfiable

integrity_band_lock. Positive-controlled zero (the a-search-that-cannot-match lesson): an

unreachable resolver is reported as unreachable, never as a clean zero — the exact discipline T-A3

already implements in Gate 26.

L3/L4/L5 lane is empty, FAIL (or WARN with the named worklist, scaffold-style). This is the

executable form of the no-dead-end floor for this feature.

out_of_combat_only=true. Josh's constraint made unspellable-to-violate in data.

(T-A6 role derivation, T-A7 pool breadth) plus a dominance tooth — a revive option that is picked in

~100% of sweep-viable builds is a balance DEFECT under §10, symmetrically to a never-picked option.

here once the affordance layer populates; today the gate is a declared scaffold.

Soak

Add a DEATH-LOOP lane to Tools/run_soak.py: N scripted deaths per map, both branches, asserting

no leaked RespawnTimerHandle, no duplicate ledger rows, no actor leak (the BUG-0018 class), stable

peak memory across loops. Cheap, and it covers a path with literally zero coverage today.

---

7. THE MMO BRIDGE — what scales, what stays solo

Read against _source/01_Tier_1_Foundation/T1_Tier_C_MMO_Spec [ACTIVE v1.0].md §8.1-§8.9.

SCALES cleanly — the architecture is already there:

arenas."* ROLE_GROUP_HEAL / ROLE_SINGLE_HEAL need nothing added.

*"all downed allies within range return to combat consciousness simultaneously"*) is a raid rez by

construction. And Collective Surge (T1_Ability_Tree L936, T7, Ch 70-77) explicitly *relays*

Vril Mass Revival across a formation from any linked ally's position — that is a raid-rez-relay

primitive, authored before anyone asked for one.

Josh's rule is the genre-standard rule, arrived at independently.

disasters and intervenes before they cascade into team wipes."* The role exists; the mechanic it

would use is what this direction builds.

STAYS SOLO — do not scale these:

a *timed release-or-wait* (non-blocking, world keeps running), not a decision that pauses anything.

Same state machine, different surface contract. Design the state machine so S2 is

surface-agnostic and the blocking-ness is a property of the surface, not of the machine.

a Tier-A/party property.

path-agnostic: *"Integrity band gates no role, no build axis, and no operational team. An L5 Pure

Evil guild fields the same role space as an L1 Truly Good guild."* But every revival row carries

integrity_band_lock = L1 or L1,L2. Under current data an L5 guild **cannot field a rezzer at

all** — a direct contradiction of §8.7.

Recommended resolution: the band lock is a Tier-A campaign catalog-access property (that is

what T1_Ability_Tree §12 says catalog access is *for* — path identity and replayability), and

Tier-C fields the L4/L5 alternate route from §5.6 so the role space stays equal. Which makes

authoring the evil-lane revival a Tier-C blocker, not merely a no-dead-end nicety.

wipe/recovery rules are absent. Out of scope now; flag as a Tier-C-phase gap so it is not discovered

late.

---

8. HONEST BUILD-SIZE ESTIMATE, per component

Sizes are relative waves in this project's own idiom (a "wave" ≈ the W2/W5/W9 unit: a few files, its

own tests, its own commit + gate ritual). ENGINE/CANON declared per the reuse doctrine.

BUILD-NOW — no ally runtime required, fully testable today

#ComponentSizeENGINE / CANONNotes
A1Checkpoint anchor + save-on-arm. Replace nearest-marker-by-distance with a real checkpoint. Recommend the vril site — already ruled as save + recharge + loadout sanctum (addendum §9), so one anchor serves three ruled systems. AHumanityVrilRechargeZone exists (VS_CH02_001) as the actor.1 waveENGINE (checkpoint) + CANON (which sites)Hard prerequisite of the direction
A2The choice state machine + surface, with WAIT present and resolving W6 IMPOSSIBLE (no allies exist yet). This is the honest BUILD-NOW form: real machine, real choice, real ledger, truthful failure.1 waveENGINE (machine) + CANON (strings)T1, T2, T5, T9, T10, T11
A3The downed pawn contract (§4).smallENGINET7. Prerequisite of A2 not being a bug
A4The out-of-combat detector as a named primitive with provenance; fix Defect A (Flee) + Defect B (Stalk) + hysteresis.1 small waveENGINE — high reuse valueT3, T8
A5The world-advance delta on death (VOL2 SL-1, specified and unbuilt).smallENGINE seam + CANON deltaWithout it the choice is cosmetic
A6Schema/canon pass: caster_class_scope + revival_direction_scope + out_of_combat_only; taught_capability_refs on WS_027/WS_012; the defeat ledger row + APPEND_LEGAL_IDS extension; revive policy rows; Gate 26/29 teeth + the two new teeth.1 mint + critic ritualCANONZero-token compute, but full mint discipline
A7Soak death-loop lane.smallENGINECovers a zero-coverage path
A8Player-side protected 1-HP clamp (missing today; §1).smallENGINE + CANON derivationT10

BUILD-NOW total: roughly 4-5 waves plus one mint. Every piece is independently valuable — A1, A4,

A5 and A8 are all things the slice needs regardless of whether the revive branch ever ships.

POST-SLICE — the ally runtime (the real cost)

#ComponentSizeNotes
B1The ALLY PAWN + AI subsystem. Greenfield: ally character class + own ASC/AttributeSet, controller, follow/positioning, target selection, the INT-tiered behavior-policy interpreter reading T0_Ally_Behavior_Policy.condition_expr, party frame, stat/loadout application from WS_027.multi-wave, the largest item in this analysisHead start: the predicate evaluator already exists on BOTH sides — harness/condition_expr.py and Source/Humanity/Private/Quest/ConditionExpr.cpp (+ FHumanityConditionExpr49Test). The policy rows are authored. The *brain wiring* is the missing half.
B2Party combat that continues after the player falls — enemies retarget onto allies; allies can go DOWNED. This is what makes "out of combat only" mean anything.multi-waveReconcile with the named-NPC-permanent-death doctrine: recommend allies go DOWNED, never dead, in combat. Permanent death stays a story event, never a combat outcome — which also protects the §9 gear-return contract from a loot-loss edge case.
B3The revive CAST + its presentation hookup.1 waveModest once B1 exists; HumanityAbilityFoundry is built
B4The teaching loop — how the player actually trains an ally.factory work, per chapterCanon-anchored (T3 §L55); a quest/progression surface

5090-ERA / GATED

#ComponentNotes
C1Death presentation. TODO_CANON L225-227 defers it explicitly as an ART placeholder, T2/GATED-5090 — the greybox is "freeze the anim + tip the actor ~74°". Fork B's camera grammar + the revive VFX with mastery-tier variants (the ruled Presentation Ladder).
C2Phase-5M magnitudes — every number here is firewalled: wait duration, revived vitality fraction, vril cost, the two branches' currency weights, the INT threshold at which an ally notices.
C3Phase-5M/5H build-space sweeps measuring whether revive collapses the meta (§5.5).
DTier-C: raid rez rules, the wipe economy, the §8.7 path-agnostic reconciliation.

---

9. FOR THE DIRECTOR — contested calls this axis cannot rule alone

1. The constraint is nearly free until B2 exists (§2). Ship it now anyway; report it register-honestly

as "built, not yet meaningful." Do not let a play-quality claim ride on it pre-B2.

2. Boss fights: refuse WAIT, or offer-and-fail? Recommend refuse at S2, diegetically. Otherwise every

boss death becomes a dead wait.

3. §8.7 path-agnostic vs integrity_band_lock — a genuine canon collision (§7). Recommend the band

lock is Tier-A catalog-access only.

4. The L3/L4/L5 revival hole is a shipping no-dead-end violation (§5.6). Canon already supplies the

fix shape (T1_Story_Spine L114: same ability, higher vril cost, karmic-debt residue). It needs rows,

and rows here are cardinal-adjacent (band-gated capability) — Josh's call on the routing.

5. Is WAIT shown when eligibility is provably zero? Honesty (hide it) vs discoverability (show it

greyed, so the player learns the system exists). Recommend: shown, with a truthful diegetic read

the natural-voice doctrine forbids a menu word like "unavailable," so the line must be a person's

voice saying no one is coming. That string is CANON authoring, not engine.

6. The AP_0001 corpse-interpose defect (§3.4) must be fixed in the same commit as the downed state.

---

10. EVIDENCE INDEX (every claim's source)

(delegate bind), L236-266 (ResolveActiveFightConsolation), L268-278 (GetActiveDeathConsolationLine),

L280-318 (HandlePlayerDeath), L321-368 (RespawnAtNearestSite);

Public/Core/HumanityCharacter.h L59-62, L236-243, L316-328.

presentation is a greybox collapse, T2/GATED-5090) and the constants table below it.

grep -rn "Checkpoint" → 0; grep -rn "bInCombat\|IsInCombat\|CombatActive" → 0. All over

Source/Humanity/**/*.{h,cpp} excluding Intermediate. Control that hit:

grep -rni "companion" _source/01_Tier_1_Foundation/ → dense.

HumanityVerbAbilities.cpp L55-57 — all boss composure node, not a creature.

Private/Core/HumanityEnemyCharacter.cpp L288-295 (perception cone), L403-424 (leash + hysteresis).

Private/Combat/HumanityEncounterVolume.cpp L114; QA/bugs/INDEX.md row BUG-0018;

Private/QA/HumanityEncounterAutomationTests.cpp L1-112.

Soak: Tools/run_soak.py docstring (capture/render/teardown lane; no death coverage).

L71-73 (A_C_002/003/004), L92 (C_V_004); `_source/01_Tier_1_Foundation/T1_Ability_Tree

[ACTIVE v1.4].md` L848, L922, L924, L936, L1192, L1210.

Band census over all 185 rows: heal/revival = 8 rows, all L1 or L1,L2; L3 = 13 rows and L4,L5 = 7

rows exist in other classes (so the bands are expressible and the zero is real).

_source/01_Tier_1_Foundation/T1_Story_Spine [ACTIVE v1.0].md L114.

docs/pipeline_review/MINT_DESIGN_B_ITEM_ALLY_2026-07-27.md §3.1 (WS_027, 10 sub-fields), §3.2

(WS_012, 12 sub-fields), §3.3 (T0_Familiar_Bond_Ability), §3.5 (T0_Ally_Behavior_Policy),

§3.7 (MMO bridge — nothing new minted).

frozenset; WS_044/WS_046 landed outside it).

harness/check_ally_build.py docstring (teeth B1-B5); harness/check_build_space.py docstring

(T-A1..T-A13); harness/check_no_dead_end.py docstring (the scaffold discipline).

§8.7 path-agnostic rule, §8.8 recovered GDD architecture).

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