Source Authorship Forensics
A full-source investigation of github.com/spunc595/luna-chess-engine.
The code text was produced with an AI assistant — Google Gemini, per un-scrubbed citation markers — and published largely as-is. The architecture and chess logic were designed and directed by a chess-literate developer (every algorithm chosen is correct and standard); the visible debris entered during a late, unchecked AI cleanup-and-translation pass rather than careful hand-authorship. The developer has since publicly confirmed this account — see the update below.
Confidence: Very High — multiple independent, mutually corroborating proofs.
After the report circulated, the repository's author (“Spunc595”) responded publicly, accepted the verdict, and explained how it happened. Luna, he says, is a hobby passion project whose architecture and chess logic he designed himself. New to Rust, he used an AI assistant (Gemini) as a coding co-pilot — and, just before release, asked it to refactor his files and translate all his comments into fluent English. Working quickly through the GitHub web UI, he blindly copy-pasted those AI-“cleaned” outputs.
That final pass is where the debris came from: the [cite] markers, the conflicting version numbers, the orphaned uci.rs (an AI-refactored file he uploaded but never wired into main.rs), and the wrong “HalfKA” label (an AI boilerplate placeholder he failed to catch). Calling it “a massive, embarrassing lesson in repository hygiene,” he said he will wipe the repository, remove the dead code, and fix the warnings so it reflects the clean engine he intended.
Net: the forensic verdict holds, and the developer's candid account fills in the human side the artifacts alone couldn't show — he directed the design; an unchecked, last-minute AI cleanup produced the mess.
Nine signals, ranging from a literal copy-paste artifact to structural incoherence.
| # | Signal | What it proves | Weight |
|---|---|---|---|
| 1 | 147 leftover [cite: N] markers in comments | Text pasted verbatim from a Gemini response, uncleaned | Smoking gun |
| 2 | Every commit is a GitHub-web "Add files via upload" | No local development; files authored elsewhere | Strong |
| 3 | Orphaned duplicate uci.rs (never compiled) | Files generated in isolation, never integrated | Strong |
| 4 | Four conflicting version numbers | Assembled from separate generations, unreconciled | Strong |
| 5 | "HalfKA" label on a network that isn't HalfKA | Leftover AI placeholder that doesn't match the actual network | Strong |
| 6 | Duplicated PST + Zobrist code | Copy-paste from separate prompts | Medium |
| 7 | Tutorial-grade comment on every trivial line | Characteristic AI narration style | Medium |
| 8 | Italian identifiers + fluent English comments | Generation/translation layer, not one human hand | Support |
| 9 | Leftover Italian "todo" notes in cargo.toml | Assistant's paste-instructions left in verbatim | Support |
The source contains 147 stray [cite: N] tags appended to code comments — an artifact of Gemini's grounded output. No human types [cite: 10] at the end of a Rust comment.
/// Periodically checks (every 2048 nodes) if time has run out.[cite: 10]
Each file carries its own citation number, indicating each was produced in a separate AI turn.
| File | Marker count | Citation # |
|---|---|---|
src/tt.rs | 35 | [cite: 6] |
src/search.rs | 32 | [cite: 10] |
src/zobrist.rs | 27 | [cite: 12] |
src/nnue.rs | 26 | [cite: 5] |
src/evaluation.rs | 17 | [cite: 4] |
src/uci.rs | 10 | [cite: 5] |
| Total | 147 |
src/book.rs has zero markers and a different comment voice (emoji, terser style) — likely a different session or the one lightly hand-edited file.All 30 commits were made through the GitHub web UI. Not one is a local commit from real coding — no incremental building, no bug-fix commits, no branches.
| Commit message pattern | Count | Meaning |
|---|---|---|
| "Add files via upload" | 4 | Bulk paste of generated files |
| "Delete X.rs" | ~15 | Wholesale file replacement |
| "Create / Update README.md" | ~7 | Web-UI text edits |
| "Update main.rs" | 1 | Single web-UI edit |
src/uci.rs is a complete second UCI implementation that is never used: main.rs implements the loop inline and never declares mod uci;, so the file is excluded from compilation entirely. The two disagree on nearly every parameter.
| Parameter | main.rs (live) | uci.rs (dead) |
|---|---|---|
| Engine name | Luna_Hybrid_7.2 | Luna 0.6 …HalfKA |
| Author string | [redacted] | [redacted] |
| Default hash | 256 MB | 64 MB |
| Time mgmt | time / 25 | time / 30 |
| Default depth | 12 | 64 |
| Search model | synchronous | threaded |
| Location | Version |
|---|---|
README.md | v1.0.0 |
src/main.rs | 7.2 |
src/uci.rs | 0.6 |
cargo.toml | 0.6.0 |
uci.rs advertises "NNUE HalfKA," but nnue.rs is a plain 768-input network (12 pieces × 64 squares) with no king-relative features. Real HalfKA is king-bucketed with ~45,000 features — the label is a leftover AI placeholder that was never corrected.
| Duplicated item | Copy A | Copy B |
|---|---|---|
| Piece-Square Tables | evaluation.rs | movegen.rs (verbatim) |
| Zobrist hash routine | board.rs::get_hash | zobrist.rs::hash_board |
It compiles cleanly — and the compiler independently confirms the dead-code findings.
Toolchain : rustc 1.97.0 (x86_64-pc-windows-msvc) Command : cargo build --release Result : SUCCESS — 0 errors, 8 warnings, 19.75s Binary : target/release/luna.exe (257,024 bytes)
| # | Compiler warning | Location | Confirms |
|---|---|---|---|
| 1 | method hash_board never used | zobrist.rs:62 | Duplicate Zobrist |
| 2 | methods clear / new_search never used | tt.rs:53,63 | Dead TT "aging" |
| 3 | methods conta_pezzi / genera_mosse unused | board.rs:284,537 | Dead code |
| 4 | field pst_val never read | board.rs:211 | Dead field |
| 5 | variant Bound::None never constructed | tt.rs:6 | Dead code |
| 6 | fn OpeningBook::new never used | book.rs:15 | Dead code |
| 7 | value assigned to val never read | evaluation.rs:108 | Sloppiness |
| 8 | variable beta need not be mutable | search.rs:156 | Sloppiness |
tt.rs::new_search() — which bumps the generation counter for entry aging — is never called by the live binary. So the "Transposition Table with aging support" the README advertises does nothing; the generation stays at 1 forever.Fed a standard UCI handshake, the binary searches and returns a legal, sensible move. Despite the messy authorship, the engine genuinely works.
| Metric | Result |
|---|---|
| UCI handshake | OK — readyok returned |
| Search depth reached | 9 plies in ~1 second |
| Node rate | ~2.5 million nodes/sec |
| Best move | b1c3 (Nc3) — legal, sensible |
| PV legality | All principal-variation lines legal |
| Overall | Functional — plays real chess |
Startup banner (mixed Italian/English — another tell):
"NNUE: Attiva e carica!" · "Luna Engine v7.2 - Istruita Ready"
Human-conceived and human-directed; AI-authored source. A chess-literate developer designed the engine, used an AI (Gemini) to help implement it and then to "clean up" and translate it before release, and uploaded the output largely as-is. The algorithm choices are all correct and the binary compiles cleanly and plays legal chess — and the un-scrubbed citation tags, four conflicting version numbers, an orphaned source file, a dead advertised feature, and a leftover placeholder label all trace to that final, unchecked cleanup pass. The developer has since publicly confirmed this account and committed to cleaning up the repository.