backend-infra-engineer: Post v0.3.9-hotfix7 snapshot (build cleanup)

This commit is contained in:
scawful
2025-12-22 00:20:49 +00:00
parent 2934c82b75
commit 5c4cd57ff8
1259 changed files with 239160 additions and 43801 deletions

View File

@@ -0,0 +1,132 @@
# Documentation Cleanup Summary - November 2025
**Date:** 2025-11-24
**Action:** Cleanup of speculative planning documents and AI-generated bloat from `/docs/internal/plans/`
**Rationale:** Planning documents should live in GitHub issues and coordination board, not as static markdown. Only actionable, actively-tracked plans belong in the codebase.
## Files Deleted (Pure AI-Generated Bloat)
These files were entirely speculative with no corresponding implementation:
1. **asm-debug-prompt-engineering.md** (45KB)
- Extensive prompt templates for 65816 debugging
- No evidence of integration or use
- Classified as AI-generated reference material
2. **ai-assisted-development-plan.md** (17KB)
- Workflow proposal for AI-assisted development
- All features marked "Active" with "Next Review" dates but never implemented
- Generic architecture diagrams with no corresponding code
3. **app-dev-agent-tools.md** (21KB)
- 824 lines specifying 16 agent tools (build, code analysis, debug, editor integration)
- All tools in Phase 1-3 (theoretical)
- No implementation in codebase or recent commits
4. **EDITOR_ROADMAPS_2025-11.md** (25KB)
- Multi-agent analysis document referencing "imgui-frontend-engineer" agent analysis
- Generic roadmap format with estimated effort hours
- Duplicate content with dungeon_editor_ui_refactor.md
5. **message_system_improvement_plan.md** (2KB)
- Duplicate of sections in message_editor_implementation_roadmap.md
- Generic feature wishlist (JSON export, translation workspace, search & replace)
- No distinct value
6. **graphics_system_improvement_plan.md** (2.8KB)
- Feature wishlist (unified editor, palette management, sprite assembly)
- No concrete deliverables or implementation plan
- Superseded by architecture documentation
7. **ui_modernization.md** (3.3KB)
- Describes patterns already documented in CLAUDE.md
- Marked "Active" but content is obsolete (already implemented)
- Redundant with existing guidelines
## Files Archived (Partially Implemented / Historical Reference)
These files have some value as reference but are not actively tracked work:
1. **emulator-debug-api-design.md**`archive/plans-2025-11/`
- Design document for emulator debugging API
- Some features implemented (breakpoints, memory inspection)
- Watchpoints and symbol loading still planned but deprioritized
- Value: Technical reference for future work
2. **message_editor_implementation_roadmap.md**`archive/plans-2025-11/`
- References actual code (MessageData, MessagePreview classes)
- Documents what's completed vs. what's missing (JSON import/export)
- Some ongoing development but should be tracked in coordination board
- Value: Implementation reference
3. **hex_editor_enhancements.md**`archive/plans-2025-11/`
- Phase 1 (Data Inspector) concept defined
- Phases 2-4 unimplemented
- Better tracked as GitHub issue than static plan
- Value: Technical spike reference
4. **dungeon_editor_ui_refactor.md**`archive/plans-2025-11/`
- Actually referenced in git commit acab491a1f (component was removed)
- Concrete refactoring steps with clear deliverables
- Now completed/obsolete
- Value: Historical record of refactoring
## Files Retained (Actively Tracked)
1. **web_port_strategy.md**
- Strategic milestone document for WASM port
- Multiple recent commits show active ongoing work (52b1a99, 56e05bf, 206e926, etc.)
- Clear milestones with deliverables
- Actively referenced in CI/build processes
- Status: KEEP - actively developed feature
2. **ai-infra-improvements.md**
- Structured phase-based plan (gRPC server, emulator RPCs, breakpoints, symbols)
- More specific than other plans with concrete files to modify
- Tracks infrastructure gaps with file references
- Status: KEEP - tracks ongoing infrastructure work
3. **README.md**
- Directory governance and guidelines
- Actively enforces plan organization standards
- Status: KEEP - essential for directory management
## Rationale for This Cleanup
### Problem
- 14 planning files (400KB) in `/docs/internal/plans/`
- Most marked "Active" with forward-looking dates (Nov 25 → Dec 2)
- Little correlation with actual work in recent commits
- Directory becoming a repository of speculative AI-generated content
### Solution
- Keep only plans with active ongoing work (2 files)
- Archive reference documents with partial implementation (4 files)
- Delete pure speculation and AI-generated bloat (7 files)
- Directory size reduced from 400KB to 13KB at root level
### Principle
**Planning belongs in GitHub issues and coordination board, not in markdown files.**
Static plan documents should only exist for:
1. Strategic initiatives (like WASM web port) with active commits
2. Infrastructure work with concrete phases and file references
3. Historical reference after completion
Speculative planning should use:
- GitHub Discussions for RFCs
- Issues with labels for feature requests
- Coordination board for multi-agent work tracking
## Files in Archive
```
docs/internal/agents/archive/plans-2025-11/
├── CLEANUP_SUMMARY.md
├── dungeon_editor_ui_refactor.md
├── emulator-debug-api-design.md
├── hex_editor_enhancements.md
└── message_editor_implementation_roadmap.md
```
These are available if needed as historical context but should not be referenced for active development.

View File

