Skip to content

Regalia v1.0.7

Choose a tag to compare

@YDW99 YDW99 released this 29 Jun 23:48
· 47 commits to main since this release
2a3fdbc

What's Changed

Full Changelog: v1.0.6...v1.0.7


The source code files include an outdated README.md file along with the manuals. For detailed information about the relevant revisions (which encompass the manuals), please refer to the following:

b4ef1e7


Regalia v1.0.7 — Stability & Performance Maintenance Release

versionCode 107 · versionName "1.0.7" · 2026.6.28 – 2026.6.30
Stockfish 18 (arm64-v8a-dotprod) · Android 5.0+ (API 21) · arm64-v8a only

v1.0.7 is a code-quality and stability maintenance release based on three independent code-review reports + two comprehensive first-principles code-review passes (Phase 18/19) + two rounds of UX refinement (Phase 20/21). Across 21 phases, 52+ improvements were implemented. No new features were introduced, but numerous latent bugs were fixed, and the two remaining architectural suggestions from the Kimi audit report (LRU cache eviction + virtual list) were implemented.


📊 Release Overview

Metric Value
Total Phases 21
Fixes / Optimizations 52+
Code-Review Subagents 7 (Phase 19)
Lines Reviewed 28,281
Critical Bug Fixes 8
Performance Breakthroughs 3
Compatibility Xiaomi HyperOS 3 ✅

🎯 Key Highlights

⚡ Performance Breakthroughs

1. _reviewEvalCache LRU Eviction (Phase 18)

The old code commented "Unlimited cache size", arguing 60k entries ≈ 12MB was "negligible". First-principles analysis found three errors:

Old Claim                          Actual Reality
─────────────────────────────  ─────────────────────────────
~200B per entry                ~400B (JSON persistence overhead)
60k entries ≈ 12MB             ≈ 24MB JSON
"negligible" main-thread block JSON.stringify blocks 100-300ms
localStorage quota ample       WebView ~5MB → QuotaExceededError silently swallowed

Fix:

  • MAX_ENTRIES = 2000 soft cap (~800KB JSON, well under any quota)
  • _evictIfOverCap() evicts oldest entries by Map insertion order (= LRU order)
  • get()/set() refresh LRU order via delete+set
  • Does NOT evict _reviewEvalRequestedStep (the in-flight step) to avoid "analyzing..." flicker
  • Persistence preserves LRU order via Array.from(m.entries())
  • Backward-compatible: persisted files >2000 entries auto-evict on next set()

2. Review Move-List Virtual List (Phase 18)

Threshold: 80 moves    Overscan: 10 rows    Debounce: 80ms

When move count > 80, windowed rendering is enabled — only the viewport + 10 rows of overscan above/below are rendered as DOM nodes; top/bottom spacer <div>s fill the total scroll height.

Feature Implementation
Shared render function _buildReviewMovesInnerHTML(start, end) eliminates ~40 lines of landscape/portrait duplication
Scroll listener Passive (passive:true), cannot block scrolling or interfere with scroll-restore
Partial refresh _refreshReviewMovesOnly() replaces only .review-moves innerHTML
Dynamic row height First render measures average height of first 10 rows via requestAnimationFrame
Window forcing _forceReviewWindowToStep() ensures reviewGoTo() target is in window
State reset _resetRvVirtualState() on enter/exit review, new game, import

Performance: Not enabled under 80 moves (full render is faster for short lists); long-game render cost reduced from O(total moves) to O(visible + overscan).

3. Move Animation Slowed 30% (Phase 20, 120fps Preserved)

Piece     Old Duration    New Duration
─────────────────────────────────────────
Pawn      180ms           240ms
Knight    240ms           320ms
Bishop    210ms           280ms
Rook      180ms           240ms
Queen     260ms           340ms
King      210ms           280ms
  • 120fps high-frame-rate preserved — GPU-composited via will-change:transform + translate3d
  • cubic-bezier(.25,.1,.25,1) easing curve unchanged; only duration is longer
  • CSS transition durations updated to match JS durations table

🐛 Critical Bug Fixes

Chess960 Castling "King Self-Capture" Fatal Bug (Phase 17)

Symptom: In Chess960 mode, when the king's starting position happens to be its castling destination square (e.g. an SP-ID where the white king starts on g1), castling caused the king to "capture itself" and vanish from the board.

