chore(simulation): address review suggestions — comments and minor fixes

- monologue.rs: tracing::warn on unrecognized trigger in fallback arm
- disclosure.rs: borrow-sequencing comment, first() simplification note
- trait_modifiers.rs: delegate parse_confidence to KnowledgeConfidence::try_from
- npc_knowledge_transfer.rs: fix misleading "draw randomly" comment,
  document one-directional transfer behavior
- graph.rs: document intentional no-retrigger after contradiction
- dialogue.rs: explain entity grant guardrail asymmetry (D-079)
- knowledge/mod.rs: document one-tick monologue lag from system ordering
- poi_discovery.rs: document D-079 carve-out for direct KG write

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-24 12:45:47 +01:00
co-authored by Claude Opus 4.6
parent c655878dee
commit 132676c25a
8 changed files with 42 additions and 12 deletions
+5
View File
@@ -674,6 +674,11 @@ fn emit_knowledge_grant(
},
});
}
// Entity grants have no "NPC knows this entity" guardrail (unlike Fact
// grants above). This is intentional per D-079: entity grants introduce
// NEW knowledge about an entity the NPC is talking about — the NPC
// doesn't need to "know" the entity in their own KG to reference it
// in dialogue. The entity_ref resolves via ContentEntityRegistry, not KG.
KnowledgeGrant::Entity {
entity_ref,
attributes,
+4 -1
View File
@@ -457,7 +457,10 @@ fn select_hardcoded_fallback(trigger: &str, rng: &mut impl Rng) -> (String, Stri
"hear_sound" => HEAR_SOUND_LINES,
"witness_interaction" => WITNESS_INTERACTION_LINES,
"post_conversation" => POST_CONVERSATION_LINES,
_ => OBSERVE_NPC_LINES,
unknown => {
tracing::warn!("select_hardcoded_fallback: unrecognized trigger '{}', using observe_npc", unknown);
OBSERVE_NPC_LINES
}
};
let index = rng.random_range(0..lines.len());
(lines[index].0.to_string(), lines[index].1.to_string())
@@ -197,6 +197,10 @@ pub fn transfer_npc_knowledge(
}
// --- Dual-mutable KG access ---
// Transfer is one-directional per conversation tick: speaker → partner.
// If both participants are Active NPCs, each fires as "speaker" in
// separate conversation pairs (run_npc_conversations creates symmetric
// pairs), so both directions are covered across two iterations.
let Ok([speaker_kg, mut partner_kg]) =
kg_query.get_many_mut([speaker_entity, partner_entity])
@@ -265,7 +269,8 @@ pub fn transfer_npc_knowledge(
// Sort by most recently updated (deterministic: descending tick, stable by BTreeMap key order)
candidates.sort_by(|a, b| b.sort_key().cmp(&a.sort_key()));
// Draw 13 entries
// Take top 13 entries by recency (random count, deterministic selection).
// The random element is HOW MANY facts transfer, not WHICH ones.
let count = rng.rng.random_range(1u32..=3u32) as usize;
let count = count.min(candidates.len());
+5
View File
@@ -81,6 +81,11 @@ pub fn discover_pois(
}
if can_discover(observer_pos, &geometry, &kg, poi) {
// Direct KG write — bypasses the KnowledgeGranted event queue.
// Justified for LOS-based physical discovery: the observer sees
// the POI directly, no intermediary grant source. This is a D-079
// carve-out; NPC tips and research-based POI discovery (Sprint 18)
// will use the event queue path.
kg.facts.insert(
fact_id,
FactKnowledge {