@@ -0,0 +1,48 @@
# Dungeon Editor UI Refactor Plan
## 1. Overview
The Dungeon Editor currently uses a primitive "colored square" representation for objects in the object selector, despite having a full-fidelity rendering component (`DungeonObjectSelector`) available. This plan outlines the refactoring steps to integrate the game-accurate object browser into the main `ObjectEditorCard`, improving UX and eliminating code duplication.
## 2. Current State Analysis
- **`ObjectEditorCard` (Active UI):** Reimplements object selection logic in `DrawObjectSelector()`. Renders objects as simple colored rectangles (`DrawObjectPreviewIcon`).
- **`DungeonObjectSelector` (Component):** Contains `DrawObjectAssetBrowser()`, which uses `ObjectDrawer` to render actual tile graphics. This component is instantiated as a member `object_selector_` in `ObjectEditorCard` but is effectively unused.
- **`DungeonEditorV2`:** Instantiates a separate, unused `DungeonObjectSelector` (`object_selector_`), adding to the confusion.
## 3. Implementation Plan
### Phase 1: Component Preparation
1. **Expose UI Method:** Ensure `DungeonObjectSelector::DrawObjectAssetBrowser()` is public or accessible to `ObjectEditorCard`.
2. **State Synchronization:** Ensure `DungeonObjectSelector` has access to the same `Rom` and `PaletteGroup` data as `ObjectEditorCard` so it can render correctly.
### Phase 2: Refactor ObjectEditorCard
1. **Delegate Rendering:** Replace the body of `ObjectEditorCard::DrawObjectSelector()` with a call to `object_selector_.DrawObjectAssetBrowser()`.
2. **Callback Wiring:**
* In `ObjectEditorCard::Initialize` (or constructor), set up the callback for `object_selector_`.
* When an object is selected in `object_selector_`, it should update `ObjectEditorCard::preview_object_` and `canvas_viewer_`.
* Current logic:
```cpp
object_selector_.SetObjectSelectedCallback([this](const zelda3::RoomObject& obj) {
this->preview_object_ = obj;
this->has_preview_object_ = true;
this->canvas_viewer_->SetPreviewObject(obj);
this->interaction_mode_ = InteractionMode::Place;
});
```
3. **Cleanup:** Remove private helper `DrawObjectPreviewIcon` and the old loop logic in `ObjectEditorCard`.
### Phase 3: Cleanup DungeonEditorV2
1. **Remove Redundancy:** Remove the top-level `DungeonObjectSelector object_selector_` from `DungeonEditorV2`. The one inside `ObjectEditorCard` is sufficient.
2. **Verify Initialization:** Ensure `DungeonEditorV2` correctly initializes `ObjectEditorCard` with the necessary dependencies.
## 4. Verification
1. **Build:** Compile `yaze`.
2. **Test:** Open Dungeon Editor -> Object Editor tab.
3. **Expectation:** The object list should now show actual graphics (walls, chests, pots) instead of colored squares.
4. **Interaction:** Clicking an object should correctly load it into the cursor for placement.
## 5. Dependencies
- `src/app/editor/dungeon/object_editor_card.cc`
- `src/app/editor/dungeon/object_editor_card.h`
- `src/app/editor/dungeon/dungeon_object_selector.cc`
- `src/app/editor/dungeon/dungeon_object_selector.h`
- `src/app/editor/dungeon/dungeon_editor_v2.h`

View File