Root cause: The makeMv/makeMvInPlace castling branch unconditionally executed:

ns.board[to.row][to.col] = ns.board[from.row][from.col];  // self-copy
ns.board[from.row][from.col] = null;                       // ← BUG: when from===to, this nulled the king's own square

Fix: When castling AND from === to, skip the king move entirely (per the Fischer Random Chess "castling in place" rule). Also fixed unmakeMv and animateMove symmetrically. Added 20 Node-sandbox regression tests.

Chess960 unmakeMv Board Corruption (Phase 18, Critical)

Symptom: In ~half of all Chess960 SP-ID positions (e.g. white king on f1 castling kingside), the makeMvInPlaceunmakeMv round-trip corrupted the board.

Root cause: unmakeMv step 2 restores the king at f (king source), but the rook's destination cr.to may equal f (the rook moved to the king's old square) — step 2 already overwrote the rook with the king; step 4 s.board[cr.from] = s.board[cr.to] then read the king instead of the rook.

Fix: Save the rook piece itself in undo.castlingRook.piece, restoring from the saved piece rather than relying on board state.

_reviewEvalCache Corruption Race (Phase 19, Critical)

Symptom: requestEngineEval's cache-hit fast path and terminal-position fast path did not clear the pending debounce timer, allowing a stale debounce timer capturing a prior step's FEN to fire after the cache-hit return and overwrite the current step's correct cached eval.

Fix: Clear _reviewEvalDebounceTimer and increment _evalStaleGen on both fast paths to invalidate any in-flight callback.

Cross-Mode Stale Callback Race (Phase 19, Critical)

Symptom: onEngineEval's two filters are mode-exclusive; after exitReview, a review-mode callback still in flight could pass the normal-mode gen check and overwrite the correct eval for up to 30 seconds.

Fix: Capture _evalRequestReviewMode at request time; onEngineEval rejects cross-mode callbacks at the top.

PGN [%eval] Placeholder Offset (Phase 19, Critical)

Symptom: FEN-start PGNs where Black is to move had evals attach to the wrong reviewStep (off by 1).

Root cause: _parsePGN was unaware of the null placeholder that importPGN prepends after parsing.

Fix: Apply _placeholderOffset when populating the eval/annotation/comment caches.

StockfishNative Thread Safety (Phase 19)

Five fields changed from non-volatile to volatile:

private volatile Process engineProcess;
private volatile BufferedReader engineReader;
private volatile OutputStreamWriter engineWriter;
private volatile Thread readerThread;
private volatile ExecutorService _engineExecutor;

Root cause: These fields are written from multiple threads (_engineExecutor worker, heartbeat thread, JS binder) without volatile/synchronization. A read on one thread may never observe a null write from another, producing NPEs or writes to a destroyed process's stream.

stopAndWaitForBestmove Timeout Stale-Bestmove Corruption (Phase 19)

Symptom: When the engine didn't respond to "stop" within 1 second, the late bestmove was processed as a real move, potentially generating an AI move for the wrong position.

Fix: On timeout, set _discardingPonderBestmove = true to discard the late bestmove.

ChessApp UncaughtExceptionHandler Swallowed Error (Phase 19)

Symptom: Worker-thread Errors (OOM/StackOverflow/NoClassDefFoundError) were silently swallowed, leaving the JVM in a corrupted state — e.g. if the SF-Reader thread died from OOM, the engine silently stopped responding while isProcessAlive() still returned true, causing a 30-120s apparent hang.

Fix: Error subclasses are now chained to the default handler so the process dies cleanly and restarts.


🎨 UX Refinements (Phase 20 + 21)

Review Eval Bar / Analyze Button Enlarged (Phase 20)

Element Old New
Eval bar font (portrait/landscape) .75rem / .7rem .85rem / .8rem
Emoji size .95rem 1.1rem / 1.05rem
max-height 1.9em 2.4em
padding 3px 8px 5px 10px
Analyze button font .7rem .8rem
Analyze button min-height 28px 34px

Text and emoji now display fully with comfortable breathing room — no longer cramped.

Portrait Dialog Positioning Precision Fix (Phase 21)

Phase 20 attemptPhase 21 precision fix:

