feat(simulation): sprint 17 — knowledge graph, disclosure, POI, contradiction #63

Closed
jpmschweitzer wants to merge 0 commits from server into main
Owner

Summary

Sprint 17 server delivery — knowledge graph becomes a live system:

  • Knowledge grants (#545, #546): KnowledgeGrant untagged enum (Fact + Entity), ContentEntityRegistry, KnowledgeGranted event processing at line selection time (D-079)
  • Contradiction detection (#547): ContradictionClaim struct with 600-tick window in observe_entity, epistemic neutrality (D-083)
  • NPC-to-NPC transfer (#548): Trust-gated fact exchange, confidence capping at KnowsOf, ToldBy source construction (D-080)
  • NPC information boundaries (#549): tell_state reads KG for other-entity relationship state, MVP boundary (D-082)
  • Contradiction monologue (#550): Pre-resolved entity names, PersonOfInterest shift, THE FRIEND arc event chain (D-083)
  • Unprompted disclosure (#551, #173): DisclosureCandidates with 7 trigger gates, three-layer rate limiting, two-stage trait filter (D-081)
  • POI infrastructure (#148, #149): PointOfInterest component, proximity-based discovery via KnowledgeGranted events
  • Protocol versioning (#232): Version field tests, mismatch detection, serde_default migration pattern

868 tests passing, 0 failures. +4,699 lines across 26 files.

Tickets

#545, #546, #547, #548, #549, #550, #551, #148, #149, #173, #232

Decisions implemented

D-079 (grant architecture), D-080 (NPC propagation), D-081 (unprompted disclosure), D-082 (NPC boundaries MVP), D-083 (contradiction pipeline)

Test plan

  • KnowledgeGrant serde roundtrip, ContentEntityRegistry resolution
  • Contradiction detection: location mismatch, time window boundary, no false positive for non-ToldBy
  • THE FRIEND arc integration: ToldBy grant → DirectObservation → ContradictionClaim → monologue → PersonOfInterest → AnomalyMarker
  • NPC-to-NPC transfer: trust-gated, confidence capped, ToldBy source
  • tell_state KG awareness: falls through to axes for self-knowledge, reads KG for others
  • Unprompted disclosure: trigger gates, trait filters, rate limiting
  • Protocol versioning: round-trip, mismatch detection, variant coverage
## Summary Sprint 17 server delivery — knowledge graph becomes a live system: - **Knowledge grants** (#545, #546): `KnowledgeGrant` untagged enum (Fact + Entity), `ContentEntityRegistry`, `KnowledgeGranted` event processing at line selection time (D-079) - **Contradiction detection** (#547): `ContradictionClaim` struct with 600-tick window in `observe_entity`, epistemic neutrality (D-083) - **NPC-to-NPC transfer** (#548): Trust-gated fact exchange, confidence capping at KnowsOf, `ToldBy` source construction (D-080) - **NPC information boundaries** (#549): tell_state reads KG for other-entity relationship state, MVP boundary (D-082) - **Contradiction monologue** (#550): Pre-resolved entity names, PersonOfInterest shift, THE FRIEND arc event chain (D-083) - **Unprompted disclosure** (#551, #173): DisclosureCandidates with 7 trigger gates, three-layer rate limiting, two-stage trait filter (D-081) - **POI infrastructure** (#148, #149): PointOfInterest component, proximity-based discovery via KnowledgeGranted events - **Protocol versioning** (#232): Version field tests, mismatch detection, serde_default migration pattern 868 tests passing, 0 failures. +4,699 lines across 26 files. ## Tickets #545, #546, #547, #548, #549, #550, #551, #148, #149, #173, #232 ## Decisions implemented D-079 (grant architecture), D-080 (NPC propagation), D-081 (unprompted disclosure), D-082 (NPC boundaries MVP), D-083 (contradiction pipeline) ## Test plan - KnowledgeGrant serde roundtrip, ContentEntityRegistry resolution - Contradiction detection: location mismatch, time window boundary, no false positive for non-ToldBy - THE FRIEND arc integration: ToldBy grant → DirectObservation → ContradictionClaim → monologue → PersonOfInterest → AnomalyMarker - NPC-to-NPC transfer: trust-gated, confidence capped, ToldBy source - tell_state KG awareness: falls through to axes for self-knowledge, reads KG for others - Unprompted disclosure: trigger gates, trait filters, rate limiting - Protocol versioning: round-trip, mismatch detection, variant coverage
jpmschweitzer added 8 commits 2026-02-24 12:17:25 +01:00
KnowledgeGrant untagged enum (Fact + Entity variants), ContentEntityRegistry
resource, KnowledgeGranted event processing, ContradictionClaim struct with
600-tick window detection in observe_entity. Wires knowledge_grant field in
dialogue line selection. Implements D-079, D-083. Closes Q-026.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
transfer_npc_knowledge system runs after conversations with trust-gated
fact exchange, confidence capping at KnowsOf, ToldBy source construction.
POI data model with PointOfInterest component and proximity-based discovery
via KnowledgeGranted events. Implements D-080. Closes Q-024.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
tell_state reads KG for other-entity relationship state (MVP boundary
per D-082). Contradiction monologue fires with pre-resolved entity names,
shifts ToldBy source to PersonOfInterest. Full THE FRIEND arc event chain.
Implements D-082 step 1, D-083 event chain.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
DisclosureCandidates component with 7 trigger gates, three-layer rate
limiting, and two-stage trait filter (what + how). Cautious/Gossipy/Loyal/
Talkative predicates via TraitModifierConfig. POI component and discovery
system. Implements D-081, D-082 step 2.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Version field round-trip, mismatch detection, serde_default migration
pattern, all TellCategory and VerbKind variant coverage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Heartbeat rule for agent spawn prompts (15-min progress check) and
team lead proactive checks (bottleneck detection pattern).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
jpmschweitzer added 1 commit 2026-02-24 12:24:12 +01:00
Reviews must run from main. Added step 0 hard stop if current branch
is not main, preventing repeated misuse from team branches.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Author
Owner

Review: server → main (#63) — type: code

Hoshe (Code Quality): REQUEST_CHANGES

Well-structured 4700-line implementation. Knowledge graph core, contradiction detection, NPC-to-NPC transfer, POI discovery, and disclosure pipeline are all architecturally sound. Test coverage is thorough for happy paths and most edge cases. Two warning-level issues found.

# File Severity Issue
1 server/src/knowledge/graph.rs:206-218 warning record_incomplete_interaction creates new entries with KnowledgeSource::DirectObservation — walk-away from dialogue is not direct observation. Falsely inoculates entries against future contradiction detection (pre-overwrite check only fires when existing.source is ToldBy).
2 server/src/npc/disclosure.rs:123-199 warning exclude_high_trust_entities (Loyal trait) is defined, configured, and tested via any_excludes_high_trust, but derive_disclosure_candidates never calls the filter. Loyal trait silently has no effect on disclosure.
3 server/src/simulation/monologue.rs:453-464 suggestion Wildcard arm _ => OBSERVE_NPC_LINES silently returns wrong lines for unknown trigger strings. Add tracing::warn! on the default arm.
4 server/src/npc/disclosure.rs:394-397 suggestion process_unprompted_disclosure re-queries npc_query mutably after read pass. Pattern is fragile — consider extracting mutable cooldown update or adding explicit borrow-sequencing comment.
5 server/src/npc/trait_modifiers.rs:192-203 suggestion parse_confidence duplicates KnowledgeConfidence::try_from but only accepts underscore forms. Should delegate to try_from instead.
6 server/src/simulation/npc_knowledge_transfer.rs:265-270 suggestion Comment says "draw 1–3 entries randomly" but implementation always takes top-N by recency. Either update comment or implement random sampling.

Tyre (Architecture): APPROVE

Substantial, well-executed sprint implementing D-079 through D-083. Information boundaries are first-class, BTreeMaps used correctly for determinism, D-010 principles consistently upheld. Contradiction detection, NPC-to-NPC transfer, unprompted disclosure, and POI discovery all integrate cleanly without violating multiplayer-readiness baseline.

# File Severity Issue
1 server/src/simulation/npc_knowledge_transfer.rs:199-210 suggestion Dual-mutable KG access is correct, but one-directional transfer (A→B only) emergent behavior if conversations fire on both participants should be documented.
2 server/src/knowledge/graph.rs:171-177 suggestion After contradiction, source rewritten to DirectObservation means subsequent observations don't re-trigger — intentional but undocumented. Add comment to prevent future "fix."
3 server/src/npc/disclosure.rs:~283 suggestion candidates.first() always picks highest-priority fact — known simplification, worth a comment flagging it for Layer 4 line selection (#172).
4 server/src/simulation/dialogue.rs:677-709 suggestion Entity grants have no NPC-knows-this-entity guardrail (unlike Fact grants). Correct per D-079 spec, but comment should explain why the asymmetry exists.
5 server/src/knowledge/mod.rs:40-44 suggestion process_knowledge_events runs after snapshot → contradiction monologue lags by one tick (~0.1s). Not a bug, but worth a comment on ordering.
6 server/src/simulation/poi_discovery.rs:84-93 suggestion Direct KG write bypasses event queue — justified for LOS discovery but breaks the unified KnowledgeGranted path from D-079. Document the carve-out.
7 server/src/simulation/monologue.rs (fallback lines) suggestion Wildcard arm in select_hardcoded_fallback silently uses wrong lines for unrecognized triggers. Add tracing::warn!.

Verdict: CHANGES REQUESTED

Fixes needed:

  1. record_incomplete_interaction — use a correct KnowledgeSource variant (not DirectObservation) for walk-away entries
  2. Wire up exclude_high_trust_entities filter in derive_disclosure_candidates, or remove/stub it with a TODO if it's deferred
## Review: server → main (#63) — type: code ### Hoshe (Code Quality): REQUEST_CHANGES Well-structured 4700-line implementation. Knowledge graph core, contradiction detection, NPC-to-NPC transfer, POI discovery, and disclosure pipeline are all architecturally sound. Test coverage is thorough for happy paths and most edge cases. Two warning-level issues found. | # | File | Severity | Issue | |---|------|----------|-------| | 1 | `server/src/knowledge/graph.rs`:206-218 | warning | `record_incomplete_interaction` creates new entries with `KnowledgeSource::DirectObservation` — walk-away from dialogue is not direct observation. Falsely inoculates entries against future contradiction detection (pre-overwrite check only fires when `existing.source` is `ToldBy`). | | 2 | `server/src/npc/disclosure.rs`:123-199 | warning | `exclude_high_trust_entities` (Loyal trait) is defined, configured, and tested via `any_excludes_high_trust`, but `derive_disclosure_candidates` never calls the filter. Loyal trait silently has no effect on disclosure. | | 3 | `server/src/simulation/monologue.rs`:453-464 | suggestion | Wildcard arm `_ => OBSERVE_NPC_LINES` silently returns wrong lines for unknown trigger strings. Add `tracing::warn!` on the default arm. | | 4 | `server/src/npc/disclosure.rs`:394-397 | suggestion | `process_unprompted_disclosure` re-queries `npc_query` mutably after read pass. Pattern is fragile — consider extracting mutable cooldown update or adding explicit borrow-sequencing comment. | | 5 | `server/src/npc/trait_modifiers.rs`:192-203 | suggestion | `parse_confidence` duplicates `KnowledgeConfidence::try_from` but only accepts underscore forms. Should delegate to `try_from` instead. | | 6 | `server/src/simulation/npc_knowledge_transfer.rs`:265-270 | suggestion | Comment says "draw 1–3 entries randomly" but implementation always takes top-N by recency. Either update comment or implement random sampling. | ### Tyre (Architecture): APPROVE Substantial, well-executed sprint implementing D-079 through D-083. Information boundaries are first-class, BTreeMaps used correctly for determinism, D-010 principles consistently upheld. Contradiction detection, NPC-to-NPC transfer, unprompted disclosure, and POI discovery all integrate cleanly without violating multiplayer-readiness baseline. | # | File | Severity | Issue | |---|------|----------|-------| | 1 | `server/src/simulation/npc_knowledge_transfer.rs`:199-210 | suggestion | Dual-mutable KG access is correct, but one-directional transfer (A→B only) emergent behavior if conversations fire on both participants should be documented. | | 2 | `server/src/knowledge/graph.rs`:171-177 | suggestion | After contradiction, source rewritten to `DirectObservation` means subsequent observations don't re-trigger — intentional but undocumented. Add comment to prevent future "fix." | | 3 | `server/src/npc/disclosure.rs`:~283 | suggestion | `candidates.first()` always picks highest-priority fact — known simplification, worth a comment flagging it for Layer 4 line selection (#172). | | 4 | `server/src/simulation/dialogue.rs`:677-709 | suggestion | Entity grants have no NPC-knows-this-entity guardrail (unlike Fact grants). Correct per D-079 spec, but comment should explain *why* the asymmetry exists. | | 5 | `server/src/knowledge/mod.rs`:40-44 | suggestion | `process_knowledge_events` runs after snapshot → contradiction monologue lags by one tick (~0.1s). Not a bug, but worth a comment on ordering. | | 6 | `server/src/simulation/poi_discovery.rs`:84-93 | suggestion | Direct KG write bypasses event queue — justified for LOS discovery but breaks the unified `KnowledgeGranted` path from D-079. Document the carve-out. | | 7 | `server/src/simulation/monologue.rs` (fallback lines) | suggestion | Wildcard arm in `select_hardcoded_fallback` silently uses wrong lines for unrecognized triggers. Add `tracing::warn!`. | ### Verdict: CHANGES REQUESTED **Fixes needed:** 1. `record_incomplete_interaction` — use a correct `KnowledgeSource` variant (not `DirectObservation`) for walk-away entries 2. Wire up `exclude_high_trust_entities` filter in `derive_disclosure_candidates`, or remove/stub it with a TODO if it's deferred
jpmschweitzer added 1 commit 2026-02-24 12:42:42 +01:00
record_incomplete_interaction now uses Heard/Close source instead of
DirectObservation, preventing false inoculation against contradiction
detection. Wired exclude_high_trust_entities (Loyal trait) filter into
derive_disclosure_candidates — facts from Friendly-relationship source
entities are excluded from disclosure pool.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
jpmschweitzer added 1 commit 2026-02-24 12:45:54 +01:00
- 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>
Author
Owner

Re-Review: server → main (#63) — Round 2

Hoshe (Code Quality): APPROVE

Both warning-level issues fixed. All 4 suggestions addressed. No new issues.

# Issue Status
1 record_incomplete_interaction wrong source FIXED — now uses KnowledgeSource::Heard { Close }
2 Loyal trait filter never called FIXED — wired into derive_disclosure_candidates
3 Wildcard arm missing warning ADDRESSED — tracing::warn! added
4 Fragile borrow pattern ADDRESSED — documented inline
5 parse_confidence duplication FIXED — delegates to try_from
6 Random vs recency comment ADDRESSED — comment corrected

Tyre (Architecture): APPROVE

All 7 suggestions addressed with inline comments and decision references. Fix commits architecturally sound.

Verdict: APPROVED

## Re-Review: server → main (#63) — Round 2 ### Hoshe (Code Quality): APPROVE Both warning-level issues fixed. All 4 suggestions addressed. No new issues. | # | Issue | Status | |---|-------|--------| | 1 | `record_incomplete_interaction` wrong source | FIXED — now uses `KnowledgeSource::Heard { Close }` | | 2 | Loyal trait filter never called | FIXED — wired into `derive_disclosure_candidates` | | 3 | Wildcard arm missing warning | ADDRESSED — `tracing::warn!` added | | 4 | Fragile borrow pattern | ADDRESSED — documented inline | | 5 | `parse_confidence` duplication | FIXED — delegates to `try_from` | | 6 | Random vs recency comment | ADDRESSED — comment corrected | ### Tyre (Architecture): APPROVE All 7 suggestions addressed with inline comments and decision references. Fix commits architecturally sound. ### Verdict: APPROVED
jpmschweitzer closed this pull request 2026-02-24 13:00:47 +01:00

Pull request closed

This pull request cannot be reopened because the branch was deleted.
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: jpmschweitzer/settled-reach#63