dota2tuned / PLAN.md
Dracufeuer's picture
docs: tag build small submission
f5bddfd verified
|
Raw
History Blame Contribute Delete
45.3 kB

A newer version of the Gradio SDK is available: 6.20.0

Upgrade

DOTA2Tuned Hackathon Plan

Summary

  • Build a full Dota 2 data platform plus a Hugging Face Gradio Space for the Build Small Hackathon, backed by Modal GPU functions for training and optional serving.
  • Optimize for both tracks: a serious draft/meta coach for Backyard AI and a playful Draft Lab mode for Thousand Token Wood.
  • Use deterministic stats and predictors for recommendations; use profiled sub-32B QLoRA adapters for grounded explanations.
  • Keep Hugging Face Space as the canonical submitted app, with Modal as the GPU execution path because Modal credits are available.
  • First implementation step: create PLAN.md, .env.example, .env, and .gitignore secret rules, then build the code scaffold.

Source Constraints

  • Hackathon: <=32B total model parameters, Gradio app hosted as a Hugging Face Space, Space link + short demo video + social post by June 15, 2026. Source: https://huggingface.co/build-small-hackathon
  • Hugging Face: host the submitted Space and model/dataset artifacts on the Hub.
  • Modal: use TRL SFT/QLoRA for GPU training, and optionally host the Gradio app with mount_gradio_app, @modal.asgi_app(), and max_containers=1 to satisfy Gradio sticky-session requirements.
  • API limits: OpenDota free metadata reports 3000/day, 60/min, premium 3000/min; STRATZ default token is 20/sec, 250/min, 2000/hour, 10000/day.

Architecture

  • Stack: Python 3.12, uv, src/ layout, ruff, pytest, pydantic, httpx, tenacity, polars, pyarrow, duckdb, scikit-learn, lightgbm, datasets, huggingface_hub, transformers, trl, peft, bitsandbytes, gradio, optional modal.
  • Storage: raw API JSONL in data/raw, normalized Parquet in data/parquet, DuckDB at data/dota2tuned.duckdb, generated RAG docs in data/rag.
  • Tables: dim_patch, dim_hero, dim_item, dim_ability, dim_league, fact_match, fact_player_match, fact_draft_pickban, fact_item_purchase, fact_hero_pair_stats, fact_hero_build_stats, fact_hero_skill_builds, doc_patch_change, doc_stratz_match, doc_stat_card, ingest_run, api_call_log.
  • Data clients: Steam discovery/raw facts, OpenDota normalized stats, STRATZ rich enrichment, Valve patch JSON feed, dotaconstants constants.
  • Modal backend: deployed ui, remote_smoke, train_sft, and generate_answer functions. The HF Space remains available; Modal provides GPU training, adapter inference, and a verified alternate Gradio endpoint.

Interfaces

  • CLI: dota2tuned ingest, normalize, features, train-predictor, build-rag, make-sft, finetune, eval, serve, modal-deploy, modal-smoke, modal-train, modal-ask.
  • .env keys: HF_TOKEN, HF_ORG, HF_SPACE_ID, MODEL_PROFILE, MODEL_PROFILES_PATH, HF_MODEL_REPO_ID, HF_DATASET_REPO_ID, STRATZ_TOKEN, OPENDOTA_API_KEY, STEAM_API_KEY, BASE_MODEL_ID, TRAINING_FLAVOR, SPACE_HARDWARE, SFT_MAX_LENGTH, LORA_R, LORA_ALPHA, LORA_DROPOUT, LORA_TARGET_MODULES, MODAL_TOKEN_ID, MODAL_TOKEN_SECRET, MODAL_APP_NAME, MODAL_ENABLED, MODAL_TRAIN_GPU, MODAL_TRAIN_TIMEOUT, MODAL_INFER_GPU, MODAL_INFER_TIMEOUT, MODAL_CACHE_VOLUME, MODAL_OUTPUT_VOLUME, DUCKDB_PATH, RAW_DATA_DIR, PARQUET_DIR.
  • Recommendation schema: hero_id, hero_name, role, score, win_prob_delta, counter_lift, synergy_lift, sample_size, patch, scope, sources, confidence, caveats.
  • Gradio left-sidebar views: Ask, Draft, Meta, Builds, Predictor, Data.

Pipeline

  • Ingest pro tournaments first: OpenDota /proMatches, professional /leagues, /leagues/{league_id}/matches, then /matches/{match_id} and STRATZ match(id) enrichment.
  • Initial dataset mix: 65% pro/tournament, 25% high-rank current-patch public, 10% broad current-patch public for rare hero coverage.
  • Budget defaults: OpenDota free day uses about 1900 pro/current league calls, 750 high-rank/public enrichment calls, 250 constants/retries; STRATZ default day uses 7000 pro enrich, 2000 high-rank/public enrich, 1000 retry/schema reserve.
  • Prediction: train calibrated logistic baseline and LightGBM draft predictor; choose by temporal patch validation.
  • Recommendations: rank heroes by predicted win-probability delta plus empirical counter/synergy lift; builds come from observed item/skill/talent timing stats, not LLM invention.
  • RAG: index patch-change docs, hero stat cards, item constants, item timing stats, skill-build stats, and STRATZ match docs with patch/scope filters before retrieval.
  • Fine-tuning: default Tiny profile Qwen/Qwen3-4B-Instruct-2507; Balanced profile openbmb/MiniCPM4.1-8B; Quality profile Qwen/Qwen3-30B-A3B-Instruct-2507. Use explicit 4-bit QLoRA with TRL SFT on Modal A100-80GB, 1 epoch, structured answer examples, then push adapters to Hub.
  • Serving: HF Gradio Space loads compact predictor/RAG artifacts; Modal ui is a verified alternate Gradio endpoint, Modal train_sft handles GPU fine-tuning, and Modal generate_answer serves the fine-tuned adapter for explicit LLM responses.