Phase 20: padding-top:18vh + padding-bottom:10px
          → center = 18 + (100-18-1)/2 ≈ 59vh  ❌ BELOW center

Phase 21: padding-top:10px + padding-bottom:12vh
          → center = 10px + (100vh-10px-12vh)/2 ≈ 44vh  ✅ slightly above center

The fullscreen dialog (New Game Settings) uses negative margins to cancel both paddings, maintaining true full-screen fill.

Landscape Anti-Shake Clipping Root-Cause Fix (Phase 21)

Phase 20 attempt (.bsec margin-right:10px) was ineffective — the clip happens at .bsec's own overflow:hidden boundary, not at the gap.

Phase 21 triple fix:

  1. Rolled back margin-right:10px
  2. .bsec changed to overflow-x:visible; overflow-y:hidden
  3. _antiShake now reserves 8px in BOTH orientations (isLandscape?0:68, matching MAX_DISPLACEMENT_PX=8.0f)

Landscape Move-History Panel Clipping Fix (Phase 21)

.panel now has overflow-x:auto, so wide content scrolls within the panel instead of being clipped by .main's overflow-x:hidden.


📋 All 21 Phases at a Glance

Phase Date Theme Key Content
Phase 1 6.28 Code-review bug fixes Critical-move cache, lightweight update, notification throttle, XSS, CSP, cross-game cache
Phase 2 6.28 Quick Toolbar + setup markers Main-screen Quick Toolbar, 🔁/⚡ manual marker buttons
Phase 3 6.28 Portrait UI redesign @media(orientation:portrait) no width threshold + vw/clamp()
Phase 4 6.29 Chess960/X-FEN rule correctness findCastlingRooks, Shredder-FEN, UCI_Chess960
Phase 5 6.29 Board sizing & layout optimization _recalcCellSize first-principles rewrite
Phase 6–8 6.29 Board sizing & layout optimization Landscape right-edge, dialogs, setup markers
Phase 9–11 6.29 ⚠️ Misreport (cleaned up in Phase 13) ⚡ marker position anomaly never existed
Phase 12 6.29 ⚡ entering-setup-mode root-cause fix enPassantTarget reverse-mapping
Phase 13 6.29 Misreport cleanup + code review Removed defensive guards, root-cause fix
Phase 14 6.29 Eval bar font enlargement + chart sizing .62→.75rem, min 120px / max 200px
Phase 15 6.29 Analyze All includes step 0 _totalSteps = moveRecords.length + 1
Phase 16 6.29 Final code review PGN [%eval] off-by-one + redundancy cleanup
Phase 17 6.29 Chess960 castling + review button + Kimi 5 King self-capture fix, analyze-all auto-refresh
Phase 18 6.30 LRU eviction + virtual list + 11 fixes Two architectural suggestions implemented
Phase 19 6.30 7-subagent 28k-line comprehensive review 20+ critical fixes
Phase 20 6.30 UX refinements Eval bar enlarged, animation slowed, dialog positioning
Phase 21 6.30 Bug fixes Dialog positioning precision fix, anti-shake root-cause fix

🔍 Phase 19 Comprehensive Code Review Details

7 subagents reviewed all 20 source files (28,281 lines) in parallel:

┌─────────────────────────────────────────────────────────┐
│  Subagent 1: game-logic.js + chess960.js   (3,005 lines)│
│  Subagent 2: ai-bridge.js                   (3,824 lines)│
│  Subagent 3: ui.js lines 1-2000                          │
│  Subagent 4: ui.js lines 2000-4000                       │
│  Subagent 5: ui.js lines 4000-5975                       │
│  Subagent 6: tablebase.js + pgn-standard.js + worker-pool│
│  Subagent 7: index.html.tpl + stats.html + 9 Java + JNI │
└─────────────────────────────────────────────────────────┘
         Total 28,281 lines, line-by-line first-principles analysis

20+ critical fixes implemented by priority: bug fix > functionality > performance > redundancy cleanup > simplification.


🛡️ Security & Compliance

stats.html CSP Added (Phase 19)

The stats page renders user-pasted PGN content but previously had no Content Security Policy. A CSP matching chess.html has been added:

Content-Security-Policy: default-src 'none';
  script-src 'unsafe-inline';
  style-src 'unsafe-inline';
  img-src data:;
  connect-src 'none';
  frame-ancestors 'none';
  base-uri 'self';

