draftomen 0.3.1__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. draftomen-0.4.0/MANIFEST.in +1 -0
  2. draftomen-0.4.0/PKG-INFO +448 -0
  3. draftomen-0.4.0/README.md +420 -0
  4. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/audit.py +199 -32
  5. draftomen-0.4.0/draftomen/augmented_artifact.py +1081 -0
  6. draftomen-0.4.0/draftomen/augmented_manifest.py +404 -0
  7. draftomen-0.4.0/draftomen/augmented_model_client.py +659 -0
  8. draftomen-0.4.0/draftomen/augmented_public_data.py +338 -0
  9. draftomen-0.4.0/draftomen/augmented_publication.py +447 -0
  10. draftomen-0.4.0/draftomen/augmented_training.py +1116 -0
  11. draftomen-0.4.0/draftomen/augmented_training_data.py +644 -0
  12. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/backtest.py +67 -11
  13. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/benchmark.py +17 -10
  14. draftomen-0.4.0/draftomen/card_data_client.py +482 -0
  15. draftomen-0.4.0/draftomen/card_data_export.py +640 -0
  16. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/carddb.py +929 -266
  17. draftomen-0.4.0/draftomen/cli.py +1938 -0
  18. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/config.py +20 -2
  19. draftomen-0.4.0/draftomen/corpus.py +1772 -0
  20. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/deckbuilder.py +1218 -32
  21. draftomen-0.4.0/draftomen/draftmancer.py +1187 -0
  22. draftomen-0.4.0/draftomen/draftmancer_server.py +305 -0
  23. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/events.py +3 -0
  24. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/mock_session.py +66 -6
  25. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/paths.py +3 -0
  26. draftomen-0.4.0/draftomen/pickengine.py +3018 -0
  27. draftomen-0.4.0/draftomen/pool_ledger.py +1084 -0
  28. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/preferences.py +20 -3
  29. draftomen-0.4.0/draftomen/profile_batch_generation.py +705 -0
  30. draftomen-0.4.0/draftomen/profile_client.py +1037 -0
  31. draftomen-0.4.0/draftomen/profile_data_refresh.py +606 -0
  32. draftomen-0.4.0/draftomen/profile_generation.py +1639 -0
  33. draftomen-0.4.0/draftomen/profile_generation_execution.py +859 -0
  34. draftomen-0.4.0/draftomen/profile_generation_stage_policy.py +283 -0
  35. draftomen-0.4.0/draftomen/profile_input_acquisition.py +1820 -0
  36. draftomen-0.4.0/draftomen/profile_input_cache.py +1155 -0
  37. draftomen-0.4.0/draftomen/profile_manifest.py +365 -0
  38. draftomen-0.4.0/draftomen/profile_publication.py +801 -0
  39. draftomen-0.4.0/draftomen/profile_refresh_execution.py +1869 -0
  40. draftomen-0.4.0/draftomen/profile_statistics.py +153 -0
  41. draftomen-0.4.0/draftomen/progress.py +70 -0
  42. draftomen-0.4.0/draftomen/public_dump.py +846 -0
  43. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/qml/AppBar.qml +15 -0
  44. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/qml/CardPreview.qml +91 -14
  45. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/qml/LiveDraftView.qml +182 -17
  46. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/qml/Main.qml +9 -0
  47. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/qml/RecentPicksGallery.qml +1 -1
  48. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/qml/RecommendationRow.qml +6 -3
  49. draftomen-0.4.0/draftomen/qml/SettingsTextField.qml +37 -0
  50. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/qml/SettingsView.qml +216 -95
  51. draftomen-0.4.0/draftomen/qml/StateBanner.qml +284 -0
  52. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/qml/StatusStrip.qml +48 -0
  53. draftomen-0.4.0/draftomen/qml/TestDraftDialog.qml +339 -0
  54. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/qml/qmldir +2 -0
  55. draftomen-0.4.0/draftomen/qt_adapter.py +2069 -0
  56. draftomen-0.4.0/draftomen/qt_gui.py +1256 -0
  57. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/ranking.py +9 -9
  58. draftomen-0.4.0/draftomen/refresh_plan.py +865 -0
  59. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/replay.py +125 -47
  60. draftomen-0.4.0/draftomen/semantic_roles.py +2309 -0
  61. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/session.py +1949 -651
  62. draftomen-0.4.0/draftomen/set_card_data.py +712 -0
  63. draftomen-0.4.0/draftomen/set_profile.py +1396 -0
  64. draftomen-0.4.0/draftomen/sets_manifest.py +253 -0
  65. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/seventeen.py +241 -148
  66. draftomen-0.4.0/draftomen/test_draft.py +1208 -0
  67. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/tui.py +460 -199
  68. draftomen-0.4.0/draftomen/watch.py +537 -0
  69. draftomen-0.4.0/draftomen.egg-info/PKG-INFO +448 -0
  70. draftomen-0.4.0/draftomen.egg-info/SOURCES.txt +161 -0
  71. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen.egg-info/requires.txt +1 -0
  72. {draftomen-0.3.1 → draftomen-0.4.0}/pyproject.toml +38 -3
  73. draftomen-0.4.0/scripts/hob_model_c_training.py +124 -0
  74. draftomen-0.4.0/tests/test_audit.py +913 -0
  75. draftomen-0.4.0/tests/test_augmented_artifact.py +362 -0
  76. draftomen-0.4.0/tests/test_augmented_manifest.py +122 -0
  77. draftomen-0.4.0/tests/test_augmented_model_client.py +471 -0
  78. draftomen-0.4.0/tests/test_augmented_public_data.py +618 -0
  79. draftomen-0.4.0/tests/test_augmented_publication.py +647 -0
  80. draftomen-0.4.0/tests/test_augmented_training.py +1074 -0
  81. draftomen-0.4.0/tests/test_augmented_training_data.py +376 -0
  82. draftomen-0.4.0/tests/test_backtest.py +798 -0
  83. {draftomen-0.3.1 → draftomen-0.4.0}/tests/test_benchmark.py +194 -5
  84. draftomen-0.4.0/tests/test_card_data_client.py +473 -0
  85. draftomen-0.4.0/tests/test_card_data_export.py +892 -0
  86. draftomen-0.4.0/tests/test_carddb.py +1144 -0
  87. draftomen-0.4.0/tests/test_ci_workflow_config.py +55 -0
  88. draftomen-0.4.0/tests/test_cli.py +3680 -0
  89. draftomen-0.4.0/tests/test_corpus.py +645 -0
  90. {draftomen-0.3.1 → draftomen-0.4.0}/tests/test_deckbuilder.py +857 -3
  91. draftomen-0.4.0/tests/test_desktop_bundle.py +1231 -0
  92. draftomen-0.4.0/tests/test_draftmancer.py +1505 -0
  93. draftomen-0.4.0/tests/test_draftmancer_server.py +469 -0
  94. {draftomen-0.3.1 → draftomen-0.4.0}/tests/test_mock_session.py +84 -1
  95. draftomen-0.4.0/tests/test_pickengine.py +4630 -0
  96. draftomen-0.4.0/tests/test_pool_ledger.py +582 -0
  97. {draftomen-0.3.1 → draftomen-0.4.0}/tests/test_preferences.py +127 -0
  98. draftomen-0.4.0/tests/test_profile_batch_generation.py +532 -0
  99. draftomen-0.4.0/tests/test_profile_client.py +1040 -0
  100. draftomen-0.4.0/tests/test_profile_data_refresh.py +985 -0
  101. draftomen-0.4.0/tests/test_profile_generation.py +1680 -0
  102. draftomen-0.4.0/tests/test_profile_generation_execution.py +1034 -0
  103. draftomen-0.4.0/tests/test_profile_generation_stage_policy.py +193 -0
  104. draftomen-0.4.0/tests/test_profile_input_acquisition.py +1621 -0
  105. draftomen-0.4.0/tests/test_profile_input_cache.py +461 -0
  106. draftomen-0.4.0/tests/test_profile_manifest.py +214 -0
  107. draftomen-0.4.0/tests/test_profile_publication.py +852 -0
  108. draftomen-0.4.0/tests/test_profile_refresh_execution.py +1576 -0
  109. draftomen-0.4.0/tests/test_profile_refresh_publication.py +1514 -0
  110. draftomen-0.4.0/tests/test_profile_refresh_workflow_config.py +329 -0
  111. draftomen-0.4.0/tests/test_profile_refresh_workflow_helper.py +1884 -0
  112. draftomen-0.4.0/tests/test_profile_statistics.py +176 -0
  113. draftomen-0.4.0/tests/test_progress.py +86 -0
  114. draftomen-0.4.0/tests/test_public_dump.py +332 -0
  115. draftomen-0.4.0/tests/test_qt_adapter.py +5746 -0
  116. draftomen-0.4.0/tests/test_qt_gui.py +10220 -0
  117. {draftomen-0.3.1 → draftomen-0.4.0}/tests/test_qt_mock.py +26 -1
  118. draftomen-0.4.0/tests/test_refresh_plan.py +386 -0
  119. draftomen-0.4.0/tests/test_replay.py +817 -0
  120. draftomen-0.4.0/tests/test_semantic_roles.py +826 -0
  121. draftomen-0.4.0/tests/test_session.py +8549 -0
  122. draftomen-0.4.0/tests/test_set_card_data.py +309 -0
  123. draftomen-0.4.0/tests/test_set_profile.py +793 -0
  124. draftomen-0.4.0/tests/test_sets_manifest.py +174 -0
  125. {draftomen-0.3.1 → draftomen-0.4.0}/tests/test_seventeen.py +231 -5
  126. draftomen-0.4.0/tests/test_test_draft.py +2257 -0
  127. {draftomen-0.3.1 → draftomen-0.4.0}/tests/test_tui.py +1336 -486
  128. draftomen-0.4.0/tests/test_watch.py +1729 -0
  129. draftomen-0.3.1/PKG-INFO +0 -156
  130. draftomen-0.3.1/README.md +0 -129
  131. draftomen-0.3.1/draftomen/cli.py +0 -891
  132. draftomen-0.3.1/draftomen/pickengine.py +0 -1117
  133. draftomen-0.3.1/draftomen/qml/StateBanner.qml +0 -189
  134. draftomen-0.3.1/draftomen/qt_adapter.py +0 -884
  135. draftomen-0.3.1/draftomen/qt_gui.py +0 -338
  136. draftomen-0.3.1/draftomen/watch.py +0 -336
  137. draftomen-0.3.1/draftomen.egg-info/PKG-INFO +0 -156
  138. draftomen-0.3.1/draftomen.egg-info/SOURCES.txt +0 -87
  139. draftomen-0.3.1/tests/test_audit.py +0 -379
  140. draftomen-0.3.1/tests/test_backtest.py +0 -179
  141. draftomen-0.3.1/tests/test_carddb.py +0 -501
  142. draftomen-0.3.1/tests/test_cli.py +0 -716
  143. draftomen-0.3.1/tests/test_desktop_bundle.py +0 -256
  144. draftomen-0.3.1/tests/test_pickengine.py +0 -1042
  145. draftomen-0.3.1/tests/test_qt_adapter.py +0 -1124
  146. draftomen-0.3.1/tests/test_qt_gui.py +0 -4126
  147. draftomen-0.3.1/tests/test_replay.py +0 -278
  148. draftomen-0.3.1/tests/test_session.py +0 -3176
  149. draftomen-0.3.1/tests/test_watch.py +0 -600
  150. {draftomen-0.3.1 → draftomen-0.4.0}/LICENSE +0 -0
  151. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/__init__.py +0 -0
  152. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/assets/draftomen.icns +0 -0
  153. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/assets/draftomen.ico +0 -0
  154. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/assets/draftomen_logo.png +0 -0
  155. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/cardimages.py +0 -0
  156. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/logfollow.py +0 -0
  157. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/pool.py +0 -0
  158. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/qml/AboutDialog.qml +0 -0
  159. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/qml/BacktestView.qml +0 -0
  160. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/qml/BuildView.qml +0 -0
  161. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/qml/DimensionalButton.qml +0 -0
  162. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/qml/DimensionalComboBox.qml +0 -0
  163. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/qml/DimensionalSurface.qml +0 -0
  164. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/qml/DimensionalTabButton.qml +0 -0
  165. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/qml/NavigationRail.qml +0 -0
  166. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/qml/PoolSummaryPanel.qml +0 -0
  167. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/qml/PrivacyDialog.qml +0 -0
  168. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/qml/RecentPickThumbnail.qml +0 -0
  169. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/qml/SettingsSwitch.qml +0 -0
  170. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/qml/Theme.qml +0 -0
  171. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/qt_mock.py +0 -0
  172. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/setinfo.py +0 -0
  173. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen/splash.py +0 -0
  174. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen.egg-info/dependency_links.txt +0 -0
  175. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen.egg-info/entry_points.txt +0 -0
  176. {draftomen-0.3.1 → draftomen-0.4.0}/draftomen.egg-info/top_level.txt +0 -0
  177. {draftomen-0.3.1 → draftomen-0.4.0}/setup.cfg +0 -0
  178. {draftomen-0.3.1 → draftomen-0.4.0}/tests/test_cardimages.py +0 -0
  179. {draftomen-0.3.1 → draftomen-0.4.0}/tests/test_events.py +0 -0
  180. {draftomen-0.3.1 → draftomen-0.4.0}/tests/test_extract_changelog.py +0 -0
  181. {draftomen-0.3.1 → draftomen-0.4.0}/tests/test_logfollow.py +0 -0
  182. {draftomen-0.3.1 → draftomen-0.4.0}/tests/test_paths.py +0 -0
  183. {draftomen-0.3.1 → draftomen-0.4.0}/tests/test_pool.py +0 -0
  184. {draftomen-0.3.1 → draftomen-0.4.0}/tests/test_render_homebrew_formula.py +0 -0
