{"slug": "position-evaluator-a-chess-diagnostic-for-your-daily-decisions", "title": "Position Evaluator — A Chess Diagnostic for Your Daily Decisions", "summary": "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.", "body_md": "*This is a submission for Weekend Challenge: Passion Edition*\n\nI'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.\n\nSo 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.\n\nIt'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.\n\nDaily 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.\n\n```\npython -m venv venv\nsource venv/bin/activate  # Windows: venv\\Scripts\\activate\npip install -r requirements.txt\n\ncp .env.example .env\n# edit .env: add your GEMINI_API_KEY and MySQL credentials\n\nmysql -u root -p < schema.sql\n\npython app.py\n# open http://127.0.0.1:5000\n# fast, no API calls, safe to run anytime — this is what CI runs on every push\npytest tests/ -k \"not eval_set\"\n\n# slower, calls the real Gemini API, costs quota — run after editing the\n# system prompt in gemini_client.py to check for prompt drift\npytest tests/ -k \"eval_set\"\n```\n\n`.github/workflows/test.yml`\n\nruns the deterministic tests on every push/PR to `main`\n\n. The Gemini eval-set tests are deliberately excluded from CI. They call…\n\nStack: Python (Flask), MySQL, Gemini API (gemini-3.1-flash-lite) via the google-genai SDK, vanilla JS/CSS frontend.\n\nSeven 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.\n\nThe 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.\n\nI 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.\n\nThat 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.\n\nEverything 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.\n\nSubmitting 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).", "url": "https://wpnews.pro/news/position-evaluator-a-chess-diagnostic-for-your-daily-decisions", "canonical_source": "https://dev.to/semtione/position-evaluator-a-chess-diagnostic-for-your-daily-decisions-3omj", "published_at": "2026-07-13 01:44:28+00:00", "updated_at": "2026-07-13 02:14:36.784729+00:00", "lang": "en", "topics": ["artificial-intelligence", "large-language-models", "ai-tools", "developer-tools"], "entities": ["Gemini", "Flask", "MySQL", "Pydantic"], "alternates": {"html": "https://wpnews.pro/news/position-evaluator-a-chess-diagnostic-for-your-daily-decisions", "markdown": "https://wpnews.pro/news/position-evaluator-a-chess-diagnostic-for-your-daily-decisions.md", "text": "https://wpnews.pro/news/position-evaluator-a-chess-diagnostic-for-your-daily-decisions.txt", "jsonld": "https://wpnews.pro/news/position-evaluator-a-chess-diagnostic-for-your-daily-decisions.jsonld"}}