Files
Erupe/docs/technical-debt.md
Houmgaor f640cfee27 fix: log SJIS decoding errors instead of silently discarding them
Add SJISToUTF8Lossy() that wraps SJISToUTF8() and logs decode errors at
slog.Debug level. Replace all 31 call sites across 17 files that previously
discarded the error with `_, _ =`. This makes garbled text from malformed
SJIS client data debuggable without adding noise at default log levels.
2026-02-22 17:01:22 +01:00

7.2 KiB

Erupe Technical Debt & Suggested Next Steps

Analysis date: 2026-02-22

This document tracks actionable technical debt items discovered during a codebase audit. It complements anti-patterns.md (which covers structural patterns) by focusing on specific, fixable items with file paths and line numbers.

Table of Contents


High Priority

1. Broken game features (gameplay-impacting TODOs)

These TODOs represent features that are visibly broken for players.

Location Issue Impact
model_character.go:88,101,113 TODO: fix bookshelf data pointer for G10-ZZ, F4-F5, and S6 versions Wrong pointer corrupts character save reads for three game versions
handlers_guild.go:389 TODO: Implement month-by-month tracker — always returns 0x01 (claimed) Players can never claim monthly guild items Fixed. Now tracks per-character per-type monthly claims via stamps table.
handlers_guild_ops.go:148 TODO: Move this value onto rp_yesterday and reset to 0... daily? Guild daily RP rollover logic is missing entirely
handlers_achievement.go:125 TODO: Notify on rank increase — always returns false Achievement rank-up notifications are silently suppressed
handlers_guild_info.go:443 TODO: Enable GuildAlliance applications — hardcoded true Guild alliance applications are always open regardless of setting
handlers_session.go:397 TODO(Andoryuuta): log key index off-by-one Known off-by-one in log key indexing is unresolved
handlers_session.go:577 TODO: This case might be <=G2 Uncertain version detection in switch case
handlers_session.go:777 TODO: Retail returned the number of clients in quests Player count reported to clients does not match retail behavior

2. Test gaps on critical paths

Handler files with no test file:

File Lines Priority Reason
handlers_session.go 833 HIGH Login/logout, log key, character enumeration
handlers_gacha.go 411 HIGH Economy system with DB writes
handlers_commands.go 421 HIGH Admin command system
handlers_data_paper.go 621 MEDIUM Daily paper data
handlers_plate.go 294 MEDIUM Armor plate system
handlers_shop.go 291 MEDIUM Shopping system
handlers_seibattle.go 259 MEDIUM Sei battle system
handlers_scenario.go ~100 LOW Mostly complete, uses repo
handlers_distitem.go small LOW Distribution items
handlers_guild_mission.go small LOW Guild missions
handlers_kouryou.go small LOW Kouryou system

Repository files with no store-level test file (17 total):

repo_achievement.go, repo_cafe.go, repo_distribution.go, repo_diva.go, repo_festa.go, repo_gacha.go, repo_goocoo.go, repo_house.go, repo_mail.go, repo_mercenary.go, repo_misc.go, repo_rengoku.go, repo_scenario.go, repo_session.go, repo_shop.go, repo_stamp.go, repo_tower.go

These are validated indirectly through mock-based handler tests but have no SQL-level integration tests.

3. Sign server has no repository layer

The channelserver was refactored to use repository interfaces (commits a9cca84, 6fbd294, 1d5026c), but server/signserver/ was not included. It still does raw db.QueryRow/db.Exec with 8 silently discarded errors on write paths:

server/signserver/dbutils.go:86,91,94,100,107,123,149
server/signserver/session.go
server/signserver/dsgn_resp.go

Examples of discarded errors (login timestamps, return-to-player expiry, rights queries):

_, _ = s.db.Exec("UPDATE users SET return_expires=$1 WHERE id=$2", returnExpiry, uid)
_ = s.db.QueryRow("SELECT last_character FROM users WHERE id=$1", uid).Scan(&lastPlayed)

A database connectivity issue during login would be invisible.


Medium Priority

4. Split repo_guild.go

At 1004 lines with 71 functions, repo_guild.go mixes 6 distinct concerns:

  • Guild CRUD and metadata
  • Member management
  • Applications/recruitment
  • RP tracking
  • Item box operations
  • Message board posts

Suggested split: repo_guild.go (core CRUD), repo_guild_members.go, repo_guild_items.go, repo_guild_board.go.

5. Logging anti-patterns

a) fmt.Sprintf inside structured logger calls (6 sites): Fixed. All 6 sites now use zap.Uint32/zap.Uint8/zap.String structured fields instead of fmt.Sprintf.

b) 20+ silently discarded SJIS encoding errors in packet parsing: Fixed. All call sites now use SJISToUTF8Lossy() which logs decode errors at slog.Debug level.

6. Inconsistent transaction API (Fixed)

Status: Fixed. All transaction call sites now use BeginTxx(context.Background(), nil) with deferred rollback, replacing the old Begin() + manual rollback pattern across repo_guild.go, repo_guild_rp.go, repo_festa.go, and repo_event.go.

7. LoopDelay config has no Viper default (Fixed)

Status: Fixed. viper.SetDefault("LoopDelay", 50) added in config/config.go, matching the config.example.json value.


Low Priority

8. Typos and stale comments

Location Issue
sys_session.go:73 Comment says "For Debuging" — typo, and the field is used in production logging, not just debugging
handlers_session.go:397 "offical" should be "official"
handlers_session.go:324 if s.server.db != nil guard wraps repo calls that are already nil-safe — refactoring artifact

9. CI updates

  • codecov-action@v3 could be updated to v4 (current stable)
  • No coverage threshold is enforced — coverage is uploaded but regressions aren't caught

Suggested Execution Order

Based on impact and the momentum from recent repo-interface refactoring:

  1. Add tests for handlers_session.go and handlers_gacha.go — highest-risk untested code on the critical login and economy paths
  2. Refactor signserver to use repository interfaces — completes the pattern established in channelserver and surfaces 8 hidden error paths
  3. Fix monthly guild item claim (handlers_guild.go:389) — Done
  4. Split repo_guild.go — last oversized file after the recent refactoring push
  5. Fix fmt.Sprintf in logger callsDone
  6. Add LoopDelay Viper defaultDone
  7. Log SJIS decoding errorsDone
  8. Standardize on BeginTxxDone