pipelines/FORKB_ANALYSIS_ENGINE_SCHEMA_2026-07-27.md
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.
---
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_id | name | class | band | tier | prereq | cost | EAM |
|---|---|---|---|---|---|---|---|
A_A_009 | Breath of Life | revival | L1 | 5.0 Philosophus | Vril Healing T5 Philosophus | high | EAM-on-bonded-Heart |
A_C_003 | Vril Revival | revival | L1,L2 | 5.0 Philosophus | Vril Healing 70-99 Philosophus | high | EAM-on-bonded-Crown |
A_C_004 | Vril Mass Revival | revival_aoe | L1 | 7.0 Adeptus_Major | Vril Revival 100 Adeptus Minor | extreme | EAM-on-bonded-Crown |
A_C_002 | Vril Healing | healing | L1,L2 | 4.0 Practicus | Ch_06 Sri Lanka | medium | — |
A_W_007 / A_W_014 / C_P_003 / C_V_004 | healing lane | healing / healing_aoe | L1 or L1,L2 | 3.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):
grep -rn "\bAlly\|Allies" -i → 0 hits.grep -rn "Companion" -i → 10 hits, all data plumbing, zero runtime: 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.
grep -rn "Familiar" -i returns~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.
AHumanityEnemyCharacter (+ AHumanityEnemyController, 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.
grep -rni "companion" _source/01_Tier_1_Foundation/ returns dense canon. Thecanon 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.
---
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 distance → GetArrivalPoint(),
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.
| Required by the direction | Reality today | Control | |
|---|---|---|---|
| A checkpoint | None. 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 death | None. 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 0 | None. A timer, not a prompt. | code read | |
| A downed state distinct from dead | None. HP 0 → full-health teleport, one path. | code read | |
| A 1-HP protected clamp on the PLAYER | None. 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.
---
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; }
Flee counts as aggroed. A timid macaque (bFlee, CR_0003) running away holds "combat" open indefinitely. A revive-wait gated on !IsAggroed() would never resolve near timid fauna.
Stalk does NOT count as aggroed. The Wave-G stalker (Ebu Gogo) shadowing the playerat a standoff reads as out of combat. That is precisely the horror beat where a revive window is
most wrong — and it would open.
bPerceivedThisFrame is frame-transient. Any detector must be hysteretic (the pawn already uses DeAggroRadius hysteresis for its own state; the detector needs its own).
.cpp L403-424): DistFromHome > LeashRadius → Return, "leash wins over everything."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.
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.
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.
---
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
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.
---
Without it, S2/S3b is a corpse-beating bug. The player pawn while downed must:
false from IHumanityTargetable::IsLockOnTargetable() (the interface exists and bothenemy and boss already implement the alive-gated form — this is a one-line pattern match),
AHumanityEnemyCharacter's perception cone (AggroRadius / AggroHalfAngleDeg, .cpp L288-295) so hostiles disengage rather than flail,
IsDowned() distinct from bPlayerDead).Declare it ENGINE (reusable) per the engine-vs-canon reuse doctrine every header in this project
already carries.
---
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:
caster_class_scope column on T0_Ability_Tree_Registry (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.
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:
WS_027 companion_roster_state (the ally-build extension, mint §3.1): add 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.
WS_012 familiar_bond_state: mirror taught_capability_refs; vril_integration_state isalready the teaching ladder.
T0_Familiar_Bond_Ability (BA_*, 15 columns, live): a revival bond-rung is the natural home (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.
T0_Ally_Behavior_Policy is the exact home21 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.
WS_044 idiom exactlyWS_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.)
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.
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.
---
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).
| # | Test | Edge asserted | Must-not-fire twin |
|---|---|---|---|
| T1 | Humanity.Defeat.PlayerDeathChoiceOffered | HP 0 → S2; input accepted | the 1.45 s auto-respawn timer must NOT be armed |
| T2 | Humanity.Defeat.CheckpointReturnPath | S3a lands at the CHECKPOINT anchor, not nearest-marker-by-distance | a marker nearer than the checkpoint must NOT win |
| T3 | Humanity.Defeat.WaitBlockedInCombat | W1 cannot resolve with a live aggroed hostile, over REAL ticks | — |
| T4 | Humanity.Defeat.WaitResolvesOutOfCombat | hostile defeated/leashed → W2 → W3 → W4 | — |
| T5 | Humanity.Defeat.WaitImpossibleFailsFast | zero eligible allies → W6 → S3a immediately | must NOT run a timer out |
| T6 | Humanity.Defeat.BossFightWaitRefused | WAIT refused/unresolvable in a live boss fight; both killable and protected classes | — |
| T7 | Humanity.Defeat.DownedPawnContract | not lock-on targetable; holds no aggro; does NOT satisfy AP_0001's ≤50% predicate | an ALIVE player at 40% HP MUST still satisfy it |
| T8 | Humanity.Defeat.TeardownDoesNotFakeOutOfCombat | BUG-0018 EndPlay must not flip W1→W2 | extend GuardianTeardownOnEndPlay |
| T9 | Humanity.Defeat.LedgerAppendOnce | exactly one ledger row per death, both branches, idempotent under re-possession | a double-bind must NOT produce two |
| T10 | Humanity.Defeat.ProtectedChapterNoDeathSurface | protected chapter clamps player to 1 HP; S2 never opens | — |
| T11 | Humanity.Defeat.StringsAreData | every player-facing string resolves from a row | extend FHumanityCH02SpoilerSafeStringsTest |
check_ally_build.py (--registries, hosts T-B1): a revive policy row must parse under 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)).
taught_capability_refs entry resolves to a 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.
revival_direction_scope=to_protagonist without out_of_combat_only=true. Josh's constraint made unspellable-to-violate in data.
check_build_space.py: enroll the revive-capable ally spec in the combinatorics(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.
check_no_dead_end.py: the L3/L4/L5 hole is a genuine reachability question and belongshere once the affordance layer populates; today the gate is a declared scaffold.
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.
---
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:
T0_Role_Axis_Registry rows carry arena=both; §8.7 states *"One taxonomy, two arenas."* ROLE_GROUP_HEAL / ROLE_SINGLE_HEAL need nothing added.
A_C_004 Vril Mass Revival (T7 Adeptus Major, revival_aoe,*"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.
---
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.
| # | Component | Size | ENGINE / CANON | Notes |
|---|---|---|---|---|
| A1 | Checkpoint 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 wave | ENGINE (checkpoint) + CANON (which sites) | Hard prerequisite of the direction |
| A2 | The 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 wave | ENGINE (machine) + CANON (strings) | T1, T2, T5, T9, T10, T11 |
| A3 | The downed pawn contract (§4). | small | ENGINE | T7. Prerequisite of A2 not being a bug |
| A4 | The out-of-combat detector as a named primitive with provenance; fix Defect A (Flee) + Defect B (Stalk) + hysteresis. | 1 small wave | ENGINE — high reuse value | T3, T8 |
| A5 | The world-advance delta on death (VOL2 SL-1, specified and unbuilt). | small | ENGINE seam + CANON delta | Without it the choice is cosmetic |
| A6 | Schema/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 ritual | CANON | Zero-token compute, but full mint discipline |
| A7 | Soak death-loop lane. | small | ENGINE | Covers a zero-coverage path |
| A8 | Player-side protected 1-HP clamp (missing today; §1). | small | ENGINE + CANON derivation | T10 |
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.
| # | Component | Size | Notes |
|---|---|---|---|
| B1 | The 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 analysis | Head 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. |
| B2 | Party 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-wave | Reconcile 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. |
| B3 | The revive CAST + its presentation hookup. | 1 wave | Modest once B1 exists; HumanityAbilityFoundry is built |
| B4 | The teaching loop — how the player actually trains an ally. | factory work, per chapter | Canon-anchored (T3 §L55); a quest/progression surface |
| # | Component | Notes |
|---|---|---|
| C1 | Death 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). | |
| C2 | Phase-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. | |
| C3 | Phase-5M/5H build-space sweeps measuring whether revive collapses the meta (§5.5). | |
| D | Tier-C: raid rez rules, the wipe economy, the §8.7 path-agnostic reconciliation. |
---
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.
---
C:/dev/Humanity/Humanity/Source/Humanity/Private/Core/HumanityCharacter.cpp L216-232 (delegate bind), L236-266 (ResolveActiveFightConsolation), L268-278 (GetActiveDeathConsolationLine),
L280-318 (HandlePlayerDeath), L321-368 (RespawnAtNearestSite);
Public/Core/HumanityCharacter.h L59-62, L236-243, L316-328.
C:/dev/Humanity/Humanity/TODO_CANON.md L225-242 (the deathpresentation is a greybox collapse, T2/GATED-5090) and the constants table below it.
grep -rn "\bAlly\|Allies" -i → 0; grep -rn "Companion" -i → 10 (all data); 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.
Private/Combat/HumanityCombatTags.cpp L32/L47/L66, HumanityAttributeSet.cpp L38-335, HumanityVerbAbilities.cpp L55-57 — all boss composure node, not a creature.
Public/Core/HumanityEnemyCharacter.h L49-93; Private/Core/HumanityEnemyCharacter.cpp L288-295 (perception cone), L403-424 (leash + hysteresis).
Public/Combat/HumanityEncounterVolume.h L86 + L139; Private/Combat/HumanityEncounterVolume.cpp L114; QA/bugs/INDEX.md row BUG-0018;
Private/QA/HumanityEncounterAutomationTests.cpp L1-112.
IMPLEMENT_*_AUTOMATION_TEST classes across Private/QA/*.cpp. Soak: Tools/run_soak.py docstring (capture/render/teardown lane; no death coverage).
registries/T0_Ability_Tree_Registry [ACTIVE v0.1]/Sheet1.csv L53 (A_A_009), 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/03_Tier_3_Characters/T3_Familiars_Named [ACTIVE v1.0].md L55; _source/01_Tier_1_Foundation/T1_Story_Spine [ACTIVE v1.0].md L114.
registries/T0_Ally_Behavior_Policy [DRAFT v0.1]/Sheet1.csv (21 cols, AP_0001-0004); 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).
APPEND_LEGAL_IDS landmine: docs/pipeline_review/MINT_APPLY_CRITIC_2026-07-27.md §A (the twelve-idfrozenset; WS_044/WS_046 landed outside it).
harness/gates_config.json (29 gates; 9 no_dead_end, 26 build_space, 29 ally_build); 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).
_source/01_Tier_1_Foundation/T1_Tier_C_MMO_Spec [ACTIVE v1.0].md §8.1-§8.9 (four teams,§8.7 path-agnostic rule, §8.8 recovered GDD architecture).
docs/proposals/PRESENTATION_DOCTRINE.md §0.B (ESCALATED, awaiting this brief).