Position Evaluator — A Chess Diagnostic for Your Daily Decisions A developer built Position Evaluator, a daily diagnostic log that classifies personal decisions into formal chess concepts such as Zugzwang, Fork, and Zwischenzug using Gemini's structured output. The tool uses a strict decision order and a Pydantic schema that forces reasoning before classification, and it avoids false precision by using categorical confidence levels instead of numeric scores. This is a submission for Weekend Challenge: Passion Edition I've been obsessed with chess for years, and I kept noticing that a handful of chess concepts describe everyday life decisions better than any generic advice ever could. "Zugzwang": being forced to move when every option makes things worse. "Fork": one situation threatening two things you care about at once. "Zwischenzug": sneaking in a small unrelated move before dealing with the real problem. So I built Position Evaluator , a daily diagnostic log that takes a short description of a decision or situation you're facing, and classifies it into one of seven formal chess concepts using Gemini, such as Zugzwang, Fork, Prophylaxis, Gambit, Zwischenzug, Overextension, or Tempo Loss. You get a classification, a confidence level, and a short clinical explanation of why. Then, over time, a dashboard shows which "condition" you land in most often. It's a structured classification system with a strict decision order. The interface leans into the bit too, it's styled like a hospital lab-requisition form crossed with a chess scoresheet, complete with a stamped classification badge, a case-file number, and a "clear all records" control for starting a fresh log. Daily diagnostic log that classifies your personal decisions into formal chess concepts Zugzwang, Fork, Zwischenzug, Prophylaxis, Gambit, Overextension, Tempo Loss using Gemini structured output. Built for the DEV Weekend Challenge: Passion Edition. python -m venv venv source venv/bin/activate Windows: venv\Scripts\activate pip install -r requirements.txt cp .env.example .env edit .env: add your GEMINI API KEY and MySQL credentials mysql -u root -p < schema.sql python app.py open http://127.0.0.1:5000 fast, no API calls, safe to run anytime — this is what CI runs on every push pytest tests/ -k "not eval set" slower, calls the real Gemini API, costs quota — run after editing the system prompt in gemini client.py to check for prompt drift pytest tests/ -k "eval set" .github/workflows/test.yml runs the deterministic tests on every push/PR to main . The Gemini eval-set tests are deliberately excluded from CI. They call… Stack: Python Flask , MySQL, Gemini API gemini-3.1-flash-lite via the google-genai SDK, vanilla JS/CSS frontend. Seven overlapping chess concepts can describe the same situation in slightly different ways "procrastinating on a task to watch anime" could plausibly read as either Zwischenzug or Tempo Loss . I solved this by giving Gemini an explicit decision order in the system prompt; check for Fork first, then Zugzwang, then Prophylaxis, and so on down to Tempo Loss as the default; rather than asking it to "pick whichever fits best" from a flat list. That single change made classifications far more consistent across similar inputs. The other detail I'm most proud of is that the Pydantic schema for Gemini's structured output declares reasoning before classification. Since Gemini's controlled JSON generation fills fields in the order they're declared, this forces the model to articulate its reasoning before it's allowed to commit to a label. I also intentionally didn't build a numeric confidence score. LLMs aren't well-calibrated at self-reporting a percentage like "87% confident," so instead of a falsely precise number, the model picks a categorical low / medium / high bucket based on whether the situation contains an explicit signal for its chosen category, or is more of an inference. That same principle got tested again late in the build, when I wanted a chess-engine-style evaluation score next to each badge for extra flavor, something like FORK -2.5 . The tempting shortcut was to just ask Gemini to invent that number too. I didn't, for the same reason as above, it would've quietly reintroduced the exact false precision I'd deliberately avoided with the confidence bucket. Instead, the score is computed deterministically in plain code, from a fixed lookup table keyed on the classification and confidence Gemini already returned. Everything else, like the entry log, the duplicate-submit handling same-day identical entries return the existing diagnosis instead of creating a new row , and the distribution dashboard, is built around one goal: making the "diagnostic report" feel real. Submitting for Best Use of Google AI. The entire product only works because of Gemini's structured output support response schema bound to a Pydantic model .