Sprint 37 dead-code sweep closing out two stale supersession chains: #877 (D-167, 2026-03-24): Removes HeritageRoot type alias and ZonePaletteModifier::Heritage variant from server/src/simulation/ generator.rs. The 7 abstract heritage roots were retired in favour of the corridor cultural system; these two stubs were the only remaining references. #878 (D-032 + cascade rule): Strips the entire CharacterArchetype (Smuggler/Detective) trace from the server. Per lead direction 2026-04-21 and the development cascade (CLAUDE.md), character/NPC/ verb-differentiation/monologue code is Phase 6 detail that should not exist in code yet. The running archetype trace was pre-cascade filler, not production — production is only the client's character- creation UI and insert screens (client follow-up in #882). Deleted: - CharacterArchetype enum + StartupMessage.character_archetype field - archetype_verb_label() + archetype branch of apply_phase2_verb_filter (D-057 character-verb differentiation — marked superseded) - MonologueState.character partitioning - Gauntlet archetype plumbing (setup_gauntlet no longer takes an archetype) - server/content/schemas/drama_module.schema.yaml (zero Rust consumers) - server/content/modules/tier1/smuggling_ring_v0_1.yaml - server/tests/archetype_monologue.rs (regression guard for the removed system) - server/tests/v01_integration_playthrough.rs (archetype-dependent) Decision updates: - decisions/content.md D-032 supersession rewritten to cite the cascade (v0.2 drop invalidated the prior D-117 framing). - decisions/content.md D-035 tag taxonomy: `character` enum footnote updated; field noted as unused, do not reintroduce without a confirmed Phase 6 design. - decisions/perception.md D-057: archetype-verb differentiation marked superseded. Also bundles the types.rs version-field removal from #874 since the file was already touched here. Full trace audit in docs/architecture/sprint-37-878-audit.md. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -78,7 +78,6 @@ pub fn compute_observer_snapshot(
|
||||
&mut NearbyInteractionBuffer,
|
||||
&mut MonologueBuffer,
|
||||
Option<&Stance>,
|
||||
Option<&CharacterArchetype>,
|
||||
Option<&mut SprintAnomalyQueue>,
|
||||
Option<&CognitiveDelay>,
|
||||
Option<&mut DialogueResponseBuffer>,
|
||||
@@ -114,7 +113,6 @@ pub fn compute_observer_snapshot(
|
||||
mut interaction_buffer,
|
||||
mut monologue_buffer,
|
||||
stance_opt,
|
||||
archetype_opt,
|
||||
mut anomaly_queue_opt,
|
||||
cognitive_delay_opt,
|
||||
mut dialogue_response_opt,
|
||||
@@ -135,8 +133,6 @@ pub fn compute_observer_snapshot(
|
||||
.map(|f| f.0)
|
||||
.unwrap_or(FacingDirection::default());
|
||||
|
||||
let archetype = archetype_opt.copied().unwrap_or_default();
|
||||
|
||||
// Collect player inventory (D-065 info boundary: only own items)
|
||||
let player_inventory = registry
|
||||
.to_stable(observer_entity)
|
||||
@@ -197,7 +193,7 @@ pub fn compute_observer_snapshot(
|
||||
|
||||
// Take interactions and apply Phase 2 verb filter (D-057, #422)
|
||||
let mut nearby_interactions = interaction_buffer.take();
|
||||
apply_phase2_verb_filter(&mut nearby_interactions, observer_kg, archetype);
|
||||
apply_phase2_verb_filter(&mut nearby_interactions, observer_kg);
|
||||
|
||||
tracing::trace!(
|
||||
"compute_observer_snapshot: tick={}, visible={}, remembered={}, tiles={}",
|
||||
@@ -453,7 +449,6 @@ pub fn compute_observer_snapshot(
|
||||
};
|
||||
|
||||
buffer.snapshot = Some(ObserverSnapshot {
|
||||
version: crate::bridge::types::PROTOCOL_VERSION,
|
||||
tick: time.tick,
|
||||
game_time,
|
||||
player_facing: facing,
|
||||
@@ -654,7 +649,6 @@ fn collect_remembered_entities(
|
||||
/// 1. POI priority flips (D-060) — ExamineNpc above Talk for POI entities
|
||||
/// 2. Confront injection — adds Confront verb for NPCs when KnowsDetails+
|
||||
/// 3. Contradiction marking — sets contradicted flag when entity knowledge is Contradicted
|
||||
/// 4. Archetype label relabeling — smuggler/detective see different labels for same verb
|
||||
///
|
||||
/// Phase boundary: Phase 1 (interaction.rs) determines verb availability from
|
||||
/// ObjectType + proximity. Phase 2 (here) reads the observer's KnowledgeGraph
|
||||
@@ -663,7 +657,6 @@ fn collect_remembered_entities(
|
||||
fn apply_phase2_verb_filter(
|
||||
interactions: &mut [NearbyInteraction],
|
||||
observer_kg: &KnowledgeGraph,
|
||||
archetype: CharacterArchetype,
|
||||
) {
|
||||
for interaction in interactions.iter_mut() {
|
||||
let stable_id = StableId(interaction.entity_id);
|
||||
@@ -713,18 +706,6 @@ fn apply_phase2_verb_filter(
|
||||
}
|
||||
}
|
||||
|
||||
// --- Archetype label relabeling ---
|
||||
// Phase 2 swaps verb labels based on character archetype.
|
||||
// The VerbKind stays the same (same handler), only the display label changes.
|
||||
// This implements D-057: "Character differentiation via Phase 2 observer
|
||||
// filter, not separate verb systems."
|
||||
for verb in &mut interaction.verbs {
|
||||
if let Some(label) = archetype_verb_label(archetype, interaction.object_type, verb.kind)
|
||||
{
|
||||
verb.label = label.into();
|
||||
}
|
||||
}
|
||||
|
||||
// Re-sort after priority changes and verb additions
|
||||
interaction
|
||||
.verbs
|
||||
@@ -732,37 +713,5 @@ fn apply_phase2_verb_filter(
|
||||
}
|
||||
}
|
||||
|
||||
/// Archetype-specific verb label overrides (#422, D-057).
|
||||
///
|
||||
/// Returns a replacement label for the given (archetype, object_type, verb_kind)
|
||||
/// combination, or None to keep the Phase 1 default label.
|
||||
///
|
||||
/// v0.1: Container verbs differ by archetype. Other object types keep defaults.
|
||||
/// Add match arms here for future archetype-specific labels.
|
||||
fn archetype_verb_label(
|
||||
archetype: CharacterArchetype,
|
||||
object_type: Option<ObjectType>,
|
||||
kind: VerbKind,
|
||||
) -> Option<&'static str> {
|
||||
match (archetype, object_type, kind) {
|
||||
// Smuggler: Container verbs — physical manipulation vocabulary
|
||||
(CharacterArchetype::Smuggler, Some(ObjectType::Container), VerbKind::Open) => Some("Move"),
|
||||
(CharacterArchetype::Smuggler, Some(ObjectType::Container), VerbKind::Search) => {
|
||||
Some("Stash")
|
||||
}
|
||||
|
||||
// Detective: Container verbs — investigation vocabulary
|
||||
(CharacterArchetype::Detective, Some(ObjectType::Container), VerbKind::Open) => {
|
||||
Some("Scan")
|
||||
}
|
||||
(CharacterArchetype::Detective, Some(ObjectType::Container), VerbKind::Search) => {
|
||||
Some("Flag")
|
||||
}
|
||||
|
||||
// All other combinations: keep Phase 1 default label
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
@@ -59,7 +59,6 @@ fn player_always_visible_in_snapshot() {
|
||||
|
||||
let buffer = world.resource::<SnapshotBuffer>();
|
||||
let snapshot = buffer.snapshot.as_ref().expect("snapshot should exist");
|
||||
assert_eq!(snapshot.version, PROTOCOL_VERSION);
|
||||
assert_eq!(snapshot.entities.len(), 1);
|
||||
assert!(matches!(snapshot.entities[0].kind, EntityKind::Player));
|
||||
assert_eq!(snapshot.entities[0].observation, EntityVisibility::Visible);
|
||||
@@ -679,10 +678,6 @@ fn snapshot_v6_fields_default_through_pipeline() {
|
||||
let buffer = world.resource::<SnapshotBuffer>();
|
||||
let snapshot = buffer.snapshot.as_ref().expect("snapshot should exist");
|
||||
|
||||
assert_eq!(
|
||||
snapshot.version, PROTOCOL_VERSION,
|
||||
"should be current protocol version"
|
||||
);
|
||||
assert_eq!(
|
||||
snapshot.player_stance,
|
||||
MovementStance::Walk,
|
||||
@@ -694,29 +689,6 @@ fn snapshot_v6_fields_default_through_pipeline() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_v6_version_is_protocol_version() {
|
||||
let mut world = setup_world(32, 32);
|
||||
world.spawn((
|
||||
PlayerCharacter,
|
||||
TilePosition::new(16, 16, 0),
|
||||
Facing::default(),
|
||||
KnowledgeGraph::new(),
|
||||
NearbyInteractionBuffer::default(),
|
||||
MonologueBuffer::default(),
|
||||
));
|
||||
|
||||
run_observer_pipeline(&mut world);
|
||||
|
||||
let buffer = world.resource::<SnapshotBuffer>();
|
||||
let snapshot = buffer.snapshot.as_ref().unwrap();
|
||||
assert_eq!(
|
||||
snapshot.version,
|
||||
crate::bridge::types::PROTOCOL_VERSION,
|
||||
"snapshot version must match PROTOCOL_VERSION constant"
|
||||
);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Phase 2 verb filter tests (#422, D-057)
|
||||
// -----------------------------------------------------------------------
|
||||
@@ -967,148 +939,9 @@ fn phase2_no_contradiction_for_active_knowledge() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn phase2_smuggler_relabels_container_verbs() {
|
||||
let mut world = setup_world(32, 32);
|
||||
let mut registry = EntityRegistry::new(0);
|
||||
|
||||
// Container at close range, north of player
|
||||
let container = world
|
||||
.spawn((
|
||||
TilePosition::new(16, 15, 0),
|
||||
crate::simulation::interaction::Interactable,
|
||||
ObjectType::Container,
|
||||
))
|
||||
.id();
|
||||
registry.register(container);
|
||||
|
||||
// Smuggler player
|
||||
let player = world
|
||||
.spawn((
|
||||
PlayerCharacter,
|
||||
TilePosition::new(16, 16, 0),
|
||||
Facing(FacingDirection::North),
|
||||
KnowledgeGraph::new(),
|
||||
NearbyInteractionBuffer::default(),
|
||||
MonologueBuffer::default(),
|
||||
CharacterArchetype::Smuggler,
|
||||
))
|
||||
.id();
|
||||
registry.register(player);
|
||||
world.insert_resource(registry);
|
||||
|
||||
run_full_pipeline(&mut world);
|
||||
|
||||
let buffer = world.resource::<SnapshotBuffer>();
|
||||
let snapshot = buffer.snapshot.as_ref().unwrap();
|
||||
assert_eq!(snapshot.nearby_interactions.len(), 1);
|
||||
let interaction = &snapshot.nearby_interactions[0];
|
||||
// Container at close range: Open→"Move", Search→"Stash", Observe stays "Observe"
|
||||
let open_verb = interaction.verbs.iter().find(|v| v.kind == VerbKind::Open);
|
||||
let search_verb = interaction
|
||||
.verbs
|
||||
.iter()
|
||||
.find(|v| v.kind == VerbKind::Search);
|
||||
let observe_verb = interaction
|
||||
.verbs
|
||||
.iter()
|
||||
.find(|v| v.kind == VerbKind::Observe);
|
||||
assert_eq!(open_verb.unwrap().label, "Move", "smuggler Open→Move");
|
||||
assert_eq!(search_verb.unwrap().label, "Stash", "smuggler Search→Stash");
|
||||
assert_eq!(observe_verb.unwrap().label, "Observe", "Observe unchanged");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn phase2_detective_relabels_container_verbs() {
|
||||
let mut world = setup_world(32, 32);
|
||||
let mut registry = EntityRegistry::new(0);
|
||||
|
||||
let container = world
|
||||
.spawn((
|
||||
TilePosition::new(16, 15, 0),
|
||||
crate::simulation::interaction::Interactable,
|
||||
ObjectType::Container,
|
||||
))
|
||||
.id();
|
||||
registry.register(container);
|
||||
|
||||
// Detective player (explicit)
|
||||
let player = world
|
||||
.spawn((
|
||||
PlayerCharacter,
|
||||
TilePosition::new(16, 16, 0),
|
||||
Facing(FacingDirection::North),
|
||||
KnowledgeGraph::new(),
|
||||
NearbyInteractionBuffer::default(),
|
||||
MonologueBuffer::default(),
|
||||
CharacterArchetype::Detective,
|
||||
))
|
||||
.id();
|
||||
registry.register(player);
|
||||
world.insert_resource(registry);
|
||||
|
||||
run_full_pipeline(&mut world);
|
||||
|
||||
let buffer = world.resource::<SnapshotBuffer>();
|
||||
let snapshot = buffer.snapshot.as_ref().unwrap();
|
||||
assert_eq!(snapshot.nearby_interactions.len(), 1);
|
||||
let interaction = &snapshot.nearby_interactions[0];
|
||||
let open_verb = interaction.verbs.iter().find(|v| v.kind == VerbKind::Open);
|
||||
let search_verb = interaction
|
||||
.verbs
|
||||
.iter()
|
||||
.find(|v| v.kind == VerbKind::Search);
|
||||
assert_eq!(open_verb.unwrap().label, "Scan", "detective Open→Scan");
|
||||
assert_eq!(search_verb.unwrap().label, "Flag", "detective Search→Flag");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn phase2_default_archetype_is_detective() {
|
||||
// When no CharacterArchetype component attached, defaults to Detective
|
||||
let mut world = setup_world(32, 32);
|
||||
let mut registry = EntityRegistry::new(0);
|
||||
|
||||
let container = world
|
||||
.spawn((
|
||||
TilePosition::new(16, 15, 0),
|
||||
crate::simulation::interaction::Interactable,
|
||||
ObjectType::Container,
|
||||
))
|
||||
.id();
|
||||
registry.register(container);
|
||||
|
||||
// Player WITHOUT CharacterArchetype component
|
||||
let player = world
|
||||
.spawn((
|
||||
PlayerCharacter,
|
||||
TilePosition::new(16, 16, 0),
|
||||
Facing(FacingDirection::North),
|
||||
KnowledgeGraph::new(),
|
||||
NearbyInteractionBuffer::default(),
|
||||
MonologueBuffer::default(),
|
||||
))
|
||||
.id();
|
||||
registry.register(player);
|
||||
world.insert_resource(registry);
|
||||
|
||||
run_full_pipeline(&mut world);
|
||||
|
||||
let buffer = world.resource::<SnapshotBuffer>();
|
||||
let snapshot = buffer.snapshot.as_ref().unwrap();
|
||||
assert_eq!(snapshot.nearby_interactions.len(), 1);
|
||||
let interaction = &snapshot.nearby_interactions[0];
|
||||
// Default = Detective labels
|
||||
let open_verb = interaction.verbs.iter().find(|v| v.kind == VerbKind::Open);
|
||||
assert_eq!(
|
||||
open_verb.unwrap().label,
|
||||
"Scan",
|
||||
"default archetype should use Detective labels"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn phase2_non_container_keeps_default_labels() {
|
||||
// Readable objects should keep their default labels regardless of archetype
|
||||
// Readable objects keep their default labels (post-archetype cleanup, D-032 SUPERSEDED).
|
||||
let mut world = setup_world(32, 32);
|
||||
let mut registry = EntityRegistry::new(0);
|
||||
|
||||
@@ -1129,7 +962,6 @@ fn phase2_non_container_keeps_default_labels() {
|
||||
KnowledgeGraph::new(),
|
||||
NearbyInteractionBuffer::default(),
|
||||
MonologueBuffer::default(),
|
||||
CharacterArchetype::Smuggler,
|
||||
))
|
||||
.id();
|
||||
registry.register(player);
|
||||
@@ -1145,7 +977,7 @@ fn phase2_non_container_keeps_default_labels() {
|
||||
assert_eq!(
|
||||
read_verb.unwrap().label,
|
||||
"Read",
|
||||
"Readable labels unchanged for smuggler"
|
||||
"Readable labels unchanged"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user