File Header License Notice Completed (Phase 19 supplement)

stats.html was missing the full Copyright + GPL v3 license block (only had the AI-GEN line in the <style> comment). A complete HTML comment license block matching index.html.tpl's style has been added to <head>.


📁 Project Structure

Regalia/
├── src/main/
│   ├── assets/
│   │   ├── chess.src/              # Source files (JS + CSS + HTML template)
│   │   │   ├── game-logic.js       # Chess rules, move generation, i18n, castling detection
│   │   │   ├── chess960.js         # Chess960 SP-ID, Shredder-FEN, 960 castling rules
│   │   │   ├── pgn-standard.js     # Standardized PGN encoder/decoder, NAG, [%csl]/[%cal]
│   │   │   ├── worker-pool.js      # Web Worker pool
│   │   │   ├── ai-bridge.js        # Engine communication, eval display, PGN export
│   │   │   ├── ui.js               # Rendering, dialogs, interaction, review mode
│   │   │   ├── eco-data.js         # ECO opening classification data
│   │   │   ├── tablebase.js        # Syzygy tablebase + PGN import
│   │   │   ├── index.html.tpl      # CSS template
│   │   │   └── build-chess.sh      # Build script → chess.html
│   │   ├── chess.html              # Built output
│   │   ├── stats.html              # Statistics page
│   │   └── *.svg                   # License logos
│   ├── java/com/Regalia/           # Java source files (9 files)
│   ├── cpp/engine_jni.cpp          # JNI bridge
│   └── AndroidManifest.xml
├── Manual/                         # User manuals (Chinese & English, 4 versions)
├── NOTICE                          # Third-party component notices
├── LICENSE-AGPL v3                 # AGPL v3 full text
├── LICENSE-GPL v3                  # GPL v3 full text
├── LICENSE-Apache v2.0             # Apache v2.0 full text
├── README.md                       # Project readme
└── PRIVACY.md                      # Privacy policy

📥 Downloads

File Size Description
Regalia-v1.0.7-release.apk 74 MB Release APK, v1+v2+v3 triple signed
Regalia-v1.0.7-manual-zh.html 505 KB Chinese user manual
Regalia-v1.0.7-manual-en.html 597 KB English user manual

Installation Requirements

  • Architecture: arm64-v8a only
  • OS: Android 5.0 (API 21)+
  • Target SDK: 35 (Android 15)
  • Compatibility: Xiaomi HyperOS 3 ✅

Build Verification

✅ APK signature v1 (JAR signing): true
✅ APK signature v2 (APK Signature Scheme v2): true
✅ APK signature v3 (APK Signature Scheme v3): true
✅ chess.html JS syntax validation passed
✅ tar package contains no engine files (98 files)
✅ Phase 18 feature tests all passed (28 PASS)

📜 License

Regalia is a dual-licensed combined work:

Component License Source
Application as a whole AGPL v3 Original code
DroidFish-derived code GPL v3 game-logic.js, ai-bridge.js, ui.js, StockfishNative.java, engine_jni.cpp
Stockfish 18 GPL v3 Engine binary
Gradle Apache v2.0 Build tooling

AI-GEN Declaration: All source files are marked // AI-GEN: AI assisted, indicating the code was AI-assisted and has been reviewed for license compliance.


🙏 Acknowledgements

  • DroidFish — Peter Österlund's Android chess app; this project's engine management, PGN parsing, and SAN notation logic are derived from it
  • Stockfish — The world-class open-source chess engine
  • lichess-org/chess-openings — ECO opening classification data (CC0)
  • Kimi Audit Report — Provided 30+ suggestions; 5 were adopted in Phase 17, and 2 architectural suggestions were implemented in Phase 18

🔄 Full Changelog

The changelog is ordered newest-to-oldest. See:

  • 📖 Chinese manual: Regalia-v1.0.7-manual-zh.html Appendix A
  • 📖 English manual: Regalia-v1.0.7-manual-en.html Appendix A
  • 📋 NOTICE file: License classification and per-phase structural summary
  • 📋 README.md: Complete 52+ itemized update records

🎉 v1.0.7 release complete! Thank you for using Regalia.


AI-GEN