@@ -0,0 +1,516 @@
# Emulator Debug API Design for AI Agent Integration
**Status:** Active
**Owner (Agent ID):** snes-emulator-expert
**Last Updated:** 2025-11-25
**Next Review:** 2025-12-02
**Coordination Board Entry:** link when claimed
## Executive Summary
This document outlines the design for a comprehensive debugging API that enables AI agents to debug Zelda ROM hacks through the yaze emulator. The API provides execution control, memory inspection, disassembly, and analysis capabilities specifically tailored for 65816 and SPC700 debugging.
## Architecture Overview
```
┌──────────────────┐ ┌─────────────────┐ ┌──────────────────┐
│ AI Agent │◄────►│ Tool Dispatcher │◄────►│ gRPC Service │
│ (Claude/GPT) │ │ │ │ │
└──────────────────┘ └─────────────────┘ └──────────────────┘
│ │
▼ ▼
┌─────────────────┐ ┌──────────────────┐
│ Tool Handlers │ │ Emulator Service │
│ │ │ Implementation │
└─────────────────┘ └──────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────┐
│ Debug Infrastructure │
├─────────────────┬───────────────────────┤
│ Disassembler │ Step Controller │
│ Symbol Provider │ Breakpoint Manager │
│ Memory Tracker │ State Snapshots │
└─────────────────┴───────────────────────┘
```
## Phase 1 (MVP) Features
### 1. Execution Control API
```cpp
// Tool Dispatcher Commands
enum class EmulatorDebugTool {
// Basic execution
kDebugRun, // Run until breakpoint or pause
kDebugStep, // Single instruction step
kDebugStepOver, // Step over JSR/JSL calls
kDebugStepOut, // Step out of current subroutine
kDebugPause, // Pause execution
kDebugReset, // Reset to power-on state
// Breakpoint management
kDebugSetBreak, // Set execution breakpoint
kDebugClearBreak, // Clear breakpoint by ID
kDebugListBreaks, // List all breakpoints
kDebugToggleBreak, // Enable/disable breakpoint
};
```
#### Example Tool Call Structure:
```cpp
struct DebugStepRequest {
enum StepType {
SINGLE, // One instruction
OVER, // Step over calls
OUT, // Step out of routine
TO_ADDRESS // Run to specific address
};
StepType type;
uint32_t target_address; // For TO_ADDRESS
uint32_t max_steps; // Timeout protection
};
struct DebugStepResponse {
bool success;
uint32_t pc; // New program counter
uint32_t instruction_count;
DisassembledInstruction current_instruction;
std::vector<std::string> call_stack;
std::string message;
};
```
### 2. Memory Inspection API
```cpp
enum class MemoryDebugTool {
kMemoryRead, // Read memory region
kMemoryWrite, // Write memory (for patching)
kMemoryWatch, // Set memory watchpoint
kMemoryCompare, // Compare two memory regions
kMemorySearch, // Search for byte pattern
kMemorySnapshot, // Save memory state
kMemoryDiff, // Diff against snapshot
};
```
#### Memory Region Types:
```cpp
enum class MemoryRegion {
WRAM, // Work RAM ($7E0000-$7FFFFF)
SRAM, // Save RAM ($700000-$77FFFF)
ROM, // ROM banks ($008000-$FFFFFF)
VRAM, // Video RAM (PPU)
OAM, // Sprite data
CGRAM, // Palette data
APU_RAM, // Audio RAM ($0000-$FFFF in SPC700 space)
};
struct MemoryReadRequest {
MemoryRegion region;
uint32_t address; // 24-bit SNES address
uint32_t size; // Bytes to read
bool as_hex; // Format as hex dump
bool with_symbols; // Include symbol annotations
};
struct MemoryReadResponse {
std::vector<uint8_t> data;
std::string hex_dump;
std::map<uint32_t, std::string> symbols; // Address -> symbol name
std::string interpretation; // AI-friendly interpretation
};
```
### 3. Disassembly API
```cpp
enum class DisassemblyTool {
kDisassemble, // Disassemble at address
kDisassembleRange, // Disassemble N instructions
kDisassembleContext, // Show surrounding code
kFindInstruction, // Search for instruction pattern
kGetCallStack, // Get current call stack
kTraceExecution, // Get execution history
};
```
#### Disassembly Request/Response:
```cpp
struct DisassemblyRequest {
uint32_t address;
uint32_t instruction_count;
uint32_t context_before; // Instructions before target
uint32_t context_after; // Instructions after target
bool include_symbols;
bool include_execution_counts;
bool track_branches; // Show branch targets
};
struct DisassemblyResponse {
struct Line {
uint32_t address;
std::string hex_bytes; // "20 34 80"
std::string mnemonic; // "JSR"
std::string operands; // "$8034"
std::string symbol; // "MainGameLoop"
std::string comment; // "; Initialize game state"
bool is_breakpoint;
bool is_current_pc;
uint32_t execution_count;
uint32_t branch_target; // For jumps/branches
};
std::vector<Line> lines;
std::string formatted_text; // Human-readable disassembly
std::vector<std::string> referenced_symbols;
};
```
### 4. Analysis API
```cpp
enum class AnalysisTool {
kAnalyzeRoutine, // Analyze subroutine behavior
kFindReferences, // Find references to address
kDetectPattern, // Detect common bug patterns
kCompareRom, // Compare with original ROM
kProfileExecution, // Performance profiling
kTrackDataFlow, // Track value propagation
};
```
## Tool Dispatcher Integration
### New Tool Definitions
```cpp
// In tool_dispatcher.h
enum class ToolCallType {
// ... existing tools ...
// Debugger - Execution Control
kDebugRun,
kDebugStep,
kDebugStepOver,
kDebugStepOut,
kDebugRunToAddress,
// Debugger - Breakpoints
kDebugSetBreakpoint,
kDebugSetWatchpoint,
kDebugClearBreakpoint,
kDebugListBreakpoints,
kDebugEnableBreakpoint,
// Debugger - Memory
kDebugReadMemory,
kDebugWriteMemory,
kDebugSearchMemory,
kDebugCompareMemory,
kDebugSnapshotMemory,
// Debugger - Disassembly
kDebugDisassemble,
kDebugGetCallStack,
kDebugGetExecutionTrace,
kDebugFindInstruction,
// Debugger - Analysis
kDebugAnalyzeRoutine,
kDebugFindReferences,
kDebugDetectBugs,
kDebugProfileCode,
};
```
### Tool Handler Implementation
```cpp
class DebuggerToolHandler {
public:
explicit DebuggerToolHandler(EmulatorServiceImpl* service);
absl::StatusOr<ToolResponse> HandleDebugStep(const nlohmann::json& params);
absl::StatusOr<ToolResponse> HandleDebugSetBreakpoint(const nlohmann::json& params);
absl::StatusOr<ToolResponse> HandleDebugDisassemble(const nlohmann::json& params);
absl::StatusOr<ToolResponse> HandleDebugReadMemory(const nlohmann::json& params);
absl::StatusOr<ToolResponse> HandleDebugAnalyze(const nlohmann::json& params);
private:
EmulatorServiceImpl* emulator_service_;
Disassembler65816 disassembler_;
SymbolProvider symbol_provider_;
MemoryAnalyzer analyzer_;
};
```
## Example AI Agent Interactions
### Example 1: Debugging a Crash
**Agent Query:**
```json
{
"tool": "debug_analyze",
"params": {
"problem": "Game crashes when entering dungeon room 15",
"context": {
"room_id": 15,
"entrance_id": 3
}
}
}
```
**System Response:**
```json
{
"analysis": {
"crash_location": {
"address": "0x008A45",
"instruction": "LDA [$00],Y",
"symbol": "LoadRoomHeader+0x15"
},
"cause": "Null pointer dereference",
"explanation": "Direct page location $00 contains $0000, causing invalid long pointer access",
"registers_at_crash": {
"Y": "0x0010",
"DP": "0x1E00",
"$1E00": "0x0000"
},
"suggested_fix": "Check room header pointer before dereferencing",
"call_stack": [
"Module_Dungeon",
"Dungeon_LoadRoom",
"LoadRoomHeader"
]
}
}
```
### Example 2: Step-by-Step Debugging
**Agent Query:**
```json
{
"tool": "debug_step",
"params": {
"type": "over",
"with_context": true,
"show_memory": ["$7E0010", "$7E0012"]
}
}
```
**Response:**
```json
{
"pc_before": "0x008034",
"pc_after": "0x008037",
"instruction_executed": {
"address": "0x008034",
"mnemonic": "JSR",
"operand": "$8520",
"symbol": "UpdateSprites",
"cycles": 6
},
"context": {
"before": [
{"address": "0x008031", "instruction": "LDA $10", "value": "0x07"}
],
"after": [
{"address": "0x008037", "instruction": "BEQ $8045"}
]
},
"memory_values": {
"$7E0010": "0x07",
"$7E0012": "0x00"
},
"call_depth": 2
}
```
### Example 3: Finding Bug Patterns
**Agent Query:**
```json
{
"tool": "debug_detect_bugs",
"params": {
"patterns": ["stack_overflow", "invalid_bank", "dma_collision"],
"range": {
"start": "0x008000",
"end": "0x00FFFF"
}
}
}
```
**Response:**
```json
{
"bugs_found": [
{
"type": "potential_stack_overflow",
"location": "0x009A23",
"description": "Recursive JSR without stack check",
"severity": "high",
"suggestion": "Add stack pointer validation before recursive call"
},
{
"type": "invalid_bank_switch",
"location": "0x00B456",
"description": "PHB without corresponding PLB",
"severity": "medium",
"suggestion": "Ensure data bank is restored after operation"
}
]
}
```
### Example 4: Memory Watchpoint
**Agent Query:**
```json
{
"tool": "debug_set_watchpoint",
"params": {
"address": "0x7E0020",
"size": 2,
"type": "write",
"condition": "value > 0x00FF",
"description": "Monitor game state overflow"
}
}
```
**Response:**
```json
{
"watchpoint_id": 5,
"status": "active",
"message": "Watchpoint set on $7E0020-$7E0021 for writes > 0x00FF"
}
```
## Phase 2 (Full) Features
### Advanced Analysis
- **Control Flow Graphs**: Generate CFG for routines
- **Data Flow Analysis**: Track value propagation through code
- **Symbolic Execution**: Analyze possible execution paths
- **Pattern Matching**: Detect specific code patterns (e.g., DMA setup, HDMA tables)
- **Performance Profiling**: Cycle-accurate performance analysis
### Enhanced Debugging
- **Conditional Breakpoints**: Complex expressions (e.g., "A > 0x10 && X == 0")
- **Trace Recording**: Record full execution traces to file
- **Reverse Debugging**: Step backwards through recorded execution
- **Memory Diffing**: Visual diff between memory states
- **SPC700 Debugging**: Full audio processor debugging support
### AI-Specific Features
- **Semantic Analysis**: Understanding game logic from assembly
- **Bug Pattern Database**: ML-trained bug detection
- **Automated Fix Suggestions**: Propose assembly patches for bugs
- **Test Case Generation**: Generate test scenarios for ROM hacks
- **Documentation Generation**: Auto-document assembly routines
## Implementation Priority
### Phase 1A (Immediate - Week 1-2)
1. Basic step control (single, over, out)
2. Simple breakpoints (address-based)
3. Memory read/write operations
4. Basic disassembly at address
### Phase 1B (Short-term - Week 3-4)
1. Call stack tracking
2. Symbol resolution
3. Memory watchpoints
4. Execution trace (last N instructions)
### Phase 1C (Medium-term - Week 5-6)
1. Pattern-based bug detection
2. Memory snapshots and comparison
3. Advanced breakpoint conditions
4. Performance metrics
### Phase 2 (Long-term - Month 2+)
1. Full analysis suite
2. SPC700 debugging
3. Reverse debugging
4. AI-specific enhancements
## Success Metrics
### Technical Metrics
- Response time < 100ms for step operations
- Support for 100+ simultaneous breakpoints without performance impact
- Accurate disassembly for 100% of valid 65816 opcodes
- Symbol resolution for all loaded ASM files
### User Experience Metrics
- AI agents can identify crash causes in < 5 interactions
- Step debugging provides sufficient context without overwhelming
- Memory inspection clearly shows relevant game state
- Bug detection has < 10% false positive rate
## Integration Points
### With Existing yaze Components
- **Rom Class**: Read-only access to ROM data
- **Emulator Core**: Direct CPU/PPU/APU state access
- **Symbol Files**: Integration with usdasm output
- **Canvas System**: Visual debugging overlays (Phase 2)
### With AI Infrastructure
- **Tool Dispatcher**: Seamless tool call routing
- **Prompt Builder**: Context-aware debugging prompts
- **Agent Memory**: Persistent debugging session state
- **Response Formatter**: Human-readable debug output
## Security Considerations
1. **Read-Only by Default**: Prevent accidental ROM corruption
2. **Sandboxed Execution**: Limit memory access to emulated space
3. **Rate Limiting**: Prevent runaway debugging loops
4. **Audit Logging**: Track all debugging operations
5. **Session Isolation**: Separate debug sessions per agent
## Testing Strategy
### Unit Tests
- Disassembler accuracy for all opcodes
- Step controller call stack tracking
- Breakpoint manager hit detection
- Symbol provider resolution
### Integration Tests
- Full debugging session workflows
- gRPC service communication
- Tool dispatcher routing
- Memory state consistency
### End-to-End Tests
- AI agent debugging scenarios
- Bug detection accuracy
- Performance under load
- Error recovery paths
## Documentation Requirements
1. **API Reference**: Complete gRPC service documentation
2. **Tool Guide**: How to use each debugging tool
3. **Assembly Primer**: 65816 basics for AI agents
4. **Common Patterns**: Debugging patterns for Zelda3
5. **Troubleshooting**: Common issues and solutions
## Conclusion
This debugging API design provides a comprehensive foundation for AI agents to effectively debug SNES ROM hacks. The phased approach ensures quick delivery of core features while building toward advanced analysis capabilities. The integration with existing yaze infrastructure and focus on 65816-specific debugging makes this a powerful tool for ROM hacking assistance.
The API balances technical depth with usability, providing both low-level control for precise debugging and high-level analysis for pattern recognition. This enables AI agents to assist with everything from simple crash debugging to complex performance optimization.