@@ -0,0 +1 @@
1
+ include scripts/hob_model_c_training.py
@@ -0,0 +1,448 @@
1
+ Metadata-Version: 2.4
2
+ Name: draftomen
3
+ Version: 0.4.0
4
+ Summary: An unofficial Quick Draft assistant for MTG Arena
5
+ Author: Andrea Grandi
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/andreagrandi/draftomen
8
+ Project-URL: Repository, https://github.com/andreagrandi/draftomen
9
+ Project-URL: Issues, https://github.com/andreagrandi/draftomen/issues
10
+ Keywords: draft,magic-the-gathering,mtg-arena,terminal,tui
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: End Users/Desktop
14
+ Classifier: Operating System :: MacOS
15
+ Classifier: Operating System :: Microsoft :: Windows
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Games/Entertainment
20
+ Requires-Python: >=3.12
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: pyside6<7,>=6.9
24
+ Requires-Dist: python-socketio[client]<6,>=5.16.4
25
+ Requires-Dist: textual>=8.2.8
26
+ Requires-Dist: textual-image>=0.13.2
27
+ Dynamic: license-file
28
+
29
+ <p align="center">
30
+ <img src="https://raw.githubusercontent.com/andreagrandi/draftomen/master/docs/assets/draftomen_banner.png" alt="Draft Omen banner" width="100%">
31
+ </p>
32
+
33
+ # Draft Omen
34
+
35
+ Draft Omen is an unofficial desktop draft assistant for MTG Arena Quick Drafts. Its PySide6/QML application reads Arena's local `Player.log`, recognizes each pack and pick, and ranks the available cards while you draft. When the draft is complete, it also suggests a 40-card deck from your pool. A terminal interface with the same draft behavior is available as `draftomen-tui`.
36
+
37
+ Draft Omen is read-only: it does not write to, inject into, or automate MTG Arena. Card details come from [Scryfall](https://scryfall.com/) and draft statistics come from [17Lands](https://www.17lands.com/).
38
+
39
+ ## Screenshots
40
+
41
+ ### Live Draft GUI — pick recommendations
42
+
43
+ The Live Draft view shows Pack 1, Pick 3 with 12 cards available and Glóin the Mighty selected. Its DO Score, 17Lands win rate, grade, and color fit appear alongside focused-card details and a pool summary.
44
+
45
+ ![Draft Omen Live Draft GUI showing Pack 1, Pick 3 with 12 cards available, Glóin the Mighty selected, ranked card rows, DO Score, 17Lands win rate, grade, color fit, focused-card details, and pool summary](https://raw.githubusercontent.com/andreagrandi/draftomen/master/docs/assets/draft-pick-recommendations.png)
46
+
47
+ ### Suggested deck GUI
48
+
49
+ After the draft, the Suggested deck view shows an automatic UR pair and a 40-card build with 23 spells, 17 lands, a mana base and curve, grouped main-deck spells, and selected-card details.
50
+
51
+ ![Draft Omen Suggested deck GUI with an automatic UR pair, 40-card build with 23 spells and 17 lands, mana base, mana curve, grouped main-deck spells, and Tidings of War selected](https://raw.githubusercontent.com/andreagrandi/draftomen/master/docs/assets/suggested-deck-build.png)
52
+
53
+ ## How recommendations work
54
+
55
+ Draft Omen keeps the data behind every recommendation visible instead of presenting a black-box pick order:
56
+
57
+ - **17Lands ratings:** each card shows its Games-in-Hand win rate (`17L WR`) and a 17Lands-style grade. Quick Draft data is preferred; Premier Draft data is used as a fallback when Quick Draft samples are missing or too small.
58
+ - **DO Score:** the default 0-100 ranking normalizes 17Lands win rates across the set. A card without a reliable sample starts from a neutral score of 50, adjusted by its Average Last Seen At (`ALSA`) when available. The five freely available basic lands instead score 0 and rank after draftable cards.
59
+ - **Color fit:** early picks stay open. From pick 6 onward, scores gradually favor the colors supported by the drafted pool; from pick 16, on-color cards receive the full bonus and off-color cards the full penalty. Strong picks influence the inferred color pair more than filler.
60
+ - **Close early picks:** when two cards have similar scores, set- and format-specific 17Lands color-pair win rates can break the tie without forcing an early commitment.
61
+ - **Conservative splashing:** an `A`-range, single-pip card can be marked as a visible third-color splash when it is materially better than the on-color choices and the pool can support its mana. Draft Omen limits this to one extra color and two cards.
62
+ - **Transparent alternatives:** press `s` to compare rankings by DO Score, raw 17Lands win rate, ALSA, or mana value. The interface also identifies neutral-prior and Premier-fallback rows.
63
+ - **Deck suggestion:** the builder evaluates two-color pairs using card quality and 17Lands pair performance, then chooses spells and lands while considering creatures, curve, colored mana requirements, and cached 17Lands deck-structure targets when available.
64
+
65
+ DO Score is the default because it performed better than raw 17Lands win rate in Draft Omen's offline pick benchmarks. It is still guidance rather than a perfect pick order: public statistics reflect the decks, players, and contexts in which cards were played.
66
+
67
+ For the complete methodology, see [pick scoring](docs/pick-scoring.md), [benchmarking](docs/benchmarking.md), and the [deck builder](docs/deck-builder.md).
68
+
69
+ ## How to use it
70
+
71
+ ### 1. Install
72
+
73
+ On macOS, install Draft Omen with Homebrew:
74
+
75
+ ```bash
76
+ brew install andreagrandi/tap/draftomen
77
+ ```
78
+
79
+ On other platforms, [install uv](https://docs.astral.sh/uv/getting-started/installation/) and run:
80
+
81
+ ```bash
82
+ uv tool install draftomen
83
+ ```
84
+
85
+ ### 2. Enable Arena logs
86
+
87
+ In MTG Arena, open **Settings → Account**, enable **Detailed Logs (Plugin Support)**, and restart Arena.
88
+
89
+ ### 3. Start Draft Omen
90
+
91
+ Start Draft Omen before entering a Quick Draft:
92
+
93
+ ```bash
94
+ draftomen
95
+ ```
96
+
97
+ The PySide6/QML desktop application loads card metadata when needed, watches
98
+ Arena's standard log location, detects the set, and follows the draft
99
+ automatically. Native and terminal live sessions use the shared set-profile
100
+ lifecycle as their sole ratings authority. They load a validated local profile
101
+ cache first, so a warm valid profile is active immediately while an allowed
102
+ hosted-profile refresh proceeds. If the production manifest (or an explicit
103
+ override) is absent, inaccessible, invalid, or has no profile for the set, the
104
+ cached profile is retained; with no usable cache, deterministic fallback scoring
105
+ remains active. Live sessions do not load ratings directly from 17Lands.
106
+
107
+ Native and terminal live commands use
108
+ `https://www.draftomen.com/profiles/manifest.json` by default. For the desktop
109
+ command, use `--profile-manifest-url URL` to select an explicit HTTPS manifest,
110
+ or `--offline-profiles` to select profile-only offline mode:
111
+
112
+ ```bash
113
+ draftomen --profile-manifest-url "$PROFILE_MANIFEST_URL"
114
+ draftomen --offline-profiles
115
+ ```
116
+
117
+ `--offline-profiles` selects `ProfileNetworkPolicy.OFFLINE` and takes
118
+ precedence over profile networking only. It does not disable Scryfall card
119
+ metadata, card images, or static card-data networking.
120
+
121
+ The TUI `d` action and the native ratings refresh control use the existing
122
+ shared profile-refresh command boundary. A newer validated profile reports an
123
+ `updated` outcome and changes recommendations in place; an equal result reports
124
+ `unchanged` and leaves the current ratings active. Failed, offline, or missing
125
+ refreshes retain the last usable cache when ratings exist; with no usable
126
+ profile, deterministic fallback scoring remains active. Repeated requests
127
+ coalesce, and `watch --plain` has no command UI.
128
+
129
+ ### Terminal interface
130
+
131
+ For a terminal workflow, use the stable `draftomen-tui` command. It provides
132
+ watch, replay, build, backtest, benchmark, data-refresh, `export-set-data`,
133
+ local `generate-profile`, and `refresh-profile` commands:
134
+
135
+ ```bash
136
+ draftomen-tui
137
+ draftomen-tui watch
138
+ draftomen-tui watch --plain
139
+ draftomen-tui watch --offline-profiles
140
+ draftomen-tui watch --profile-manifest-url "$PROFILE_MANIFEST_URL"
141
+ ```
142
+
143
+ Terminal `watch` and `watch --plain` use the production hosted manifest by
144
+ default. `--profile-manifest-url` selects an alternate HTTPS manifest, and
145
+ `--offline-profiles` disables only profile networking; Scryfall card data,
146
+ images, and other static data sources retain their own network/cache behavior.
147
+
148
+ To generate a deterministic set profile from pinned input files, use
149
+ `generate-profile` with explicit set, format, stage, timezone-aware timestamp,
150
+ card-database, and output paths. The producer and cache workflow, including
151
+ remote manifest fields, validation, refresh, recovery, and explicit provider
152
+ ingestion, is documented in [set profiles](docs/set-profiles.md).
153
+
154
+ ### Static set card data
155
+
156
+ The live card lookup uses one schema-versioned (schema version `1`), canonical
157
+ Scryfall artifact per Arena set. Artifacts are published at
158
+ `website/public/card-data/<lowercase-set-code>.json.gz` and hosted at
159
+ `https://www.draftomen.com/card-data/<lowercase-set-code>.json.gz`.
160
+ Generate one set by exact code or full name, or discover every eligible set:
161
+
162
+ ```bash
163
+ draftomen-tui export-set-data SET
164
+ draftomen-tui export-set-data
165
+ ```
166
+
167
+ Discovery makes one `17Lands /data/expansions` request and one Scryfall
168
+ default-cards bulk acquisition. No-argument discovery requires at least 200
169
+ distinct Arena card identities per set; paper-only, Cube, Chaos, and Remix
170
+ sets are excluded. `--inventory-file PATH` and `--bulk-file PATH` replace
171
+ those network sources for reproducible or offline runs. The all-set command
172
+ validates existing artifacts, publishes pending sets in code order, and can be
173
+ rerun to resume from the first pending set.
174
+
175
+ ### Sets manifest
176
+
177
+ `website/public/sets/manifest.json`, hosted at
178
+ `https://www.draftomen.com/sets/manifest.json`, lists every set with a
179
+ card-data file. Each entry records the set name, the card-data URL, byte size
180
+ and SHA-256, the published profile formats with their maturity, and the
181
+ augmented model metrics when one exists. `export-set-data`,
182
+ `build-augmented-set` and the Profile Refresh publication regenerate it from
183
+ the files under `website/public`, and a test fails when the committed file
184
+ no longer matches them.
185
+
186
+ In live mode, Draft Omen detects the set before loading its selected artifact.
187
+ The default cache path is the application-data `card-data/<set-code>.json.gz`
188
+ file (normally `~/.draftomen/card-data/<set-code>.json.gz`); a valid cache is
189
+ reused without network access. Card metadata is automatically loaded at most
190
+ once per pre-draft detection lifecycle for a selected set; no card-data network
191
+ request is made after `DraftStartedEvent`.
192
+ Printed card fields and images come from Scryfall; 17Lands ratings and
193
+ statistics remain a separate data source and are not embedded in card-data
194
+ artifacts.
195
+
196
+ In the TUI, press `r` to retry a recoverable card-data error. Network repair is
197
+ available only before draft start; after `DraftStartedEvent`, retries use the
198
+ local cache only.
199
+
200
+ ### Hosted set profiles and profile-only offline mode
201
+
202
+ Native and terminal set-profile loading is local-first and hosted by default. A
203
+ validated flat cache is used before any network refresh, so a warm valid cache
204
+ remains active while the production manifest is checked. The default manifest
205
+ for both live commands is:
206
+
207
+ ```text
208
+ https://www.draftomen.com/profiles/manifest.json
209
+ ```
210
+
211
+ Override it for a different HTTPS manifest:
212
+
213
+ ```bash
214
+ draftomen --profile-manifest-url "$PROFILE_MANIFEST_URL"
215
+ draftomen-tui watch --profile-manifest-url "$PROFILE_MANIFEST_URL"
216
+ draftomen-tui watch --plain --profile-manifest-url "$PROFILE_MANIFEST_URL"
217
+ ```
218
+
219
+ Use `--offline-profiles` for profile-only offline operation:
220
+
221
+ ```bash
222
+ draftomen --offline-profiles
223
+ draftomen-tui watch --offline-profiles
224
+ draftomen-tui watch --plain --offline-profiles
225
+ ```
226
+
227
+ This flag selects `ProfileNetworkPolicy.OFFLINE` for set profiles only and
228
+ takes precedence over profile networking. It does not disable Scryfall card
229
+ metadata, card images, or static card-data networking; those sources retain
230
+ their own cache and network policies.
231
+
232
+ When a hosted manifest or artifact is missing, unreachable, invalid, or weaker
233
+ than the cached profile, the last-good cache remains authoritative. If there
234
+ is no usable cache, deterministic fallback scoring remains active; live
235
+ sessions do not load ratings directly from 17Lands. The TUI `d` action and the
236
+ native ratings refresh control request the same forced hosted-profile refresh.
237
+ A newer validated profile reports an `updated` outcome and changes
238
+ recommendations in place; an equal result reports `unchanged` and leaves
239
+ ratings active. Failed, offline, or missing refreshes retain the last usable
240
+ cache when ratings exist; with no usable profile, deterministic fallback
241
+ scoring remains active. Repeated requests coalesce, and `watch --plain` has
242
+ no command UI.
243
+
244
+ Manual `refresh-profile` remains an explicit producer/client operation:
245
+
246
+ ```bash
247
+ draftomen-tui refresh-profile --set-code SET --format FORMAT \
248
+ --manifest-url "$PROFILE_MANIFEST_URL"
249
+ ```
250
+
251
+ Draft Omen does not bundle a hosted manifest. Producer generation, website
252
+ publication, and Python/native release workflows remain independent of runtime
253
+ profile consumption. Native applications may still carry a validated baseline
254
+ profile resource for local fallback; hosted refresh never mutates that
255
+ resource.
256
+
257
+ For development-only semantic analysis, use the reproducible [card corpus
258
+ workflow](docs/corpus.md). It keeps pinned source bytes and locks outside
259
+ tracked data and emits deterministic artifacts for offline consumers.
260
+
261
+ Use the arrow keys or `j`/`k` to browse cards, `s` to change the ranking,
262
+ `b` to open the current build, `c` to configure the view and optional splash
263
+ recommendations, `d` to refresh the hosted profile in the TUI, and `q` to quit.
264
+
265
+ ### Visual development
266
+
267
+ For deterministic visual development, launch the explicit forced-mock entry
268
+ point:
269
+
270
+ ```bash
271
+ draftomen-gui-mockup
272
+ ```
273
+
274
+ For an automated, non-interactive GUI smoke check, use the default command
275
+ with its mock provider and bounded smoke flag:
276
+
277
+ ```bash
278
+ QT_QPA_PLATFORM=offscreen draftomen --provider mock --smoke-test
279
+ ```
280
+
281
+ See the [desktop GUI guide](docs/gui-mockup.md) for live and mock launch
282
+ options, selectable states, and responsive review targets. For reproducible
283
+ unsigned development bundles, see the [desktop bundle guide](docs/desktop-bundles.md).
284
+
285
+ ### Draftmancer protocol development
286
+
287
+ The Draftmancer protocol smoke requires Node.js 22 and a sibling checkout;
288
+ do not put the simulator in a tracked or vendored directory. From the parent
289
+ directory of this repository:
290
+
291
+ ```bash
292
+ git clone https://github.com/Senryoku/Draftmancer.git
293
+ cd Draftmancer
294
+ git checkout --detach df08e5ef647aae54e0b1c569e70b4b2aa5e0016c
295
+ npm ci
296
+ npm run build-server
297
+ DISABLE_PERSISTENCE=TRUE npm start
298
+ ```
299
+
300
+ Download Scryfall's complete default-cards bulk source once through the
301
+ development corpus cache; the smoke never performs per-card API requests:
302
+
303
+ ```bash
304
+ uv run draftomen-tui corpus-build --selection explicit --set-code HOB
305
+ ```
306
+
307
+ With the pinned server running, open a second terminal in Draft Omen and run:
308
+
309
+ ```bash
310
+ uv run python scripts/draftmancer_smoke.py \
311
+ --draftmancer-dir ../Draftmancer
312
+ ```
313
+
314
+ The helper, rather than ordinary Draft Omen startup, owns the simulator
315
+ connection. It chooses the first simulator card instance deterministically
316
+ only to complete the protocol smoke; it does not apply recommendations or
317
+ manage the Draftmancer service.
318
+
319
+ HOB is the default and required real-smoke target. The helper maps each
320
+ Draftmancer Scryfall printing ID through the local bulk file's `oracle_id` to
321
+ the canonical HOB Arena grpId. Missing, ambiguous, or unknown identities fail
322
+ before an offer reaches `LiveSession`. Pass `--scryfall-bulk-file` only when
323
+ the complete local JSONL bulk cache is stored somewhere other than
324
+ `.draftomen/corpus-cache/sources/scryfall-default-cards.jsonl.gz`.
325
+
326
+ The same pinned checkout and bulk source drive the headless test draft, which
327
+ drafts a complete three-pack event through production recommendations and the
328
+ normal deck builder:
329
+
330
+ ```bash
331
+ uv run draftomen-tui test-draft \
332
+ --draftmancer-dir ../Draftmancer
333
+ ```
334
+
335
+ `test-draft` always drafts automatically: it confirms the first ranked
336
+ recommendation of every offered pack, prints one
337
+ `Pack N pick M: <card> (grpId <id>)` line per accepted pick, and finishes with
338
+ the ordinary deck-builder report. It reads the configured card-data cache and
339
+ set profiles from the normal application directory, keeps simulated draft state
340
+ and audit records in a private temporary directory, and neither reads nor
341
+ changes Arena draft history.
342
+
343
+ `--set-code` accepts any set present in both Draftmancer's `MTGASets` and the
344
+ local card-data cache (HOB by default); an unsupported set fails before any
345
+ pick, and a booster printing that cannot be resolved to one canonical Arena
346
+ grpId fails before that pack is submitted.
347
+
348
+ `--server-url`, `--scryfall-bulk-file`, and `--timeout` mirror the smoke
349
+ defaults, and `--profile-manifest-url` / `--offline-profiles` behave as in
350
+ `watch`. Startup, drafting, and deck-building failures report
351
+ `test-draft failed: <reason>` and exit nonzero; the command never starts,
352
+ stops, or configures the Draftmancer service.
353
+
354
+ The native application serves the same developer checkout itself. With the Mocked
355
+ Draft setting enabled the application starts the pinned checkout on a port it
356
+ picks, adopts a server that already answers the configured location, and stops
357
+ only the process it started when the draft is left or the application exits. The
358
+ three source values live in Settings → DEVELOPER next to the Mocked Draft switch —
359
+ the Draftmancer checkout directory, the Draftmancer server URL, and the Scryfall
360
+ bulk file — each prefilled with the application-data location, editable in the
361
+ running app, and still overridden by `--draftmancer-dir`, `--test-draft-server-url`,
362
+ and `--scryfall-bulk-file`.
363
+
364
+ Mocked Draft reads that Scryfall bulk file for printed card identities, and it does
365
+ not ship with the file. When the file is missing, the dialog offers **Download
366
+ Scryfall data**: the application fetches Scryfall's `default_cards` bulk JSONL (about
367
+ 80 MB, gzip) from `https://api.scryfall.com/bulk-data` and installs it as
368
+ `corpus-cache/sources/scryfall-default-cards.jsonl.gz` under the application data
369
+ directory — the path the Scryfall bulk file setting shows. The download runs in the
370
+ background with progress, never installs a partial file over an existing one, and
371
+ leaves the dialog ready without a restart. Nothing is downloaded automatically.
372
+
373
+ The native app journeys need the enabled setting instead of a manually managed server:
374
+
375
+ ```bash
376
+ uv run draftomen
377
+ ```
378
+
379
+ The dialog offers the sets the pinned checkout and the local card-data cache
380
+ both provide (HOB, the application's default test-draft set, whenever both have
381
+ it) and lets the developer choose Manual or Auto. Manual mode confirms the
382
+ selected recommendation with the **Pick** button in the ordinary live drafting
383
+ view and leaves the run through the dialog's **Leave test draft** button, while
384
+ Auto reuses the normal completed-draft and build surfaces. Without the enabled
385
+ setting no Mocked Draft control is present, and the Pick button stays hidden
386
+ during ordinary Arena drafting. The TUI/CLI commands and the compiled-bundle
387
+ helper keep requiring the developer-managed server above.
388
+
389
+ The complete acceptance workflow is three developer-run commands. The headless and
390
+ compiled-bundle commands run against the developer-managed pinned server above,
391
+ while the interactive launch uses the enabled Mocked Draft setting and its
392
+ self-served checkout:
393
+
394
+ A headless auto draft proves the production recommendation and deck-building
395
+ path end to end against the real protocol:
396
+
397
+ ```bash
398
+ uv run draftomen-tui test-draft \
399
+ --draftmancer-dir ../Draftmancer
400
+ ```
401
+
402
+ The compiled bundle proves both native journeys in one invocation. Auto drafts
403
+ to the ordinary build result, and Manual confirms five picks through the real
404
+ Test Draft controls. The helper requires each journey's summary line and proves
405
+ the external server is still alive before and after:
406
+
407
+ ```bash
408
+ uv run python tests/bundle_smoke.py --test-draft \
409
+ --draftmancer-dir ../Draftmancer \
410
+ --scryfall-bulk-file .draftomen/corpus-cache/sources/scryfall-default-cards.jsonl.gz \
411
+ --app-dir <prepared-dir> \
412
+ dist-native/macos-unsigned/Draftomen-unsigned-macos.app
413
+ ```
414
+
415
+ An interactive launch proves a developer can start a simulated draft, confirm
416
+ picks, and leave it by hand through those same controls:
417
+
418
+ ```bash
419
+ uv run draftomen
420
+ ```
421
+
422
+ To run the same pinned server through a compiled bundle instead of the source
423
+ tree, see [Native Test Draft smoke
424
+ (manual)](docs/desktop-bundles.md#native-test-draft-smoke-manual) in the desktop
425
+ bundle guide, which lists the prerequisites, the prepared app directory, and
426
+ both journey summary lines.
427
+
428
+ Live recommendations currently support Quick Draft. Windows support is best-effort.
429
+
430
+ ## Local draft audit data
431
+
432
+ Live sessions started with `draftomen-tui`, including `watch --plain`, keep an
433
+ independent, append-only JSONL audit log for every draft under
434
+ `~/.draftomen/audit/drafts/<account-id>/<draft-id>.jsonl`. Each record includes
435
+ the offered pack, pool snapshot, ratings source, scoring configuration, complete
436
+ candidate calculations, splash eligibility and mana-source reasoning, all
437
+ supported rankings, the recommendation visible when the pick was made, and the
438
+ card actually chosen. Stable record IDs prevent
439
+ startup scans and log rotation from rewriting prior evidence.
440
+
441
+ Offline `replay` and backtest commands do not write audit records. For the schema
442
+ and retention details, see [draft audit logging](docs/draft-audit-log.md).
443
+
444
+ ## Branding and compliance
445
+
446
+ Draft Omen is not affiliated with, sponsored by, approved by, or endorsed by Wizards of the Coast, Scryfall, or 17Lands.
447
+
448
+ Draft Omen is unofficial Fan Content permitted under the Fan Content Policy. Not approved/endorsed by Wizards. Portions of the materials used are property of Wizards of the Coast. ©Wizards of the Coast LLC. Card data from Scryfall and 17Lands; neither service endorses this tool.