Protocol v14 — Three new ObserverSnapshot fields: poi_list (minimap), examine_result (examine overlay), player_knowledge (journal). Server populates live from KG and PointOfInterest components.
#151 Minimap rendering — Circular 160px diegetic insert overlay with POI dots (colored by category: diamond/danger, square/evidence, circle/default), border arrows for distant POIs, player-centered fixed-north, on InsertOverlay CanvasLayer 10.
#174 Dialogue UI hardening — Confrontation italic voice (D-063), examine result overlay with 5s auto-dismiss and confidence coloring. D-062 invisible locked options confirmed correct.
#264 Knowledge/journal panel — Right-side insert panel (J key), facts grouped by entity with confidence/source/state metadata, contradicted entries in amber+strikethrough (THE FRIEND arc), stale entries dimmed, mutual exclusion with dialogue.
50 gdUnit4 tests — 30 dialogue tests (D-062, D-063, D-064, BBCode guard) + 20 journal tests (KG parsing, scene structure, UIStrings). Test plan document with manual procedures.
Add three new ObserverSnapshot fields for client Sprint 18 tickets:
poi_list (Vec<PoiWire>) for minimap #151, examine_result
(Option<ExamineResultWire>) for #174, player_knowledge
(Option<PlayerKnowledgeWire>) for journal #264. POI list populated
live from KG-discovered PointOfInterest components. KG dump
serializes entity/fact knowledge with confidence, source, and state.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Decode poi_list, examine_result, and player_knowledge from
ObserverSnapshot. Add GameState.discovered_pois,
current_examine_result, and player_knowledge fields populated
from snapshot apply handlers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Circular 160px diegetic insert overlay on CanvasLayer 10. Nearby
POIs as colored dots (diamond=danger, square=evidence, circle=default),
distant POIs as directional border arrows. Player centered, fixed-north.
Moved from UILayer to InsertOverlay per D-013/D-049.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Confrontation options use RichTextLabel with italic tags for
first-person voice (D-063). Examine result overlay auto-dismisses
after 5s with confidence-based color tinting. Dismisses when
dialogue opens. D-062 invisible locked options confirmed correct.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Right-side insert panel toggled with J key. Facts grouped by entity
with confidence, source, and state metadata. Contradicted entries
in amber with strikethrough (THE FRIEND arc surface). Stale entries
dimmed. Mutual exclusion with dialogue box. All labels via UIStrings.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
50 tests across two files: 30 dialogue tests (D-062 compliance,
D-063 confrontation beat, D-064 walk-away, BBCode guard, size
constraints) and 20 journal tests (KG parsing, confidence/source/
state enums, scene structure, UIStrings keys, POI list). Test plan
document with manual procedures and sprint completion checklist.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- minimap.gd: fix "poi_category" → "category" key mismatch so POI
colors and shapes render correctly
- journal_panel.gd: parse ToldBy(N) source format, resolve entity
names from player_knowledge; move confidence/source labels to
UIStrings per D-042
- observer/mod.rs: add Changed<KnowledgeGraph> dirty flag to skip
per-tick KG serialization when unchanged
- types.rs: fix stale version doc comment (13 → 14)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Well-structured features with sound core logic. The a82eb07 fix commit correctly addresses POI key, ToldBy parsing, and KG dirty flag. However, two issues remain.
Tests access panel.CONFIDENCE_LABELS and panel.SOURCE_LABELS — constants that don't exist on JournalPanel. Five tests will fail at runtime. Either add the constants to journal_panel.gd or rewrite tests to match the UIStrings-based implementation.
2
client/ui/dialogue_box.gd:541
warning
_escape_bbcode only escapes [ but not ]. Should also .replace("]", "[rb]") for complete BBCode protection. This was flagged as "Hoshe #2" fix but is incomplete.
3
client/ui/dialogue_box.gd:598-609
warning
_expire_entries breaks at first pinned entry — expired entries behind a pinned entry are never cleaned until unpin. Bounded leak but violates the stated contract.
4
client/ui/dialogue_box.gd:349
suggestion
Sort comparator is correct but a comment clarifying "lower value = higher priority" would aid maintainability.
5
server/src/perception/observer/mod.rs:397
suggestion
examine_result: None always — known stub for #242, acceptable but track as regression risk.
6
client/ui/journal_panel.gd:208-214
suggestion
_last_rendered_tick not updated on dialogue-close, causing unnecessary rebuilds after reopen. No functional bug.
Tyre (Architecture): APPROVE
Architecture is sound throughout. D-010/D-012 baselines respected, information boundary honored at every layer, ObserverSnapshot remains the sole client-server data boundary. V14 protocol additions follow established versioning strategy (flat struct, #[serde(default)], additive-only). The a82eb07 fixes are architecturally correct.
#
File
Severity
Issue
1
client/ui/journal_panel.gd:167-183
suggestion
ToldBy parsing fix is correct. to_int() on malformed input degrades gracefully to "#0".
2
server/src/perception/observer/mod.rs:123-124
suggestion
KG dirty flag capture before reborrow is idiomatic bevy_ecs. Empty KG guard handles first-tick edge case.
3
client/ui/journal_panel.gd:212-214
suggestion
Tick-gated rebuild triggers every tick journal is open even if KG unchanged. Acceptable at current entity counts.
4
client/ui/dialogue_box.gd:142
suggestion
Direct call to UIStrings._parse_yaml() crosses private method convention. Future refactor candidate.
Verdict: CHANGES REQUESTED
Hoshe flagged 1 critical (missing constants causing test failures) and 2 warnings (incomplete BBCode escape, pinned entry expiry gap). Tyre approved with suggestions only.
## Review: client -> main (type: code) — PR #65
### Hoshe (Code Quality): REQUEST_CHANGES
Well-structured features with sound core logic. The `a82eb07` fix commit correctly addresses POI key, ToldBy parsing, and KG dirty flag. However, two issues remain.
| # | File | Severity | Issue |
|---|------|----------|-------|
| 1 | `client/tests/test_journal_sprint18.gd:409,421,433,543` | critical | Tests access `panel.CONFIDENCE_LABELS` and `panel.SOURCE_LABELS` — constants that don't exist on `JournalPanel`. Five tests will fail at runtime. Either add the constants to `journal_panel.gd` or rewrite tests to match the UIStrings-based implementation. |
| 2 | `client/ui/dialogue_box.gd:541` | warning | `_escape_bbcode` only escapes `[` but not `]`. Should also `.replace("]", "[rb]")` for complete BBCode protection. This was flagged as "Hoshe #2" fix but is incomplete. |
| 3 | `client/ui/dialogue_box.gd:598-609` | warning | `_expire_entries` breaks at first pinned entry — expired entries behind a pinned entry are never cleaned until unpin. Bounded leak but violates the stated contract. |
| 4 | `client/ui/dialogue_box.gd:349` | suggestion | Sort comparator is correct but a comment clarifying "lower value = higher priority" would aid maintainability. |
| 5 | `server/src/perception/observer/mod.rs:397` | suggestion | `examine_result: None` always — known stub for #242, acceptable but track as regression risk. |
| 6 | `client/ui/journal_panel.gd:208-214` | suggestion | `_last_rendered_tick` not updated on dialogue-close, causing unnecessary rebuilds after reopen. No functional bug. |
### Tyre (Architecture): APPROVE
Architecture is sound throughout. D-010/D-012 baselines respected, information boundary honored at every layer, `ObserverSnapshot` remains the sole client-server data boundary. V14 protocol additions follow established versioning strategy (flat struct, `#[serde(default)]`, additive-only). The `a82eb07` fixes are architecturally correct.
| # | File | Severity | Issue |
|---|------|----------|-------|
| 1 | `client/ui/journal_panel.gd:167-183` | suggestion | ToldBy parsing fix is correct. `to_int()` on malformed input degrades gracefully to `"#0"`. |
| 2 | `server/src/perception/observer/mod.rs:123-124` | suggestion | KG dirty flag capture before reborrow is idiomatic bevy_ecs. Empty KG guard handles first-tick edge case. |
| 3 | `client/ui/journal_panel.gd:212-214` | suggestion | Tick-gated rebuild triggers every tick journal is open even if KG unchanged. Acceptable at current entity counts. |
| 4 | `client/ui/dialogue_box.gd:142` | suggestion | Direct call to `UIStrings._parse_yaml()` crosses private method convention. Future refactor candidate. |
### Verdict: CHANGES REQUESTED
Hoshe flagged 1 critical (missing constants causing test failures) and 2 warnings (incomplete BBCode escape, pinned entry expiry gap). Tyre approved with suggestions only.
- test_journal_sprint18.gd: replace references to removed
CONFIDENCE_LABELS/SOURCE_LABELS with UIStrings key tests and
regression guards
- dialogue_box.gd: escape ] as [rb] in _escape_bbcode for complete
BBCode injection protection
- dialogue_box.gd: fix _expire_entries to skip pinned entries with
continue instead of break, cleaning expired entries behind pins
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Sprint 18: Touch — Client team deliverables.
poi_list(minimap),examine_result(examine overlay),player_knowledge(journal). Server populates live from KG and PointOfInterest components.Decision compliance
D-013 (diegetic insert), D-020 (client pure renderer), D-041 (KG data model), D-042 (UIStrings YAML), D-049 (z-layer 6), D-061 (dialogue box), D-062 (invisible locked), D-063 (confrontation), D-064 (walk-away)
Test plan
Review: client → main (PR #65, type: code)
Hoshe (Code Quality): REQUEST_CHANGES
Good test coverage and clean feature implementation, but two runtime defects.
client/ui/minimap.gd:94"poi_category"but decoder stores"category". All POIs render as default white circles.client/ui/journal_panel.gd:32-37SOURCE_LABELS["ToldBy"]never matches server's"ToldBy(12)"format. Raw entity IDs shown in journal.server/src/bridge/types.rs:45client/ui/dialogue_box.gd:598-608client/ui/dialogue_box.gd:654-659Tyre (Architecture): REQUEST_CHANGES
Architecture is sound — D-010/D-012 respected throughout. Two issues need fixing.
client/ui/minimap.gd:94server/src/perception/observer/mod.rs:292-366player_knowledgeserialized every tick with no dirty flag — contradicts design comment, will cause per-tick allocation spikes as KG grows.server/src/bridge/types.rs:45client/ui/dialogue_box.gd:142UIStrings._parse_yaml()— couples to internal API.client/ui/journal_panel.gd:88-106Verdict: CHANGES REQUESTED
Deduplicated blockers:
"category"vs"poi_category"key mismatch (one-line fix in minimap.gd)ToldBy(N)source label never matchesSOURCE_LABELSdictReview: client -> main (type: code) — PR #65
Hoshe (Code Quality): REQUEST_CHANGES
Well-structured features with sound core logic. The
a82eb07fix commit correctly addresses POI key, ToldBy parsing, and KG dirty flag. However, two issues remain.client/tests/test_journal_sprint18.gd:409,421,433,543panel.CONFIDENCE_LABELSandpanel.SOURCE_LABELS— constants that don't exist onJournalPanel. Five tests will fail at runtime. Either add the constants tojournal_panel.gdor rewrite tests to match the UIStrings-based implementation.client/ui/dialogue_box.gd:541_escape_bbcodeonly escapes[but not]. Should also.replace("]", "[rb]")for complete BBCode protection. This was flagged as "Hoshe #2" fix but is incomplete.client/ui/dialogue_box.gd:598-609_expire_entriesbreaks at first pinned entry — expired entries behind a pinned entry are never cleaned until unpin. Bounded leak but violates the stated contract.client/ui/dialogue_box.gd:349server/src/perception/observer/mod.rs:397examine_result: Nonealways — known stub for #242, acceptable but track as regression risk.client/ui/journal_panel.gd:208-214_last_rendered_ticknot updated on dialogue-close, causing unnecessary rebuilds after reopen. No functional bug.Tyre (Architecture): APPROVE
Architecture is sound throughout. D-010/D-012 baselines respected, information boundary honored at every layer,
ObserverSnapshotremains the sole client-server data boundary. V14 protocol additions follow established versioning strategy (flat struct,#[serde(default)], additive-only). Thea82eb07fixes are architecturally correct.client/ui/journal_panel.gd:167-183to_int()on malformed input degrades gracefully to"#0".server/src/perception/observer/mod.rs:123-124client/ui/journal_panel.gd:212-214client/ui/dialogue_box.gd:142UIStrings._parse_yaml()crosses private method convention. Future refactor candidate.Verdict: CHANGES REQUESTED
Hoshe flagged 1 critical (missing constants causing test failures) and 2 warnings (incomplete BBCode escape, pinned entry expiry gap). Tyre approved with suggestions only.
Review Round 3: client -> main — PR #65
Hoshe (Code Quality): APPROVE
All three round 2 issues confirmed fixed:
[and].continuepast pinned entries instead ofbreak.client/ui/dialogue_box.gd:615-621client/tests/test_dialogue_sprint18.gd:432-440[rb]for]escaping.Tyre (Architecture): APPROVE
Fix commit is narrow and correct. D-042 boundary respected. D-010 information boundary intact. No new concerns.
Verdict: APPROVED
Ready to merge.
Pull request closed