View File

@@ -0,0 +1,80 @@
# Plan: Hex Editor Enhancements (Inspired by ImHex)
**Status:** Active
**Owner (Agent ID):** imgui-frontend-engineer
**Last Updated:** 2025-11-25
**Next Review:** 2025-12-02
**Coordination Board Entry:** link when claimed
This document outlines the roadmap for enhancing the `yaze` Memory/Hex Editor to provide robust analysis tools similar to ImHex.
## Phase 1: Data Inspector (High Priority)
**Goal:** Provide immediate context for the selected byte(s) in the Hex Editor without mental math.
**Implementation Steps:**
1. **Create `DataInspector` Component:**
* A standalone ImGui widget (`src/app/editor/code/data_inspector.h/cc`).
* Accepts a `const uint8_t* data_ptr` and `size_t max_len`.
2. **Standard Types:**
* Decode and display Little Endian values:
* `int8_t` / `uint8_t`
* `int16_t` / `uint16_t`
* `int24_t` / `uint24_t` (Common SNES pointers)
* `int32_t` / `uint32_t`
* Display Binary representation (`00001111`).
3. **SNES-Specific Types (The "Yaze" Value):**
* **SNES LoROM Address:** Convert the physical offset to `$BB:AAAA` format.
* **RGB555 Color:** Interpret 2 bytes as `0bbbbbgggggrrrrr`. Show a colored rectangle preview.
* **Tile Attribute:** Interpret byte as `vhopppcc` (Vertical/Horizontal flip, Priority, Palette, Tile High bit).
4. **Integration:**
* Modify `MemoryEditorWithDiffChecker` to instantiate and render `DataInspector` in a sidebar or child window next to the main hex grid.
* Hook into the hex editor's "Selection Changed" event (or poll selection state) to update the Inspector.
## Phase 2: Entropy Navigation (Navigation)
**Goal:** Visualize the ROM's structure to quickly find free space, graphics, or code.
**Implementation Steps:**
1. **Entropy Calculator:**
* Create a utility to calculate Shannon entropy for blocks of data (e.g., 256-byte chunks).
* Run this calculation in a background thread when a ROM is loaded to generate an `EntropyMap`.
2. **Minimap Widget:**
* Render a thin vertical bar next to the hex scrollbar.
* Map the file offset to vertical pixels.
* **Color Coding:**
* **Black:** Zeroes (`0x00` fill).
* **Dark Grey:** `0xFF` fill (common flash erase value).
* **Blue:** Low entropy (Text, Tables).
* **Red:** High entropy (Compressed Graphics, Code).
3. **Interaction:**
* Clicking the minimap jumps the Hex Editor to that offset.
## Phase 3: Structure Templates (Advanced Analysis)
**Goal:** Define and visualize complex data structures on top of the raw hex.
**Implementation Steps:**
1. **Template Definition System:**
* Define a C++-based schema builder (e.g., `StructBuilder("Header").AddString("Title", 21).AddByte("MapMode")...`).
2. **Visualizer:**
* Render these structures as a tree view (ImGui TreeNodes).
* When a tree node is hovered, highlight the corresponding bytes in the Hex Editor grid.
3. **Standard Templates:**
* Implement templates for known ALTTP structures: `SNES Header`, `Dungeon Header`, `Sprite Properties`.
## Phase 4: Disassembly Integration
**Goal:** Seamless transition between data viewing and code analysis.
**Implementation Steps:**
1. **Context Menu:** Add "Disassemble Here" to the Hex Editor right-click menu.
2. **Disassembly View:**
* Invoke the `disassembler` (already present in `app/emu/debug`) on the selected range.
* Display the output in a popup or switch to the Assembly Editor.
---
## Initial Work Item: Data Inspector
We will begin with Phase 1. This requires creating the `DataInspector` class and hooking it into `MemoryEditorWithDiffChecker`.