Current Execution Process

  1. Configure local secrets in .env; never commit .env.
    • Required for live data/API smoke: HF_TOKEN, STRATZ_TOKEN, OPENDOTA_API_KEY, STEAM_API_KEY.
    • Required for Modal: MODAL_ENABLED=1, MODAL_APP_NAME=dota2tuned, MODAL_TOKEN_ID, MODAL_TOKEN_SECRET.
    • Modal GPU defaults: MODAL_TRAIN_GPU=A100-80GB, MODAL_TRAIN_TIMEOUT=21600, MODAL_INFER_GPU=A10G, MODAL_INFER_TIMEOUT=900, MODAL_CACHE_VOLUME=dota2tuned-hf-cache, MODAL_OUTPUT_VOLUME=dota2tuned-outputs.
  2. Install local dependencies for Modal work.
    • uv sync --extra modal --extra dev
  3. Validate live API configuration.
    • uv run dota2tuned smoke --live
  4. Validate code before external deploys.
    • uv run ruff check app.py src tests
    • uv run pytest -q
    • uv run python -c "from app import demo; print(type(demo).__name__, len(demo.blocks), len(demo.fns))"
  5. Deploy Modal functions.
    • uv run dota2tuned modal-deploy
    • Expected functions: ui, remote_smoke, train_sft, generate_answer.
    • Current Modal URL: https://dracufeuer--dota2tuned-ui.modal.run
  6. Verify Modal runtime artifacts.
    • uv run dota2tuned modal-smoke
    • Expected: Gradio Blocks, 14 Parquet files, RAG index present, SFT examples present.
  7. Train the QLoRA adapter on Modal.
    • Tiny: uv run dota2tuned modal-train --profile qwen3_4b_2507
    • Balanced: uv run dota2tuned modal-train --profile minicpm4_1_8b
    • Quality: uv run dota2tuned modal-train --profile qwen3_30b_a3b_2507
    • Initial Tiny call: fc-01KV2GTE604BCRND3M6AH3GGT1.
    • Current refreshed Tiny call: fc-01KV6SE7YRK1P0JC0NYS0FPBPP.
    • Completed Balanced call: fc-01KV6S4FD9JQ6K5TCA42MHM9RC.
    • Superseded Quality A100 call: fc-01KV6S4FC8PZHBR6Y9QPFQSNFQ, failed on A100 80GB OOM during k-bit preparation.
    • Superseded Quality H200 call: fc-01KV6SWYDQ0ASTQNSXXEQ0C412, failed on target-module parsing.
    • Superseded Quality H200 call: fc-01KV6T2WHK8TEJJJ9JM2M58RBA, failed because PEFT ParamWrapper rejects nonzero dropout.
    • Completed Quality H200 call: fc-01KV6TCTX9CSYVHJ98S3P5PTMK.
    • Output repos: build-small-hackathon/dota2tuned-qwen3-4b-2507-lora, build-small-hackathon/dota2tuned-minicpm4-1-8b-lora, and build-small-hackathon/dota2tuned-qwen3-30b-a3b-2507-lora.
    • Expected files: adapter_model.safetensors, adapter_config.json, tokenizer files, training_args.bin.
  8. Verify fine-tuned adapter inference.
    • uv run dota2tuned modal-ask "Suggest one mid hero against Phantom Assassin and Witch Doctor. Include one caveat."
    • Target behavior: concise grounded answer; caveat weak evidence; no invented heroes/items.
  9. Configure HF Space runtime variables/secrets for Modal-backed inference.
    • Variables: MODAL_ENABLED=1, MODAL_APP_NAME=dota2tuned.
    • Secrets: MODAL_TOKEN_ID, MODAL_TOKEN_SECRET.
    • Do not expose these values in logs or docs.
  10. Upload the Space code/artifacts through the Hub API with explicit ignore patterns.
    • Include compact serving artifacts: data/parquet/*.parquet, data/rag/tfidf.joblib, data/models/draft_predictor.joblib, data/models/sft_examples.jsonl.
    • Exclude .env, caches, raw data, probe data, run folders, and DuckDB files.
    • Current HF Space URL: https://build-small-hackathon-dota2tuned.hf.space.
  11. Wait for Space runtime status.
    • Use HfApi.space_info(...).runtime.stage.
    • Required terminal state: RUNNING.
  12. Final endpoint checks.
    • HF Space HTTP 200 and Modal UI HTTP 200.
    • uv run dota2tuned modal-smoke.
    • uv run dota2tuned modal-ask ....
    • git status --short --branch clean after commit/push.
  13. Confidence expansion gate.
    • The runtime confidence ceiling is high, defined in code as sample_size >= 500.
    • Audit current artifacts with uv run python scripts/audit_confidence.py --threshold 500.
    • Continue background expansion with scripts/run_confidence_expansion.sh after the active tmux ingest completes.
    • Default continuation policy: targets 12,000, 17,000, 22,000, 27,000 match details and a 30,000 cap unless overridden through DOTA2TUNED_CONFIDENCE_TARGET, DOTA2TUNED_CONFIDENCE_STEP, or DOTA2TUNED_CONFIDENCE_MAX_TARGET.
    • Stop early when every hero base sample reaches 500, when the source stops yielding new match details, or when the configured cap is reached. Rare heroes may remain below 500 even after large pro-match expansion because pick distribution is not uniform; those remain explicitly caveated.
  14. Targeted rare-hero backfill.
    • Use uv run dota2tuned targeted-ingest --threshold 500 --hero-limit 64 --matches-per-hero 700 --max-new-details 5000 to discover recent public match IDs for under-sampled heroes through OpenDota Explorer and append missing /matches/{match_id} details.
    • Use scripts/run_targeted_confidence_backfill.sh for the durable loop; each round runs targeted ingest, normalization, feature rebuild, predictor training, RAG rebuild, SFT generation, and confidence audit.
    • Retrain the Modal adapter only after the targeted fetch loop reaches high confidence or exhausts useful new match details, so the adapter is trained on the strongest available SFT snapshot.

Timeline

All times are America/Los_Angeles / PDT unless noted.

  • 2026-06-13 19:54:19: created the hackathon scaffold with PLAN.md, secret-safe env templates, package layout, API clients, pipeline commands, Gradio entrypoint, tests, and initial .gitignore rules.
  • 2026-06-13 20:29:39: completed model-selection pass and set Qwen/Qwen3-4B-Instruct-2507 as the default sub-32B base model, with HuggingFaceTB/SmolLM3-3B as fallback. Gemma-class options were considered but not selected because Qwen 4B gave the better balance for structured reasoning, tool-like answers, and compact QLoRA serving.
  • 2026-06-13 20:51:29: added live smoke checks for Hugging Face, STRATZ, OpenDota, and Steam configuration without printing secrets.
  • 2026-06-13 20:58:09: fixed Hugging Face Space package loading so src/ imports resolve correctly in the hosted runtime.
  • 2026-06-13 22:37:42: shipped compact data/model artifacts and A100 preflight wiring for GPU training readiness.
  • 2026-06-13 23:08:39: separated Hugging Face job token handling from general Hub token handling. This path was later superseded by Modal after the available credit source was corrected.
  • 2026-06-14 00:24:00: created and deployed the Modal app dota2tuned as the GPU execution backend.
  • 2026-06-14 00:26-00:30: first Modal remote smoke surfaced missing runtime env inside Modal. Fixed by baking MODAL_ENABLED=1 and MODAL_APP_NAME=dota2tuned into the Modal image environment while keeping credentials secret.
  • 2026-06-14 00:30-00:31: redeployed Modal; remote_smoke passed with Gradio Blocks, 11 Parquet artifacts, RAG index, and SFT examples available remotely. Modal UI returned HTTP 200 at https://dracufeuer--dota2tuned-ui.modal.run.
  • 2026-06-14 00:31: submitted an initial Modal training call, then cancelled it as stale after redeploy so training would run against the current image.
  • 2026-06-14 00:32-00:34: submitted fresh Modal training call fc-01KV2GTE604BCRND3M6AH3GGT1; QLoRA training completed and pushed the adapter to build-small-hackathon/dota2tuned-qwen3-4b-2507-lora.
  • 2026-06-14 00:34-00:35: verified the model repo contents, including adapter_model.safetensors, adapter_config.json, tokenizer files, chat template, and training_args.bin.
  • 2026-06-14 00:35:53: committed and pushed c4dd25b (feat: add modal gpu path) with the Modal deployment, training, and smoke-test path.
  • 2026-06-14 00:36-00:45: added Modal adapter inference via generate_answer, local CLI access through dota2tuned modal-ask, and grounded generation rules for evidence-aware Dota 2 answers.
  • 2026-06-14 00:46:02: committed and pushed 2cc4796 (feat: serve adapter on modal) with Modal inference serving.
  • 2026-06-14 00:47-01:00: configured HF Space variables and secrets for Modal-backed inference without exposing values, uploaded the refreshed Space bundle, and verified the canonical Space at https://build-small-hackathon-dota2tuned.hf.space.
  • 2026-06-14 01:00-01:12: added the Gradio Tuned Model tab, added the Space-side modal dependency, ran a 10-prompt Modal adapter eval, fixed one grounding issue around unsupported generic build advice, and retested Shadow Fiend and fake-hero prompts successfully.
  • 2026-06-14 01:13: updated this plan with the execution timeline. Current required finish checks are lint, tests, Gradio import smoke, commit/push, Space upload, Space HTTP 200, Modal UI HTTP 200, modal-smoke, and modal-ask.
  • 2026-06-14 01:21: checked the latest hackathon requirements again and added SUBMISSION.md with required links, final checklist, demo video script, social post draft, and verification commands.
  • 2026-06-14 01:27: addressed the submission-readiness review by adding hero-name parsing, making Draft Lab demoable, adding tests, preparing a dataset card, declaring Apache-2.0 licensing, and aligning the Modal dependency version.
  • 2026-06-14 02:36: continued demo-readiness hardening by adding role-aware recommendation filtering, Bayesian win-rate shrinkage for low samples, pre-game item timing labels, and a repeatable public Space API check script.
  • 2026-06-14 02:41: replaced the generic generated adapter README with a DOTA2Tuned-specific model card covering intended behavior, evidence discipline, usage, evaluation notes, limitations, and public links.
  • 2026-06-14 02:57: added a final submission-readiness checker that verifies public URLs, Space runtime, Hub model/dataset cards, git cleanliness, and all public Gradio API endpoints while listing the human-only video/social/submission steps separately.
  • 2026-06-14 03:29: started a durable tmux background data expansion toward 1,600 OpenDota match details, added checkpointed detail ingestion, moved recommendation confidence to normalized player-match samples, and upgraded the Gradio UI with searchable hero/item dropdowns, alias search, and icon previews.
  • 2026-06-14 03:49: completed the background data expansion with 1,604 enriched OpenDota match details, 16,040 player-match rows, 38,347 draft pick/ban rows, 728,416 item-purchase rows, 23,080 hero-pair rows, 32,517 build-stat rows, 1,604 draft predictor samples, and 279 SFT examples. Medium-confidence recommendations now appear where normalized sample sizes exceed 100.
  • 2026-06-14 03:50: started the next durable tmux expansion dota2tuned_data_expand toward 7,000 OpenDota match details with --pro-matches 8000 --public-matches 500 --enrich-limit 7000 --patch-count 4 --league-limit 50; the run continues in the background and checkpoints existing details every 25 new match fetches.
  • 2026-06-14 04:06: audited the current 1,604-match parquet artifacts before the 7,000-match run finished: 0 high-confidence heroes, 67 medium, 60 low, median sample 104, max sample 496. Added repeatable confidence audit and continuation scripts so expansion can proceed after the active tmux job until the 500-sample high-confidence gate is reached or the configured cap/source exhaustion stops it.
  • 2026-06-14 05:37: completed the 7,000-target expansion with 7,004 enriched OpenDota match details, 70,040 player-match rows, 166,082 draft pick/ban rows, 2,661,012 item-purchase rows, 30,734 hero-pair rows, 49,327 build-stat rows, 489 SFT examples, and draft predictor metrics roc_auc=0.5522, log_loss=0.7080, brier=0.2560.
  • 2026-06-14 06:19: confidence supervisor finished after attempting continuation through the 27,000 target. The available current source pool only grew to 8,562 enriched details, producing 85,619 player-match rows and confidence coverage of 74 high, 52 medium, 1 low, median sample 533, max sample 2479. Full max confidence was not reached because rare heroes, especially Elder Titan at sample 42, remain under the 500 high-confidence gate; further improvement requires broadening match discovery beyond the current OpenDota pro/league source pool.
  • 2026-06-14 15:13: added targeted rare-hero backfill based on OpenDota Explorer public_matches hero arrays. A capped smoke run targeted Elder Titan, discovered 10 candidate rows, fetched 5 new details, and raised raw OpenDota match details from 8,562 to 8,567 before launching the durable targeted loop.
  • 2026-06-14 16:18: polished Gradio dropdown UX by replacing packed role text symbols with image-backed role badges, adding role/scope dropdown icon decoration, keeping hero dropdown icon decoration, and preserving the Steam CDN Dota logo in the topbar. The targeted tmux loop was still running separately at 11,946 raw OpenDota match details and 3,380 targeted candidate rows.
  • 2026-06-14 16:36: removed all one-letter generated hero aliases from dropdown/search labels, kept curated conventional aliases such as AM and QoP, and replaced the top tab bar with a native left gr.Sidebar navigation so all former tab views share one consistent content layout.
  • 2026-06-14 16:54: refined the Gradio UI to match current Dota 2 web styling from the official Dota React bundle: Radiance font, black/blue-gray panels, ember red actions, muted gold accents, and plain icon+text sidebar navigation. Moved the DOTA2Tuned logo/text into the sidebar brand section, removed topbar reinjection, made view content full-width, kept hero dropdown rows icon-decorated, and changed selected hero previews to image-only cards.
  • 2026-06-14 17:37: incorporated the GitHub merge from terrible-additions, which filters Draft Coach hero dropdown choices across allies, enemies, and bans. Rechecked the current Dota home/heroes bundles and confirmed the homepage typography inherits font-family: "Radiance","Noto Sans",sans-serif; kept Radiance globally, narrowed red action-button styling to app content so Gradio utility controls stay neutral, shrank selected hero preview cards, and rendered hero dropdown roles as visible tag pills.
  • 2026-06-14 17:40: committed and pushed the Dota typography/UI fixes to GitHub as 32f691c with Codex coauthor, synced the same source/test/plan files to the Hugging Face Space as 3b4275d7, restarted the Space, and verified the public HTML now serves Radiance globally with .app-main button scoped action styling plus visible dropdown role tags.
  • 2026-06-14 17:46: reran the targeted confidence backfill supervisor. It exited without fetching more data because the current normalized artifacts already meet the 500 sample high-confidence gate for every hero: 127 high, 0 medium, 0 low, minimum sample 556, median 1016, max 3572.
  • 2026-06-14 18:04: switched all app text to the Dota Trajan Pro font assets, made sidebar nav labels uppercase, removed the style-only gr.HTML wrapper by passing CSS/JS through Gradio launch/mount paths, restored text-and-tag hero preview cards with remove buttons, hid selected hero tokens inside multiselect dropdowns so the control remains search-only, fixed chevron clicks by focusing the underlying dropdown input, and fixed the cross-browser dropdown scroll error by making injected option icons/tags non-interactive so Gradio receives events on the original option element.
  • 2026-06-14 18:07: removed the sidebar brand subtitle and added client-side sidebar navigation synchronization with stable view IDs so page content switches on the first click while the Gradio backend visibility callback catches up.
  • 2026-06-14 18:08: tightened role icon sizing inside hero-card tag pills so tag icons fit the allocated pill height instead of inheriting larger card image dimensions.
  • 2026-06-14 18:30: constrained Gradio dropdown overlays to the trigger/viewport width, scoped listbox CSS to .dota-dropdown, hid horizontal overflow, and added a runtime clamp that repositions fixed dropdown menus on open, scroll, and resize so long hero labels no longer push menus outside the field.
  • 2026-06-14 21:20: resolved the GitHub merge conflict in src/dota2tuned/ui/gradio_app.py by keeping the new Builds page while preserving the JS-only sidebar switching and dropdown clamp fixes. Refreshed direct dependency minimums and uv.lock to the latest resolved set, including Gradio 6.18.0, FastAPI 0.137.0, Transformers 5.12.0, Torch 2.12.0, Datasets 5.0.0, and matching Modal/HF training dependency lists. Validation passed with uv lock --check, uv run ruff check app.py src tests, uv run pytest -q, and a Gradio app-construction smoke check.
  • 2026-06-14 21:36: fixed the Hugging Face Space build after the dependency refresh by capping Pydantic to >=2.12.5,<2.13.0, the latest range compatible with the Space builder's injected gradio[oauth,mcp]==6.18.0. Revalidated with uv lock --check, uv run ruff check app.py src tests, uv run pytest -q, uv pip compile --python-version 3.12 requirements.txt - plus Space-injected requirements, and a Gradio app-construction smoke check. Next remote sync should upload code and tracked runtime artifacts, including data/rag/tfidf.joblib, so judges see the latest RAG artifacts in the Space.
  • 2026-06-14 21:48: fixed the dropdown scrollbar exception by ignoring inner dropdown-menu scroll events in the client-side overlay clamp and allowing hero multiselects to accept Gradio's transient [None] payload before sanitizing it back to valid hero IDs. Added regression tests for transient null hero selections and the menu-scroll guard. Validation passed with uv run ruff check app.py src tests, uv run pytest -q, a Gradio app-construction smoke check, and an assertion that all hero multiselect dropdowns have allow_custom_value=True.
  • 2026-06-14 21:53: corrected the dropdown scroll fix after the first patch caused Draft Coach dropdowns to re-render during scroll. Transient [None] events now return gr.skip() for choice filtering and hero previews, and the scroll guard ignores any .options or [role="listbox"] scroll target, including portaled Gradio dropdown menus. Revalidated with uv run ruff check app.py src tests, uv run pytest -q, and Gradio app construction.
  • 2026-06-14 22:11: fixed the Draft Coach hero dropdown field layout after Gradio 6 placed the chevron wrapper outside the visible input area. Replaced the forced 100% hero search width with a flex/min-width-safe dropdown layout, reserved right-side input padding for .icon-wrap, and made the secondary search wrappers transparent so Allied heroes, Enemy heroes, and Banned heroes no longer show a distinct nested text background.
  • 2026-06-14 22:18: fixed selected hero-card readability by changing the direct hero portrait image to object-fit: contain in the existing 48x36 slot, narrowing the portrait selector so role icons are not affected, and allowing hero names to wrap instead of being ellipsized.
  • 2026-06-14 22:25: fixed stale dropdown search rendering after confirming Gradio can reuse option DOM nodes while changing the underlying aria-label/text. The client decorator now stores the label it rendered, removes only DOTA2Tuned-injected icon/label children when a reused row changes, and observes option label/text mutations so visible search results match the actual clickable choice.
  • 2026-06-14 22:59: added an early startup loader in APP_HEAD so the app shows the DOTA2Tuned brand and Dota symbol while Gradio mounts instead of briefly exposing bare elements. The Dota symbol pulses from white to the palette red #ff6046 and back over a 4.2 second cycle, and the sidebar brand icon uses the same animation after the loader exits.
  • 2026-06-14 23:15: removed the remaining Gradio blue primary backgrounds by routing primary/theme variables, block labels, selected radio/checkbox labels, and range accents through the same red action fill used by the Recommend button. This covers Allied heroes, Enemy heroes, Banned heroes, Role, Scope, and equivalent labeled inputs across all mounted app views.
  • 2026-06-14 23:21: made selected hero-card portrait backgrounds transparent and smoothed the Dota symbol pulse for both the startup loader and sidebar brand by using matching filter functions across all keyframes, with intermediate 25%/75% stops inside the existing 4.2 second white-red-white cycle.
  • 2026-06-14 23:39: hardened the startup loader against first-paint flashes by hiding .gradio-container by default until html.d2-ready, adding a CSS-only body::before/after branded fallback before the JS loader div can mount, and revealing the app only after the Gradio load hook waits for fonts, currently-mounted images, and paint frames, with a timeout fallback.
  • 2026-06-14 23:44: removed the redundant Builds page selected-hero preview gr.HTML component and its change handler, eliminating the extra generated html-container wrapper while keeping the Builds dropdown and actual builds output intact.
  • 2026-06-15 01:37: aligned the Builds page .build-hero-header portrait with the conventional hero-card icon treatment: 48x36 landscape slot, object-fit: contain, transparent background, and no square crop. Started tmux job dota2tuned_pro_patch_fetch to continue pro/tournament-focused OpenDota ingestion from 15,144 existing match details using --pro-matches 50000 --public-matches 0 --enrich-limit 25000 --league-limit 250, then normalize, rebuild features, retrain the draft predictor, rebuild RAG, regenerate SFT, and run a confidence audit. The live official patch context is 7.41d from June 4, 2026; OpenDota metadata still reports the major patch as 7.41.
  • 2026-06-15 01:48: fetched the complete official Valve patch-note family for the recent 7.41 line: 7.41, 7.41a, 7.41b, 7.41c, and 7.41d; 7.41e returned no rows. Updated patch ingestion to expand major versions through lettered suffixes a through e, refreshed doc_patch_change.parquet, rebuilt RAG, regenerated SFT examples, and validated 2,333 total 7.41-family patch-change rows. Also preserved the user change that forces GRADIO_SSR_MODE=False before Gradio import in app.py.
  • 2026-06-15 02:10: doubled the Builds page .build-hero-header hero icon from 48x36 to 96x72 while preserving the conventional landscape shape, transparent background, and object-fit: contain. Confirmed dota2tuned_pro_patch_fetch finished successfully with 15,989 OpenDota match details, 9,202 pro match summaries, 9,202 league/tournament match rows, 0 public rows, 150 STRATZ details, 159,888 normalized player-match rows, refreshed predictor/RAG/SFT artifacts, and confidence audit high=127, medium=0, low=0, max_confidence=True.
  • 2026-06-15 02:40: investigated the HF Space startup log noise against Gradio 6.18.0 and upstream Gradio issue #12699 (ValueError: Invalid file descriptor: -1 on Spaces). Moved the targeted unraisable-hook filter into a stdlib-only startup path, added root sitecustomize.py so it installs before Gradio imports, moved CLI UI imports behind serve, added conservative cleanup of any idle main-thread event loop before Gradio/Uvicorn launch, and added a targeted asyncio.BaseEventLoop.__del__ guard that suppresses only the invalid-fd destructor error while preserving unrelated exceptions.
  • 2026-06-15 02:58: promoted the tuned model to the first/default sidebar view and rebuilt it as a GPT/Claude-style assistant landing surface: centered prompt composer, sample prompt chips, automatic local RAG evidence retrieval, Modal fine-tuned model call, rendered answer text, detected hero/item icon chips, linked source cards for Valve patch notes/OpenDota hero stat cards, and raw evidence in a collapsed panel.
  • 2026-06-15 03:07: removed the duplicate landing-page DOTA2Tuned heading block from the assistant view while keeping the sidebar brand and tuned-model composer/result surface intact.
  • 2026-06-15 03:12: aligned the assistant view with the rest of the app pages by dropping the centered hero-style layout and making the tuned-model surface full-width, top-aligned, compactly spaced, and flush with the existing app view grid.
  • 2026-06-15 03:20: centered the startup-loader radial glow on the combined Dota icon and DOTA2Tuned text mark in both the critical first-paint fallback and hydrated loader, then changed the glow from inner Dota red #ff6046 to outer Dota gold #d9b166.
  • 2026-06-15 03:42: increased the centered startup-loader radial glow by 30%, from 22rem to 28.6rem, while keeping the red-to-gold gradient centered on the brand mark in both loader paths.
  • 2026-06-15 04:02: diagnosed the Safari dropdown layering bug as a Gradio/Svelte stacking-chain issue: the fixed dropdown menu was nested under a .dota-dropdown block with overflow: hidden and a parent .form with overflow: auto hidden, so Safari could clip or paint the leftmost menu under later rows. Promoted the open dropdown plus its .form/.row/.app-view ancestors with temporary classes, forced the menu layer to fixed z-index: 10000, and kept ancestor overflow visible only while a menu is open.
  • 2026-06-15 04:18: added the official Dota 2 homepage montage video as the startup-loader background, using the Steam WebM/MP4 sources with muted inline autoplay and keeping the red-to-gold radial glow plus dark vignette as an overlay/fallback.
  • 2026-06-15 04:24: fixed the loader video visibility by changing the hydrated loader overlay from an opaque dark linear gradient to translucent RGBA layers and increasing the video layer opacity/brightness, so the montage remains visible behind the brand mark.
  • 2026-06-15 04:34: enabled Gradio share=True in both Space and CLI launch paths, added a narrow startup warning filter for Gradio's deprecated Starlette 422 constant, and added root agents.md with Space/API instructions for coding agents.
  • 2026-06-15 04:50: fixed the HF Space startup log regression from share=True: Gradio sharing is now enabled only for local runs, while HF Space containers use share=False and quiet=True because Spaces are already public and Gradio does not support share tunnels there.
  • 2026-06-15 04:59: raised loader asset priority by preloading Trajan font weights, the Dota logo, and the MP4 montage in APP_HEAD; declared critical Trajan font faces before the loader CSS; added eager/fetch-priority hints to the logo/video elements; and explicitly warmed loader fonts plus the video in startup JS.
  • 2026-06-15 05:07: fixed the mobile responsiveness breakpoint where Gradio expanded the open sidebar to the full viewport width. Below 820px, the sidebar now becomes a compact sticky top navigation bar with horizontal scrolling tabs, while an unscoped head override removes Gradio's outer mobile padding so the active page content keeps the full mobile viewport width below it.
  • 2026-06-15 05:12: standardized scrollbars across the app to use slim dark-track styling with Dota palette thumbs, and hardened the startup loader video for Safari by using the MP4 as the direct source plus muted inline autoplay attributes/properties (defaultMuted, playsinline, and webkit-playsinline) before playback.
  • 2026-06-15 05:16: moved the real startup-loader video into middleware-injected initial body HTML so Safari sees a visible muted inline <video> during document parse instead of waiting for Gradio's delayed head= injection. The app-head script now primes an existing critical loader and retries playback on loadeddata, canplay, and visibility changes while recording any play-block reason on the video dataset.
  • 2026-06-15 05:26: added an explicit Dota-styled startup-loader play button for Safari's autoplay safeguard path. The button is centered below the DOTA2Tuned icon/text, sits above all video and gradient layers, and invokes the same video prime/play logic in both the critical initial-body loader and the hydrated loader fallback.
  • 2026-06-15 05:34: researched Safari's native video start overlay and confirmed it is browser-owned, with older WebKit pseudo-elements only a best-effort positioning path because newer Safari/iOS controls can live in closed UA shadow DOM. Removed the custom loader play button completely, restored pointer events on the loader video so Safari's native play affordance is active, and moved the WebKit ::-webkit-media-controls-start-playback-button down with a scoped transform to keep it below the DOTA2Tuned icon/text.
  • 2026-06-15 05:51: removed the red/gold circular radial glow from the startup loader now that the Steam montage video is the visual background. Kept the dark linear video overlays/vignette so the DOTA2Tuned mark remains legible.
  • 2026-06-15 06:13: returned loader video handling to the normal Gradio/app-head path instead of middleware-injecting duplicate body HTML. Kept parse-time priority loading by injecting only critical preconnect/preload hints for Trajan fonts, the Dota logo, and the MP4 montage; moved the loader brand above Safari's native play affordance and added a centered app description below it.
  • 2026-06-15 06:27: removed the unreliable WebKit native play-button transform and made the loader brand/description symmetric around the default native play area.
  • 2026-06-15 06:43: normalized code output sections to Gradio accordion panels, restored the Retrieved Evidence accordion style, added selected-value icons for hero/item/role/scope/mode dropdowns, hid empty hero/item preview placeholders, and aligned action-button fills with the red field-label treatment.
  • 2026-06-15 06:58: replaced Evidence/Prediction accordions with direct gr.Code blocks so the generated .label-wrap accordion button is not rendered, while keeping the top-panel code toolbar background transparent.
  • 2026-06-15 07:16: removed rich icon/tag injection from opened dropdown option lists, kept selected-value icons in closed fields, added selected-option checkmarks, hid empty preview gr.HTML containers with visible=False updates, made hero-card remove buttons truly circular, and added THN-inspired scramble-resolve plus red/gold glitch-settle animation for dynamic text across previews, assistant outputs, build cards, and markdown result regions.
  • 2026-06-15 08:22: restored rich dropdown option rows with hero/item icons and hero role tags, added a leading selected checkmark inside those rows, hid duplicate selected labels in the dropdown input while preserving visible typed search text and the blinking caret, replaced Gradio processing/time trackers with static module status strips, and matched the code toolbar top-panel background to its parent with borders removed.
  • 2026-06-15 08:41: removed the static module status strips, restored Gradio's processing/time tracker while rewriting Processing to Thinking, added module explanation intros, expanded tuned-model sample prompts, removed selected hero text/icons from closed hero dropdown fields without changing rich dropdown lists, restored readable role/scope field text, and removed residual code-toolbar button borders.
  • 2026-06-15 08:58: collapsed Gradio's selected hero/item token DOM inside closed dropdown controls by preserving selected labels in data-*, clearing the internal token text spans, hiding token icons, and keeping the existing preview/result divs as the visible selected-content surface.
  • 2026-06-15 09:16: hid Gradio's native selected-option check span inside every decorated hero/item dropdown row so only the custom left checkmark is visible. Added stable ids for Hero Meta hero/item and Builds hero dropdowns, refreshed hidden single-select state before option decoration, and verified Builds remains single-selection after sequential hero picks.
  • 2026-06-15 13:23: extended the startup loader with a Trajan-styled red/gold loading ring and module-inspired scramble/glitch ready text. The montage video now plays once for its full duration; once app assets are ready, the ring/text becomes a clickable Skip control, while automatic entry waits for video end.
  • 2026-06-15 13:43: fixed rapid-selection text animation races by moving scramble frames into a non-mutating overlay and adding sequence/cancel state, so hero-card text cannot settle as randomized garbage. Reworked Draft Coach, Hero Meta, Match Predictor, and Draft Lab selector layouts so each dropdown owns the preview block directly below it instead of using separate left-filled preview rows.
  • 2026-06-15 13:48: converted the startup loader ring from a spinner into a determinate red/gold conic progress meter with center percentage text and a dot at the current completion angle. Slowed loader and module text randomizer frames so text resolves visibly left-to-right instead of appearing all at once.
  • 2026-06-15 14:01: moved the loader progress control to the bottom center of the viewport, underlined its status text, and changed the ready copy to Loading completed · Click to skip. Recalibrated loader progress with a drift loop and higher readiness milestones so it moves through intermediate percentages instead of jumping from the mid-50s to 100, and reset the conic arc to start at the top axis instead of the left.
  • 2026-06-15 14:07: reversed the determinate loader ring gradient so the filled arc now runs from Dota gold to Dota red while keeping the progress angle, center percentage, and endpoint dot behavior unchanged.
  • 2026-06-15 14:18: moved loader status text animation to the same non-mutating left-to-right scramble overlay used by module text. Both Loading platform and Loading completed · Click to skip now visibly randomize before settling with the red/gold pulse.
  • 2026-06-15 14:27: removed the duplicate Tuned Model pending tracker from the assistant HTML output while preserving the bottom Evidence tracker as the single visible Thinking | time indicator. Compacted that remaining tracker so it does not reserve an oversized panel before evidence content loads.
  • 2026-06-15 14:34: refined Tuned Model pending state again: neutralized Gradio's greyed pending opacity on the assistant HTML output, expanded the remaining Evidence Thinking | time tracker to cover its full parent block, and slowed the loader status randomizer to one letter per timed step with a longer red/gold settle pulse.
  • 2026-06-15 14:40: retuned the loader status animation to be 50% faster than the previous slow pass while keeping the left-to-right one-letter randomizer behavior and a shorter red/gold settle pulse.
  • 2026-06-15 14:45: merged the origin/Builds branch into main. The merge adds OpenDota ability constants, ability-upgrade normalization, per-role item build buckets, skill-build order artifacts, refreshed Builds page role filtering, core-item highlights, and larger item/ability icon presentation while preserving AGENTS.md.
  • 2026-06-15 16:10: rebuilt the refreshed pro/tournament data artifacts after the latest STRATZ expansion: 16,000 OpenDota match details, 1,950 raw STRATZ match details, 15,784 normalized matches, 159,998 player-match rows, 292,124 draft pick/ban rows, 3,432,956 item-purchase rows, 95,519 skill-build rows, 1,786 normalized STRATZ match docs, and predictor metrics roc_auc=0.5241, log_loss=0.7022, brier=0.2542.
  • 2026-06-15 16:10: rebuilt RAG and SFT with STRATZ, item, and skill evidence. Current RAG has 15,508 documents: 7,094 Valve patch notes, 3,000 item timing docs, 3,000 skill-build docs, 1,786 STRATZ match docs, 501 item constants, and 127 hero stat cards. Current SFT has 942 examples across STRATZ match evidence, pair stats, hero meta, build timing, skill builds, patch notes, item meta, and draft recommendations.
  • 2026-06-15 16:12: merged the latest origin/Builds commits again after review, keeping the short sidebar labels and new Ask/Draft/Meta/Builds/Predictor/Data structure while preserving the branch's Draft onboarding guide and dropdown bug fixes.
  • 2026-06-15 16:14: redeployed Modal with the latest model-profile code, STRATZ RAG artifacts, and a Transformers compatibility shim for MiniCPM remote code. Submitted background Modal fine-tunes for Balanced fc-01KV6S4FD9JQ6K5TCA42MHM9RC and Quality fc-01KV6S4FC8PZHBR6Y9QPFQSNFQ.
  • 2026-06-15 16:18: Balanced MiniCPM4.1 8B training completed successfully and pushed adapter files to build-small-hackathon/dota2tuned-minicpm4-1-8b-lora. Submitted a refreshed Tiny Qwen3 4B training call fc-01KV6SE7YRK1P0JC0NYS0FPBPP against the same 942-example SFT snapshot to remove ambiguity about whether Tiny reflects the latest STRATZ/item/skill data.
  • 2026-06-15 16:21: audited the latest origin/Builds commit 90806fa, which keeps preview HTML components mounted to avoid Gradio dropping first-selection visibility updates. Fast-forwarded main, reapplied local work without conflicts, extended the same preview behavior to the new Meta skill selector, and updated the UI regression test for the new always-mounted preview contract.
  • 2026-06-15 16:26: added scripts/watch_modal_training.py and started durable tmux session dota2tuned_modal_training_watch so Modal training stays monitored in the background. Current log: logs/modal-training-watch-tmux-20260615-1632.log.
  • 2026-06-15 16:29: Quality Qwen3 30B-A3B failed on the original A100 80GB training function with CUDA OOM during prepare_model_for_kbit_training. Updated Quality to use a dedicated Modal train_sft_quality function on H200, set PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True, reduced Quality LoRA/context settings for reliability, redeployed Modal, and resubmitted Quality as fc-01KV6SWYDQ0ASTQNSXXEQ0C412.
  • 2026-06-15 16:39: Quality H200 progressed past memory and target-module setup, then failed because PEFT's ParamWrapper path rejects nonzero LoRA dropout for this model. Set Quality lora_dropout=0.0 and prepared another retry.
  • 2026-06-15 16:45: Quality Qwen3 30B-A3B retry fc-01KV6TCTX9CSYVHJ98S3P5PTMK completed successfully and pushed to build-small-hackathon/dota2tuned-qwen3-30b-a3b-2507-lora.
  • 2026-06-15 16:47: added Draft-style New here? How to use ... guide cards to Ask, Meta, Builds, Predictor, and Data; kept Draft's existing guide; and documented the Build Small README validator/social-post requirement in README.md and SUBMISSION.md.

Adapter Eval Notes

  • Ran 10 Modal adapter prompts covering draft, countering Phantom Assassin, Crystal Maiden synergy, Shadow Fiend build timing, patch/meta caveats, prediction limits, fake hero refusal, support pick, anti-push response, and low-sample caveats.
  • Mechanical pass: 10/10 calls returned status=ok with non-empty answers.
  • Found and fixed one grounding weakness: generic Shadow Fiend build prompt produced unsupported item advice. The Modal inference system prompt now forbids inventing hero names, item names, scores, timings, patches, or match data and requires an uncertainty response when evidence is missing or generic.
  • Targeted retest passed:
    • Generic Shadow Fiend build prompt now says no specific item timing is available without concrete evidence.
    • Fake hero Banana King is rejected as not a real Dota 2 hero.

Test Plan

  • Unit tests: API clients, auth headers, rate limiters, retry/cache keys, patch parser, normalizers, schema validation.
  • Data checks: no duplicate match IDs, valid hero/item IDs, correct patch join by start_time, no abandoned/remake training matches, no future-patch leakage.
  • Model evals: ROC-AUC, log loss, Brier/calibration for match prediction; Recall@K/NDCG@K for recommendations; citation support rate for generated answers.
  • App checks: Gradio import/launch smoke, GPU availability logging, no secret leakage, deterministic fallback when model/backend unavailable.
  • Modal checks: disabled-by-default local behavior, backend function smoke when MODAL_ENABLED=1, ui HTTP 200, bundled artifacts visible remotely, and GPU training call tracked by Modal function call id.

Assumptions

  • The team can create the required HF Space before the June 15, 2026 deadline.
  • Modal credits are available for QLoRA training.
  • Modal can host an alternate Gradio endpoint, but the Hugging Face Space remains the canonical hackathon submission link.
  • STRATZ/OpenDota/Steam tokens will be supplied in .env; no tokens will be committed.