View File

@@ -0,0 +1,774 @@
# Message Editor Implementation Roadmap
**Status**: Active Development
**Owner (Agent ID)**: imgui-frontend-engineer
**Last Updated**: 2025-11-25
**Next Review**: 2025-12-02
**Coordination Board Entry**: link when claimed
**Related Docs**:
- `docs/internal/architecture/message_system.md` (Gemini's architecture vision)
- `docs/internal/plans/message_system_improvement_plan.md` (Gemini's feature proposals)
---
## Executive Summary
This roadmap bridges Gemini's architectural vision with practical implementation steps for completing the Message Editor. The current implementation has the **core foundation** in place (message parsing, dictionary system, preview rendering) but lacks several key features proposed in Gemini's plan, particularly around **JSON import/export**, **translation workflows**, and **theme integration**.
---
## Current State Analysis
### What's Working (Completed Features)
#### Core Data Layer ✅
- **MessageData**: Full implementation with raw/parsed representations
- **DictionaryEntry**: Compression system with dictionary optimization
- **TextElement**: Command and special character parsing
- **Character Encoding**: Complete CharEncoder table (0x00-0x66)
- **ROM Reading**: `ReadAllTextData()` successfully loads all 396 messages
- **ROM Writing**: `Save()` handles two-bank text data with overflow detection
#### Message Preview System ✅
- **MessagePreview**: Live rendering of messages as they appear in-game
- **Font Graphics**: 2BPP font tiles loaded and displayed at 0x70000
- **Character Widths**: Proportional font support via width table at 0x74ADF
- **Preview Bitmap**: Real-time message rendering with proper palette support
#### Editor UI ✅
- **Card System**: Four dockable cards (Message List, Editor, Font Atlas, Dictionary)
- **Message List**: Table view with ID, contents, and address columns
- **Text Editor**: Multiline input with live preview updates
- **Command Insertion**: Buttons to insert text commands and special characters
- **Dictionary Display**: Read-only view of all 97 dictionary entries
- **Expanded Messages**: Basic support for loading external message bins
#### Testing Coverage ✅
- **Unit Tests**: 20+ tests covering parsing, encoding, dictionary optimization
- **Integration Tests**: ROM-dependent tests verify actual game data
- **Command Parsing**: Regression tests for argument handling bugs
#### CLI Integration ✅
- **Message List**: `z3ed message list --format json --range 0-100`
- **Message Read**: `z3ed message read --id 5 --format json`
- **Message Search**: `z3ed message search --query "Link"`
- **Message Stats**: `z3ed message stats --format json`
### What's Missing (Gaps vs. Gemini's Vision)
#### 1. JSON Import/Export ❌ (HIGH PRIORITY)
**Status**: Not implemented
**Gemini's Vision**:
```json
[
{
"id": 0,
"address": 917504,
"text": "[W:00][SPD:00]Welcome to [D:05]...",
"context": "Uncle dying in sewers"
}
]
```
**Current Gap**:
- No `SerializeMessages()` or `DeserializeMessages()` in `MessageData`
- No UI for export/import operations
- No context field for translator notes
- CLI has JSON output but not JSON input
**Impact**: Cannot version control text, cannot use external editors, cannot collaborate with translators
---
#### 2. Translation Workspace ❌ (MEDIUM PRIORITY)
**Status**: Not implemented
**Gemini's Vision**: Side-by-side view with reference ROM/JSON and editable translation
**Current Gap**:
- No reference text display
- No side-by-side layout
- No translation progress tracking
- No language-specific dictionary optimization
**Impact**: Manual translation workflows are tedious and error-prone
---
#### 3. Search & Replace ⚠️ (PARTIAL)
**Status**: Stub implementation exists
**Gemini's Vision**: Regex support, batch replace across all messages
**Current Implementation**:
- `Find()` method exists in `MessageEditor` (lines 574-600)
- Basic UI skeleton present (search input, case sensitivity toggle)
- **Missing**: Replace functionality, regex support, "Find All", multi-message operations
**Impact**: Global text edits require manual per-message changes
---
#### 4. Theme Integration ❌ (LOW PRIORITY - UI POLISH)
**Status**: Not implemented
**Current Issues**:
- No hardcoded `ImVec4` colors found (GOOD!)
- Not using `AgentUITheme` system for consistency
- Missing semantic color names for message editor components
**Impact**: Message Editor UI may not match rest of application theme
---
#### 5. Expanded ROM Support ⚠️ (PARTIAL)
**Status**: Basic implementation exists
**Gemini's Vision**: Repointing text blocks to expanded ROM space (Banks 10+), automatic bank switching
**Current Implementation**:
- Can load expanded message bins (lines 322-334)
- Can save expanded messages (lines 497-508)
- **Missing**: Repointing logic, bank management, automatic overflow handling
**Impact**: Cannot support large translation projects that exceed vanilla space
---
#### 6. Scripting Integration ❌ (FUTURE)
**Status**: Not planned
**Gemini's Vision**: Lua/Python API for procedural text generation
**Current Gap**: No scripting hooks in message system
**Impact**: Low - nice-to-have for advanced users
---
## Architectural Decisions Required
### Decision 1: JSON Schema Design
**Question**: What fields should the JSON export include?
**Proposal**:
```json
{
"version": "1.0",
"rom_name": "zelda3.sfc",
"messages": [
{
"id": 0,
"address": 917504,
"address_hex": "0xE0000",
"text": "[W:00][SPD:00]Welcome...",
"context": "Optional translator note",
"dictionary_optimized": true,
"expanded": false
}
],
"dictionary": [
{
"id": 0,
"token": "[D:00]",
"contents": "the"
}
]
}
```
**Trade-offs**:
- Verbose but human-readable
- Includes metadata for validation
- Context field for translator workflow
**Status**: ✅ RECOMMENDED
---
### Decision 2: Translation Workspace Layout
**Question**: How should reference vs. translation be displayed?
**Option A**: Side-by-side split pane
```
┌────────────────┬────────────────┐
│ Reference │ Translation │
│ (English) │ (Spanish) │
│ [Read-only] │ [Editable] │
│ │ │
│ Message 0: │ Message 0: │
│ "Welcome to │ "Bienvenido a │
│ Hyrule" │ Hyrule" │
└────────────────┴────────────────┘
```
**Option B**: Top-bottom with context panel
```
┌────────────────────────────────┐
│ Reference: "Welcome to Hyrule" │
│ Context: Uncle's dying words │
├────────────────────────────────┤
│ Translation: │
│ [Editable text box] │
└────────────────────────────────┘
```
**Recommendation**: Option A for large screens, Option B for narrow windows
**Status**: ⚠️ NEEDS USER FEEDBACK
---
### Decision 3: Dictionary Auto-Optimization
**Question**: Should we auto-generate optimal dictionary for new languages?
**Challenges**:
- Dictionary optimization is NP-hard (longest common substring problem)
- Need to preserve ROM space constraints (97 entries max)
- Different languages have different common phrases
**Proposal**:
1. Provide "Analyze Translation" button that suggests optimal dictionary
2. Let user accept/reject suggestions
3. Preserve manual dictionary entries
**Status**: ⚠️ NEEDS RESEARCH
---
## Implementation Priority Matrix
### Phase 1: Foundation (Sprint 1-2 weeks)
**Goal**: JSON import/export with UI integration
#### Task 1.1: Implement JSON Serialization
**Location**: `src/app/editor/message/message_data.h`, `message_data.cc`
**Priority**: P0 (Blocker for translation workflow)
**Estimated Effort**: 3 days
**Implementation**:
```cpp
// In MessageData
nlohmann::json SerializeToJson() const;
static absl::StatusOr<MessageData> DeserializeFromJson(const nlohmann::json& j);
// Free functions
absl::Status ExportMessagesToJson(
const std::vector<MessageData>& messages,
const std::vector<DictionaryEntry>& dictionary,
const std::string& output_path);
absl::StatusOr<std::vector<MessageData>> ImportMessagesFromJson(
const std::string& input_path);
```
**Dependencies**: nlohmann/json (already in project via CPM)
**Acceptance Criteria**:
- [ ] Export all 396 messages to valid JSON
- [ ] Import JSON and verify byte-for-byte ROM equivalence
- [ ] Handle malformed JSON with clear error messages
- [ ] Preserve dictionary optimization
- [ ] Include context field in schema
---
#### Task 1.2: Add Export/Import UI
**Location**: `src/app/editor/message/message_editor.cc`
**Priority**: P0
**Estimated Effort**: 2 days
**UI Additions**:
```cpp
void MessageEditor::DrawExportImportPanel() {
if (ImGui::Button("Export to JSON")) {
std::string path = util::FileDialogWrapper::ShowSaveFileDialog("json");
PRINT_IF_ERROR(ExportMessagesToJson(list_of_texts_,
message_preview_.all_dictionaries_,
path));
}
if (ImGui::Button("Import from JSON")) {
std::string path = util::FileDialogWrapper::ShowOpenFileDialog();
auto result = ImportMessagesFromJson(path);
if (result.ok()) {
list_of_texts_ = result.value();
RefreshMessageList();
}
}
}
```
**Acceptance Criteria**:
- [ ] File dialogs open with correct filters
- [ ] Progress indicator for large exports
- [ ] Confirmation dialog on import (warns about overwriting)
- [ ] Error popup on import failure with details
---
#### Task 1.3: CLI JSON Import Support
**Location**: `src/cli/handlers/game/message.cc`
**Priority**: P1
**Estimated Effort**: 1 day
**Implementation**:
```bash
z3ed message import --json messages.json --rom zelda3.sfc --output zelda3_translated.sfc
```
**Acceptance Criteria**:
- [ ] Import JSON and write to ROM
- [ ] Validate JSON schema before import
- [ ] Verify ROM size constraints
- [ ] Dry-run mode (validate without writing)
---
### Phase 2: Translation Workflow (Sprint 2-3 weeks)
**Goal**: Side-by-side translation UI
#### Task 2.1: Add Translation Mode Card
**Location**: `src/app/editor/message/message_editor.h`, `message_editor.cc`
**Priority**: P1
**Estimated Effort**: 5 days
**New Components**:
```cpp
class TranslationWorkspace {
public:
void Initialize(Rom* reference_rom, Rom* translation_rom);
void DrawUI();
void LoadReferenceFromJson(const std::string& path);
private:
void DrawSideBySideView();
void DrawProgressTracker();
void UpdateTranslationProgress();
std::vector<MessageData> reference_messages_;
std::vector<MessageData> translation_messages_;
std::map<int, bool> translation_complete_flags_;
Rom* reference_rom_ = nullptr;
Rom* translation_rom_ = nullptr;
};
```
**UI Mockup**:
```
┌─────────────────────────────────────────────────┐
│ Translation Progress: 42/396 (10.6%) │
├──────────────────────┬──────────────────────────┤
│ Reference (EN) │ Translation (ES) │
├──────────────────────┼──────────────────────────┤
│ Message 0: │ Message 0: │
│ "Welcome to Hyrule" │ [Editable input box] │
│ │ │
│ Dictionary: [D:05] │ Dictionary: [D:05] │
├──────────────────────┴──────────────────────────┤
│ [Previous] [Next] [Mark Complete] [Skip] │
└─────────────────────────────────────────────────┘
```
**Acceptance Criteria**:
- [ ] Load reference ROM or JSON
- [ ] Display messages side-by-side
- [ ] Track translation progress (per-message completion)
- [ ] Keyboard shortcuts for navigation (Ctrl+N, Ctrl+P)
- [ ] Auto-save translated ROM on completion
---
#### Task 2.2: Context/Notes System
**Location**: `src/app/editor/message/message_data.h`
**Priority**: P2
**Estimated Effort**: 2 days
**Schema Addition**:
```cpp
struct MessageData {
// ... existing fields ...
std::string context; // Translator notes, scene context
std::string screenshot_path; // Optional screenshot reference
nlohmann::json SerializeToJson() const {
return {
{"id", ID},
{"address", Address},
{"text", RawString},
{"context", context},
{"screenshot", screenshot_path}
};
}
};
```
**UI Addition**:
```cpp
void MessageEditor::DrawContextPanel() {
ImGui::InputTextMultiline("Context Notes", &current_message_.context);
if (!current_message_.screenshot_path.empty()) {
ImGui::Image(LoadScreenshot(current_message_.screenshot_path));
}
}
```
**Acceptance Criteria**:
- [ ] Context field persists in JSON export/import
- [ ] Context displayed in translation workspace
- [ ] Optional screenshot attachment (stored as relative path)
---
### Phase 3: Search & Replace (Sprint 3-1 week)
**Goal**: Complete Find/Replace implementation
#### Task 3.1: Implement Replace Functionality
**Location**: `src/app/editor/message/message_editor.cc`
**Priority**: P2
**Estimated Effort**: 2 days
**Implementation**:
```cpp
absl::Status MessageEditor::Replace(const std::string& find_text,
const std::string& replace_text,
bool case_sensitive,
bool whole_word,
bool all_messages) {
int replaced_count = 0;
if (all_messages) {
for (auto& message : list_of_texts_) {
replaced_count += ReplaceInMessage(message, find_text, replace_text,
case_sensitive, whole_word);
}
} else {
replaced_count += ReplaceInMessage(current_message_, find_text,
replace_text, case_sensitive, whole_word);
}
return absl::OkStatus();
}
```
**UI Updates**:
```cpp
void MessageEditor::DrawFindReplacePanel() {
static char find_text[256] = "";
static char replace_text[256] = "";
ImGui::InputText("Find", find_text, IM_ARRAYSIZE(find_text));
ImGui::InputText("Replace", replace_text, IM_ARRAYSIZE(replace_text));
ImGui::Checkbox("Case Sensitive", &case_sensitive_);
ImGui::Checkbox("Whole Word", &match_whole_word_);
ImGui::Checkbox("All Messages", &replace_all_messages_);
if (ImGui::Button("Replace")) {
PRINT_IF_ERROR(Replace(find_text, replace_text, case_sensitive_,
match_whole_word_, false));
}
if (ImGui::Button("Replace All")) {
PRINT_IF_ERROR(Replace(find_text, replace_text, case_sensitive_,
match_whole_word_, true));
}
}
```
**Acceptance Criteria**:
- [ ] Replace in current message
- [ ] Replace in all messages
- [ ] Case-sensitive/insensitive options
- [ ] Whole word matching
- [ ] Undo support (requires history stack)
---
#### Task 3.2: Add Regex Support
**Location**: `src/app/editor/message/message_editor.cc`
**Priority**: P3 (Nice-to-have)
**Estimated Effort**: 2 days
**Implementation**:
```cpp
absl::Status MessageEditor::ReplaceRegex(const std::string& pattern,
const std::string& replacement,
bool all_messages) {
std::regex regex_pattern;
try {
regex_pattern = std::regex(pattern);
} catch (const std::regex_error& e) {
return absl::InvalidArgumentError(
absl::StrFormat("Invalid regex: %s", e.what()));
}
// Perform replacement...
}
```
**Acceptance Criteria**:
- [ ] Regex validation with error messages
- [ ] Capture group support ($1, $2, etc.)
- [ ] Preview matches before replacement
---
### Phase 4: UI Polish (Sprint 4-1 week)
**Goal**: Theme integration and UX improvements
#### Task 4.1: Integrate AgentUITheme
**Location**: `src/app/editor/message/message_editor.cc`
**Priority**: P3
**Estimated Effort**: 1 day
**Implementation**:
```cpp
void MessageEditor::DrawMessageList() {
const auto& theme = AgentUI::GetTheme();
AgentUI::PushPanelStyle();
ImGui::PushStyleColor(ImGuiCol_Header, theme.panel_bg_darker);
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, theme.accent_color);
// ... table rendering ...
ImGui::PopStyleColor(2);
AgentUI::PopPanelStyle();
}
```
**Acceptance Criteria**:
- [ ] All panels use `AgentUI::PushPanelStyle()`
- [ ] Section headers use `AgentUI::RenderSectionHeader()`
- [ ] Buttons use `AgentUI::StyledButton()` where appropriate
- [ ] Color scheme matches rest of editor
---
#### Task 4.2: Add Keyboard Shortcuts
**Location**: `src/app/editor/message/message_editor.cc`
**Priority**: P3
**Estimated Effort**: 1 day
**Shortcuts**:
- `Ctrl+F`: Open Find/Replace
- `Ctrl+E`: Export to JSON
- `Ctrl+I`: Import from JSON
- `Ctrl+S`: Save ROM
- `Ctrl+N`: Next message (in translation mode)
- `Ctrl+P`: Previous message (in translation mode)
**Implementation**:
```cpp
void MessageEditor::HandleKeyboardShortcuts() {
if (ImGui::IsKeyPressed(ImGuiKey_F) &&
ImGui::GetIO().KeyCtrl) {
show_find_replace_ = true;
}
// ... other shortcuts ...
}
```
**Acceptance Criteria**:
- [ ] Shortcuts don't conflict with global shortcuts
- [ ] Shortcuts displayed in tooltips
- [ ] Configurable shortcuts (future enhancement)
---
## Test Strategy
### Unit Tests
**Location**: `test/unit/message_data_test.cc` (new file)
```cpp
TEST(MessageDataTest, SerializeToJson_BasicMessage) {
MessageData msg;
msg.ID = 0;
msg.Address = 0xE0000;
msg.RawString = "Hello World";
msg.context = "Test message";
auto json = msg.SerializeToJson();
EXPECT_EQ(json["id"], 0);
EXPECT_EQ(json["text"], "Hello World");
EXPECT_EQ(json["context"], "Test message");
}
TEST(MessageDataTest, DeserializeFromJson_RoundTrip) {
MessageData original;
original.ID = 5;
original.RawString = "[W:00][K]Test";
auto json = original.SerializeToJson();
auto result = MessageData::DeserializeFromJson(json);
ASSERT_TRUE(result.ok());
EXPECT_EQ(result.value().ID, 5);
EXPECT_EQ(result.value().RawString, "[W:00][K]Test");
}
```
### Integration Tests
**Location**: `test/integration/message_export_test.cc` (new file)
```cpp
TEST_F(MessageRomTest, ExportImport_RoundTrip) {
// Export all messages to JSON
std::string json_path = "/tmp/messages.json";
EXPECT_OK(ExportMessagesToJson(list_of_texts_, dictionary_, json_path));
// Import back
auto imported = ImportMessagesFromJson(json_path);
ASSERT_TRUE(imported.ok());
// Verify identical
EXPECT_EQ(imported.value().size(), list_of_texts_.size());
for (size_t i = 0; i < list_of_texts_.size(); ++i) {
EXPECT_EQ(imported.value()[i].RawString, list_of_texts_[i].RawString);
}
}
```
### E2E Tests
**Location**: `test/e2e/message_editor_workflow_test.cc` (new file)
```cpp
TEST_F(MessageEditorE2ETest, TranslationWorkflow) {
// Open translation workspace
EXPECT_OK(ClickButton("Translation Mode"));
// Load reference ROM
EXPECT_OK(OpenFileDialog("reference_rom.sfc"));
// Navigate to message 0
EXPECT_EQ(GetCurrentMessageID(), 0);
// Edit translation
EXPECT_OK(SetTextBoxValue("Bienvenido a Hyrule"));
// Mark complete
EXPECT_OK(ClickButton("Mark Complete"));
// Verify progress
EXPECT_EQ(GetTranslationProgress(), "1/396");
}
```
---
## Dependencies & Risks
### External Dependencies
1. **nlohmann/json**: Already integrated via CPM ✅
2. **ImGui Test Engine**: Available for E2E tests ✅
3. **File Dialog**: `util::FileDialogWrapper` already exists ✅
### Technical Risks
#### Risk 1: JSON Schema Evolution
**Impact**: Breaking changes to JSON format
**Mitigation**:
- Include version number in schema
- Implement forward/backward compatibility
- Provide migration tool for old exports
#### Risk 2: Dictionary Auto-Optimization Complexity
**Impact**: Algorithm may be too slow for real-time use
**Mitigation**:
- Run optimization in background thread
- Provide progress indicator
- Allow cancellation
#### Risk 3: Large ROM Size with Expanded Messages
**Impact**: May exceed bank boundaries
**Mitigation**:
- Implement repointing logic early (Phase 5)
- Warn user when approaching limits
- Suggest dictionary optimization
---
## Success Metrics
### Quantitative Metrics
- [ ] 100% message export/import success rate (no data loss)
- [ ] JSON schema supports all 396 vanilla messages
- [ ] Translation workspace reduces edit time by 50% vs. current workflow
- [ ] Search/Replace handles batch operations in <1 second
- [ ] 90%+ test coverage for new code
### Qualitative Metrics
- [ ] Translator feedback: "Translation workflow is intuitive"
- [ ] No hardcoded colors in Message Editor
- [ ] UI matches yaze style guide
- [ ] Documentation complete for all new features
---
## Timeline Estimate
| Phase | Duration | Effort (Dev Days) |
|-------|----------|-------------------|
| Phase 1: JSON Export/Import | 2 weeks | 6 days |
| Phase 2: Translation Workspace | 3 weeks | 9 days |
| Phase 3: Search & Replace | 1 week | 4 days |
| Phase 4: UI Polish | 1 week | 2 days |
| **Total** | **7 weeks** | **21 dev days** |
**Note**: Timeline assumes single developer working full-time. Adjust for part-time work or team collaboration.
---
## Future Enhancements (Post-MVP)
1. **Scripting API** (Gemini's vision)
- Expose MessageData to Lua/Python
- Allow procedural text generation
- Useful for randomizers
2. **Cloud Translation Integration**
- Google Translate API for quick drafts
- DeepL API for quality translations
- Requires API key management
3. **Collaborative Editing**
- Real-time multi-user translation
- Conflict resolution for concurrent edits
- Requires network infrastructure
4. **ROM Patch Generation**
- Export as `.ips` or `.bps` patch files
- Useful for distribution without ROM sharing
- Requires patch generation library
5. **Message Validation**
- Check for overlong messages (exceeds textbox width)
- Verify all messages have terminators
- Flag unused dictionary entries
---
## Open Questions
1. **Q**: Should we support multiple translation languages simultaneously?
**A**: TBD - May require multi-ROM workspace UI
2. **Q**: How should we handle custom dictionary entries for expanded ROMs?
**A**: TBD - Need research into ROM space allocation
3. **Q**: Should translation progress be persisted?
**A**: TBD - Could store in `.yaze` project file
4. **Q**: Do we need undo/redo for message editing?
**A**: TBD - ImGui InputTextMultiline has built-in undo, may be sufficient
---
## Conclusion
The Message Editor has a **solid foundation** with core parsing, preview, and UI systems in place. The main gaps are **JSON export/import** (P0), **translation workspace** (P1), and **search/replace** (P2).
**Recommended Next Steps**:
1. Start with Phase 1 (JSON export/import) - this unblocks all translation workflows
2. Get user feedback on translation workspace mockups before Phase 2
3. Defer theme integration to Phase 4 - not blocking functionality
**Estimated Effort**: ~7 weeks to MVP, ~21 dev days total.
**Success Criteria**: Translator can export messages to JSON, edit in external tool, and re-import without data loss. Side-by-side translation workspace reduces manual comparison time by 50%.