gapit 0.3.1__tar.gz → 0.5.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 (413) hide show
  1. {gapit-0.3.1 → gapit-0.5.0}/AGENTS.md +58 -15
  2. gapit-0.5.0/CHANGELOG.md +473 -0
  3. {gapit-0.3.1 → gapit-0.5.0}/PKG-INFO +39 -19
  4. {gapit-0.3.1 → gapit-0.5.0}/PLAN.md +75 -0
  5. {gapit-0.3.1 → gapit-0.5.0}/README.md +36 -16
  6. {gapit-0.3.1 → gapit-0.5.0}/SPEC.md +22 -26
  7. {gapit-0.3.1 → gapit-0.5.0}/docs/agents.md +18 -11
  8. gapit-0.5.0/docs/agents.zh.md +205 -0
  9. gapit-0.5.0/docs/custom-db.zh.md +434 -0
  10. gapit-0.5.0/docs/databases.md +745 -0
  11. gapit-0.5.0/docs/databases.zh.md +701 -0
  12. {gapit-0.3.1 → gapit-0.5.0}/docs/faq.md +22 -8
  13. gapit-0.5.0/docs/faq.zh.md +111 -0
  14. {gapit-0.3.1 → gapit-0.5.0}/docs/index.md +12 -9
  15. gapit-0.5.0/docs/index.zh.md +48 -0
  16. {gapit-0.3.1 → gapit-0.5.0}/docs/installation.md +19 -14
  17. gapit-0.5.0/docs/installation.zh.md +107 -0
  18. {gapit-0.3.1 → gapit-0.5.0}/docs/mcp.md +12 -12
  19. gapit-0.5.0/docs/mcp.zh.md +294 -0
  20. {gapit-0.3.1 → gapit-0.5.0}/docs/outputs.md +188 -14
  21. gapit-0.5.0/docs/outputs.zh.md +565 -0
  22. {gapit-0.3.1 → gapit-0.5.0}/docs/quickstart.md +44 -8
  23. gapit-0.5.0/docs/quickstart.zh.md +177 -0
  24. {gapit-0.3.1 → gapit-0.5.0}/docs/reads.md +7 -7
  25. gapit-0.5.0/docs/reads.zh.md +573 -0
  26. gapit-0.5.0/docs/screen.md +377 -0
  27. gapit-0.5.0/docs/screen.zh.md +361 -0
  28. {gapit-0.3.1 → gapit-0.5.0}/docs/summary.md +2 -2
  29. gapit-0.5.0/docs/summary.zh.md +179 -0
  30. gapit-0.5.0/docs/typing.md +328 -0
  31. gapit-0.5.0/docs/typing.zh.md +308 -0
  32. gapit-0.5.0/mkdocs.yml +69 -0
  33. {gapit-0.3.1 → gapit-0.5.0}/pixi.lock +11 -2
  34. {gapit-0.3.1 → gapit-0.5.0}/pixi.toml +2 -1
  35. {gapit-0.3.1 → gapit-0.5.0}/pyproject.toml +9 -9
  36. gapit-0.5.0/recipe/meta.yaml +70 -0
  37. gapit-0.5.0/scripts/cluster_calibration.py +183 -0
  38. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/__init__.py +1 -1
  39. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/blast.py +14 -3
  40. gapit-0.5.0/src/gapit/bundled.py +148 -0
  41. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/cli.py +19 -9
  42. gapit-0.5.0/src/gapit/cluster.py +251 -0
  43. gapit-0.5.0/src/gapit/cluster_math.py +125 -0
  44. gapit-0.5.0/src/gapit/clusterbuild.py +200 -0
  45. gapit-0.5.0/src/gapit/cmd_db.py +124 -0
  46. gapit-0.5.0/src/gapit/cmd_db_build.py +111 -0
  47. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/cmd_db_install.py +6 -6
  48. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/cmd_db_outdated.py +11 -9
  49. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/cmd_db_search.py +10 -6
  50. gapit-0.5.0/src/gapit/cmd_screen.py +279 -0
  51. gapit-0.5.0/src/gapit/cmd_screen_reads_args.py +38 -0
  52. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/cmd_summary.py +8 -6
  53. gapit-0.5.0/src/gapit/cmd_typing.py +107 -0
  54. gapit-0.5.0/src/gapit/data/dbs/ecoh/bundled.json +7 -0
  55. gapit-0.5.0/src/gapit/data/dbs/ecoh/sequences +13445 -0
  56. gapit-0.5.0/src/gapit/data/dbs/ecoli_dec/bundled.json +7 -0
  57. gapit-0.5.0/src/gapit/data/dbs/ecoli_dec/sequences +352 -0
  58. gapit-0.5.0/src/gapit/data/dbs/ecoli_dec/typing.json +125 -0
  59. gapit-0.5.0/src/gapit/data/dbs/ncbi/bundled.json +7 -0
  60. gapit-0.5.0/src/gapit/data/dbs/ncbi/sequences +143433 -0
  61. gapit-0.5.0/src/gapit/data/dbs/resfinder/bundled.json +7 -0
  62. gapit-0.5.0/src/gapit/data/dbs/resfinder/sequences +54493 -0
  63. gapit-0.5.0/src/gapit/data/dbs/upec_expec_vf/bundled.json +7 -0
  64. gapit-0.5.0/src/gapit/data/dbs/upec_expec_vf/sequences +2648 -0
  65. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/db.py +27 -3
  66. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/db_build_ops.py +56 -8
  67. gapit-0.5.0/src/gapit/db_ops.py +286 -0
  68. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/db_query_ops.py +4 -28
  69. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/dbbuild.py +15 -5
  70. gapit-0.5.0/src/gapit/dispatch.py +72 -0
  71. gapit-0.5.0/src/gapit/engines.py +31 -0
  72. gapit-0.5.0/src/gapit/formats/cluster.py +236 -0
  73. gapit-0.5.0/src/gapit/formats/cluster_md.py +164 -0
  74. gapit-0.5.0/src/gapit/formats/json.py +158 -0
  75. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/formats/md.py +60 -36
  76. gapit-0.3.1/src/gapit/formats/json.py → gapit-0.5.0/src/gapit/formats/reads_json.py +8 -111
  77. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/formats/schemas.py +10 -6
  78. gapit-0.5.0/src/gapit/formats/tsv.py +67 -0
  79. gapit-0.5.0/src/gapit/formats/typing_result.py +146 -0
  80. gapit-0.5.0/src/gapit/fragments.py +131 -0
  81. gapit-0.5.0/src/gapit/gbfeatures.py +308 -0
  82. gapit-0.5.0/src/gapit/gffparse.py +204 -0
  83. gapit-0.5.0/src/gapit/hits.py +155 -0
  84. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/mcp_schemas.py +25 -11
  85. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/mcp_tools.py +22 -5
  86. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/minimap2_run.py +8 -7
  87. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/paf.py +16 -3
  88. gapit-0.5.0/src/gapit/providers/__init__.py +59 -0
  89. gapit-0.5.0/src/gapit/providers/ab_k.py +38 -0
  90. gapit-0.5.0/src/gapit/providers/ab_o.py +39 -0
  91. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/providers/argannot.py +1 -1
  92. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/providers/bacmet2.py +1 -1
  93. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/providers/card.py +6 -1
  94. gapit-0.5.0/src/gapit/providers/cluster_common.py +82 -0
  95. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/providers/common.py +19 -55
  96. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/providers/ecoh.py +1 -1
  97. gapit-0.5.0/src/gapit/providers/ecoli_kps.py +39 -0
  98. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/providers/ecoli_vf.py +6 -1
  99. gapit-0.5.0/src/gapit/providers/kosc_k.py +41 -0
  100. gapit-0.5.0/src/gapit/providers/kosc_o.py +41 -0
  101. gapit-0.5.0/src/gapit/providers/kpsc_k.py +40 -0
  102. gapit-0.5.0/src/gapit/providers/kpsc_o.py +40 -0
  103. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/providers/megares.py +1 -1
  104. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/providers/ncbi.py +1 -1
  105. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/providers/plasmidfinder.py +1 -1
  106. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/providers/resfinder.py +1 -1
  107. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/providers/upec_expec_vf.py +1 -1
  108. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/providers/vfdb.py +5 -1
  109. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/providers/victors.py +1 -1
  110. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/records.py +20 -3
  111. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/report.py +3 -1
  112. gapit-0.5.0/src/gapit/screening.py +200 -0
  113. gapit-0.5.0/src/gapit/screening_cluster.py +166 -0
  114. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/screening_reads.py +8 -3
  115. gapit-0.5.0/src/gapit/typing_decide.py +106 -0
  116. gapit-0.5.0/src/gapit/typing_engine.py +263 -0
  117. gapit-0.5.0/src/gapit/typing_gene.py +172 -0
  118. gapit-0.5.0/src/gapit/typing_input.py +234 -0
  119. gapit-0.5.0/src/gapit/typing_models.py +299 -0
  120. gapit-0.5.0/src/gapit/typing_ops.py +100 -0
  121. gapit-0.5.0/src/gapit/typing_results.py +110 -0
  122. gapit-0.5.0/src/gapit/typing_rules.py +179 -0
  123. gapit-0.5.0/tests/data/bundled_differential/resfinder/HEAD.zip +0 -0
  124. gapit-0.5.0/tests/data/bundled_differential/resfinder/README.md +15 -0
  125. gapit-0.5.0/tests/data/cluster/bakta_style.gbk +73 -0
  126. gapit-0.5.0/tests/data/cluster/clusters.gff3 +16 -0
  127. gapit-0.5.0/tests/data/cluster/clusters_gz.gff3.gz +0 -0
  128. gapit-0.5.0/tests/data/cluster/clusters_sidecar.fa +7 -0
  129. gapit-0.5.0/tests/data/cluster/clusters_sidecar.gff3 +8 -0
  130. gapit-0.5.0/tests/data/cluster/compound.gbk +19 -0
  131. gapit-0.5.0/tests/data/cluster/gz_input.gbk.gz +0 -0
  132. gapit-0.5.0/tests/data/cluster/kaptive_style.gbk +48 -0
  133. gapit-0.5.0/tests/data/cluster/nofasta.gff3 +8 -0
  134. gapit-0.5.0/tests/data/cluster/screening.gbk +82 -0
  135. gapit-0.5.0/tests/data/cluster/typing_invalid.json +9 -0
  136. gapit-0.5.0/tests/data/cluster/typing_screen.json +22 -0
  137. gapit-0.5.0/tests/data/cluster/typing_screen_cm.json +22 -0
  138. gapit-0.5.0/tests/data/cluster/typing_screen_v2.json +27 -0
  139. gapit-0.5.0/tests/data/cluster/typing_valid.json +31 -0
  140. gapit-0.5.0/tests/data/cluster/unnamed_cds.gbk +29 -0
  141. gapit-0.5.0/tests/data/fragments/fragdb/sequences +11 -0
  142. gapit-0.5.0/tests/data/fragments/split3040.fa +9 -0
  143. gapit-0.5.0/tests/data/fragments/split4060.fa +12 -0
  144. gapit-0.5.0/tests/data/fragments/split5050.fa +12 -0
  145. gapit-0.5.0/tests/data/typing/dec_s1_aggR_pic_uidA.fasta +100 -0
  146. gapit-0.5.0/tests/data/typing/dec_s2_pic_astA_uidA.fasta +90 -0
  147. gapit-0.5.0/tests/data/typing/dec_s3_stx2a_escV_aggR_uidA.fasta +85 -0
  148. gapit-0.5.0/tests/data/typing/exact.fa +39 -0
  149. gapit-0.5.0/tests/data/typing/listeria_1c.fa +29 -0
  150. gapit-0.5.0/tests/data/typing/listeria_4b.fa +32 -0
  151. gapit-0.5.0/tests/data/typing/listeria_nogate.fa +9 -0
  152. gapit-0.5.0/tests/data/typing/markers.fa +39 -0
  153. gapit-0.5.0/tests/data/typing/mutated.fa +39 -0
  154. gapit-0.5.0/tests/data/typing/negative.fa +30 -0
  155. gapit-0.5.0/tests/data/typing/partial.fa +19 -0
  156. gapit-0.5.0/tests/data/typing/schemes/cholerae.gbk +153 -0
  157. gapit-0.5.0/tests/data/typing/schemes/cholerae.json +58 -0
  158. gapit-0.5.0/tests/data/typing/schemes/dec.fa +144 -0
  159. gapit-0.5.0/tests/data/typing/schemes/dec.json +125 -0
  160. gapit-0.5.0/tests/data/typing/schemes/doumith.fa +49 -0
  161. gapit-0.5.0/tests/data/typing/schemes/doumith.json +42 -0
  162. gapit-0.5.0/tests/data/typing/schemes/meningotype.fa +66 -0
  163. gapit-0.5.0/tests/data/typing/schemes/meningotype.json +60 -0
  164. gapit-0.5.0/tests/data/typing/schemes/shigella.fa +151 -0
  165. gapit-0.5.0/tests/data/typing/schemes/shigella.json +74 -0
  166. gapit-0.5.0/tests/data/typing/schemes/vp_ok.gbk +241 -0
  167. gapit-0.5.0/tests/data/typing/schemes/vp_ok.json +66 -0
  168. gapit-0.5.0/tests/data/typing/serotyping.fa +99 -0
  169. gapit-0.5.0/tests/data/typing/typing_markers_v1.json +22 -0
  170. gapit-0.5.0/tests/data/typing/typing_markers_v2.json +47 -0
  171. gapit-0.5.0/tests/data/typing/typing_serotyping_v2.json +71 -0
  172. gapit-0.5.0/tests/data/typing/vp_mixed.fa +39 -0
  173. gapit-0.5.0/tests/data/typing/vp_typed.fa +19 -0
  174. gapit-0.5.0/tests/golden/cluster_exact.json +72 -0
  175. gapit-0.5.0/tests/golden/cluster_exact.md +28 -0
  176. gapit-0.5.0/tests/golden/cluster_exact.tsv +2 -0
  177. gapit-0.5.0/tests/golden/cluster_fragmented.json +72 -0
  178. gapit-0.5.0/tests/golden/cluster_fragmented.md +28 -0
  179. gapit-0.5.0/tests/golden/cluster_fragmented.tsv +2 -0
  180. gapit-0.5.0/tests/golden/cluster_typing_ambiguous.json +133 -0
  181. gapit-0.5.0/tests/golden/cluster_typing_ambiguous.md +30 -0
  182. gapit-0.5.0/tests/golden/cluster_typing_ambiguous.tsv +2 -0
  183. gapit-0.5.0/tests/golden/cluster_typing_cm_exact.json +95 -0
  184. gapit-0.5.0/tests/golden/cluster_typing_cm_exact.md +30 -0
  185. gapit-0.5.0/tests/golden/cluster_typing_cm_exact.tsv +2 -0
  186. gapit-0.5.0/tests/golden/cluster_typing_exact.json +95 -0
  187. gapit-0.5.0/tests/golden/cluster_typing_exact.md +30 -0
  188. gapit-0.5.0/tests/golden/cluster_typing_exact.tsv +2 -0
  189. gapit-0.5.0/tests/golden/cluster_vc_inaba.json +95 -0
  190. gapit-0.5.0/tests/golden/cluster_vc_inaba.md +30 -0
  191. gapit-0.5.0/tests/golden/cluster_vc_inaba.tsv +2 -0
  192. gapit-0.5.0/tests/golden/ecoli_dec_typed.tsv +8 -0
  193. gapit-0.5.0/tests/golden/ecoli_dec_typing.tsv +5 -0
  194. gapit-0.5.0/tests/golden/fragments_merge.json +100 -0
  195. gapit-0.5.0/tests/golden/fragments_merge.md +30 -0
  196. gapit-0.5.0/tests/golden/fragments_merge.tsv +3 -0
  197. gapit-0.5.0/tests/golden/gene_dec_pic_astA.json +69 -0
  198. gapit-0.5.0/tests/golden/gene_dec_pic_astA.md +20 -0
  199. gapit-0.5.0/tests/golden/gene_doumith_4b.json +69 -0
  200. gapit-0.5.0/tests/golden/gene_doumith_4b.md +20 -0
  201. gapit-0.5.0/tests/golden/gene_serotyping_l4b.json +69 -0
  202. gapit-0.5.0/tests/golden/gene_serotyping_l4b.md +20 -0
  203. gapit-0.5.0/tests/golden/gene_serotyping_mixed.json +85 -0
  204. gapit-0.5.0/tests/golden/gene_serotyping_mixed.md +21 -0
  205. gapit-0.5.0/tests/golden/gene_serotyping_vp_typed.json +53 -0
  206. gapit-0.5.0/tests/golden/gene_serotyping_vp_typed.md +19 -0
  207. gapit-0.5.0/tests/golden/gene_shigella_mixed.json +101 -0
  208. gapit-0.5.0/tests/golden/gene_shigella_mixed.md +22 -0
  209. gapit-0.5.0/tests/golden/gene_typing_exact.json +85 -0
  210. gapit-0.5.0/tests/golden/gene_typing_exact.md +21 -0
  211. {gapit-0.3.1 → gapit-0.5.0}/tests/golden/reads_tinyamr.json +1 -1
  212. {gapit-0.3.1 → gapit-0.5.0}/tests/golden/reads_tinyamr.md +1 -1
  213. {gapit-0.3.1 → gapit-0.5.0}/tests/golden/screen_multi.json +1 -1
  214. {gapit-0.3.1 → gapit-0.5.0}/tests/golden/screen_multi.md +1 -3
  215. {gapit-0.3.1 → gapit-0.5.0}/tests/golden/summary_multi.json +1 -1
  216. {gapit-0.3.1 → gapit-0.5.0}/tests/golden/summary_multi.md +1 -1
  217. gapit-0.5.0/tests/golden/typing_markers.json +141 -0
  218. gapit-0.5.0/tests/golden/typing_markers.md +20 -0
  219. gapit-0.5.0/tests/golden/typing_markers.tsv +7 -0
  220. gapit-0.5.0/tests/golden/typing_serotyping.tsv +21 -0
  221. gapit-0.5.0/tests/parity/corpus/04_reverse.fa +42 -0
  222. gapit-0.5.0/tests/parity/corpus/05_threshold.fa +32 -0
  223. {gapit-0.3.1 → gapit-0.5.0}/tests/parity/make_corpus.py +52 -0
  224. {gapit-0.3.1 → gapit-0.5.0}/tests/parity/run_parity.py +5 -2
  225. gapit-0.5.0/tests/test_bundled.py +481 -0
  226. {gapit-0.3.1 → gapit-0.5.0}/tests/test_cli_aligner.py +1 -1
  227. gapit-0.5.0/tests/test_cli_bare_help.py +126 -0
  228. gapit-0.5.0/tests/test_cli_db_build_cluster.py +247 -0
  229. {gapit-0.3.1 → gapit-0.5.0}/tests/test_cli_db_fetch.py +143 -108
  230. {gapit-0.3.1 → gapit-0.5.0}/tests/test_cli_db_query.py +14 -46
  231. gapit-0.5.0/tests/test_cli_fragments.py +190 -0
  232. {gapit-0.3.1 → gapit-0.5.0}/tests/test_cli_reads.py +36 -3
  233. {gapit-0.3.1 → gapit-0.5.0}/tests/test_cli_reads2.py +1 -1
  234. {gapit-0.3.1 → gapit-0.5.0}/tests/test_cli_screen.py +209 -2
  235. {gapit-0.3.1 → gapit-0.5.0}/tests/test_cli_setupdb.py +50 -17
  236. gapit-0.5.0/tests/test_cli_short_options.py +388 -0
  237. {gapit-0.3.1 → gapit-0.5.0}/tests/test_cli_summary.py +5 -3
  238. gapit-0.5.0/tests/test_cluster_calibration.py +152 -0
  239. gapit-0.5.0/tests/test_cluster_db.py +125 -0
  240. gapit-0.5.0/tests/test_cluster_math.py +141 -0
  241. gapit-0.5.0/tests/test_cluster_screen.py +574 -0
  242. gapit-0.5.0/tests/test_cluster_typing.py +379 -0
  243. gapit-0.5.0/tests/test_db_list_extras.py +169 -0
  244. {gapit-0.3.1 → gapit-0.5.0}/tests/test_error_envelope.py +15 -2
  245. gapit-0.5.0/tests/test_fragments.py +293 -0
  246. {gapit-0.3.1 → gapit-0.5.0}/tests/test_gapit_db_e2e.py +2 -1
  247. gapit-0.5.0/tests/test_gbfeatures.py +133 -0
  248. gapit-0.5.0/tests/test_gene_typing.py +530 -0
  249. gapit-0.5.0/tests/test_gene_typing2.py +389 -0
  250. gapit-0.5.0/tests/test_gffparse.py +113 -0
  251. {gapit-0.3.1 → gapit-0.5.0}/tests/test_json_format.py +7 -1
  252. {gapit-0.3.1 → gapit-0.5.0}/tests/test_mcp.py +50 -1
  253. {gapit-0.3.1 → gapit-0.5.0}/tests/test_mcp_db_tools.py +67 -48
  254. {gapit-0.3.1 → gapit-0.5.0}/tests/test_mcp_reads.py +17 -2
  255. {gapit-0.3.1 → gapit-0.5.0}/tests/test_md_format.py +1 -4
  256. gapit-0.5.0/tests/test_provider_kaptive.py +236 -0
  257. {gapit-0.3.1 → gapit-0.5.0}/tests/test_providers_common.py +27 -0
  258. {gapit-0.3.1 → gapit-0.5.0}/tests/test_reads2_homologs.py +1 -1
  259. {gapit-0.3.1 → gapit-0.5.0}/tests/test_reads2_model.py +1 -1
  260. gapit-0.5.0/tests/test_streaming_chunks.py +522 -0
  261. gapit-0.5.0/tests/test_typing_command.py +654 -0
  262. gapit-0.5.0/tests/test_typing_engine.py +679 -0
  263. gapit-0.5.0/tests/test_typing_models.py +678 -0
  264. gapit-0.5.0/tests/test_typing_schemes.py +663 -0
  265. gapit-0.5.0/tests/test_typing_schemes_cluster.py +320 -0
  266. gapit-0.5.0/tests/test_typing_stage2.py +509 -0
  267. gapit-0.3.1/.github/workflows/snapshot-refresh.yml +0 -129
  268. gapit-0.3.1/CHANGELOG.md +0 -148
  269. gapit-0.3.1/docs/databases.md +0 -529
  270. gapit-0.3.1/docs/screen.md +0 -205
  271. gapit-0.3.1/mkdocs.yml +0 -36
  272. gapit-0.3.1/recipe/meta.yaml +0 -74
  273. gapit-0.3.1/src/gapit/cmd_db.py +0 -113
  274. gapit-0.3.1/src/gapit/cmd_db_build.py +0 -72
  275. gapit-0.3.1/src/gapit/cmd_screen.py +0 -214
  276. gapit-0.3.1/src/gapit/data/snapshots/card.tar.gz +0 -0
  277. gapit-0.3.1/src/gapit/data/snapshots/vfdb.tar.gz +0 -0
  278. gapit-0.3.1/src/gapit/db_ops.py +0 -128
  279. gapit-0.3.1/src/gapit/dispatch.py +0 -31
  280. gapit-0.3.1/src/gapit/formats/tsv.py +0 -45
  281. gapit-0.3.1/src/gapit/hits.py +0 -107
  282. gapit-0.3.1/src/gapit/providers/__init__.py +0 -39
  283. gapit-0.3.1/src/gapit/providers/snapshots.py +0 -119
  284. gapit-0.3.1/src/gapit/screening.py +0 -145
  285. gapit-0.3.1/tests/test_snapshots.py +0 -204
  286. {gapit-0.3.1 → gapit-0.5.0}/.gitattributes +0 -0
  287. {gapit-0.3.1 → gapit-0.5.0}/.github/workflows/ci.yml +0 -0
  288. {gapit-0.3.1 → gapit-0.5.0}/.github/workflows/docs.yml +0 -0
  289. {gapit-0.3.1 → gapit-0.5.0}/.github/workflows/release.yml +0 -0
  290. {gapit-0.3.1 → gapit-0.5.0}/.gitignore +0 -0
  291. {gapit-0.3.1 → gapit-0.5.0}/LICENSE +0 -0
  292. {gapit-0.3.1 → gapit-0.5.0}/docs/custom-db.md +0 -0
  293. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/config.py +0 -0
  294. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/dbcodec.py +0 -0
  295. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/errors.py +0 -0
  296. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/fasta.py +0 -0
  297. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/formats/__init__.py +0 -0
  298. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/formats/summary.py +0 -0
  299. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/mcp.py +0 -0
  300. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/minimap.py +0 -0
  301. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/proctools.py +0 -0
  302. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/py.typed +0 -0
  303. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/reads.py +0 -0
  304. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/seqconvert.py +0 -0
  305. {gapit-0.3.1 → gapit-0.5.0}/src/gapit/summary.py +0 -0
  306. {gapit-0.3.1 → gapit-0.5.0}/tests/data/contigs/full.fa +0 -0
  307. {gapit-0.3.1 → gapit-0.5.0}/tests/data/contigs/gap.fa +0 -0
  308. {gapit-0.3.1 → gapit-0.5.0}/tests/data/contigs/none.fa +0 -0
  309. {gapit-0.3.1 → gapit-0.5.0}/tests/data/contigs/partial.fa +0 -0
  310. {gapit-0.3.1 → gapit-0.5.0}/tests/data/contigs/sort.fa +0 -0
  311. {gapit-0.3.1 → gapit-0.5.0}/tests/data/convert/sample.embl +0 -0
  312. {gapit-0.3.1 → gapit-0.5.0}/tests/data/convert/sample.embl.bz2 +0 -0
  313. {gapit-0.3.1 → gapit-0.5.0}/tests/data/convert/sample.fa +0 -0
  314. {gapit-0.3.1 → gapit-0.5.0}/tests/data/convert/sample.fa.gz +0 -0
  315. {gapit-0.3.1 → gapit-0.5.0}/tests/data/convert/sample.fq +0 -0
  316. {gapit-0.3.1 → gapit-0.5.0}/tests/data/convert/sample.gbk +0 -0
  317. {gapit-0.3.1 → gapit-0.5.0}/tests/data/convert/sample.gbk.gz +0 -0
  318. {gapit-0.3.1 → gapit-0.5.0}/tests/data/db/tinyamr/sequences +0 -0
  319. {gapit-0.3.1 → gapit-0.5.0}/tests/data/providers/argannot/ARG-ANNOT_NT_V6_July2019.txt +0 -0
  320. {gapit-0.3.1 → gapit-0.5.0}/tests/data/providers/bacmet2/BacMet2_EXP_database.fasta +0 -0
  321. {gapit-0.3.1 → gapit-0.5.0}/tests/data/providers/card/card.json +0 -0
  322. {gapit-0.3.1 → gapit-0.5.0}/tests/data/providers/ecoh/EcOH.fasta +0 -0
  323. {gapit-0.3.1 → gapit-0.5.0}/tests/data/providers/ecoli_vf/repaired_ecoli_vfs_shortnames.ffn +0 -0
  324. {gapit-0.3.1 → gapit-0.5.0}/tests/data/providers/megares/megares_drugs_demo.fasta +0 -0
  325. {gapit-0.3.1 → gapit-0.5.0}/tests/data/providers/ncbi/AMR_CDS.fa +0 -0
  326. {gapit-0.3.1 → gapit-0.5.0}/tests/data/providers/ncbi/ReferenceGeneCatalog.txt +0 -0
  327. {gapit-0.3.1 → gapit-0.5.0}/tests/data/providers/plasmidfinder/plasmids_a.fsa +0 -0
  328. {gapit-0.3.1 → gapit-0.5.0}/tests/data/providers/plasmidfinder/plasmids_b.fsa +0 -0
  329. {gapit-0.3.1 → gapit-0.5.0}/tests/data/providers/resfinder/aminoglycoside.fsa +0 -0
  330. {gapit-0.3.1 → gapit-0.5.0}/tests/data/providers/resfinder/beta-lactam.fsa +0 -0
  331. {gapit-0.3.1 → gapit-0.5.0}/tests/data/providers/resfinder/phenotypes.txt +0 -0
  332. {gapit-0.3.1 → gapit-0.5.0}/tests/data/providers/upec_expec_vf/UPEC_ExPEC_VF.tsv +0 -0
  333. {gapit-0.3.1 → gapit-0.5.0}/tests/data/providers/vfdb/VFDB_setA_nt.fas +0 -0
  334. {gapit-0.3.1 → gapit-0.5.0}/tests/data/providers/victors/gen_downloads.php +0 -0
  335. {gapit-0.3.1 → gapit-0.5.0}/tests/data/providers/victors/gen_downloads_protein.php +0 -0
  336. {gapit-0.3.1 → gapit-0.5.0}/tests/data/reads/bla_partial.fq +0 -0
  337. {gapit-0.3.1 → gapit-0.5.0}/tests/data/reads/junk.fq +0 -0
  338. {gapit-0.3.1 → gapit-0.5.0}/tests/data/reads/suly_partial.fq +0 -0
  339. {gapit-0.3.1 → gapit-0.5.0}/tests/data/reads/tetx_R1.fq +0 -0
  340. {gapit-0.3.1 → gapit-0.5.0}/tests/data/reads/tetx_R2.fq +0 -0
  341. {gapit-0.3.1 → gapit-0.5.0}/tests/data/reads/tetx_full.fq +0 -0
  342. {gapit-0.3.1 → gapit-0.5.0}/tests/data/reads/tetx_full.fq.gz +0 -0
  343. {gapit-0.3.1 → gapit-0.5.0}/tests/data/reads/tetx_lane1.fq +0 -0
  344. {gapit-0.3.1 → gapit-0.5.0}/tests/data/reads/tetx_lane2.fq +0 -0
  345. {gapit-0.3.1 → gapit-0.5.0}/tests/data/reads/tetx_pe1_R1.fq +0 -0
  346. {gapit-0.3.1 → gapit-0.5.0}/tests/data/reads/tetx_pe1_R2.fq +0 -0
  347. {gapit-0.3.1 → gapit-0.5.0}/tests/data/reads/tetx_pe2_R1.fq +0 -0
  348. {gapit-0.3.1 → gapit-0.5.0}/tests/data/reads/tetx_pe2_R2.fq +0 -0
  349. {gapit-0.3.1 → gapit-0.5.0}/tests/data/reads2/ont_homologs.fq +0 -0
  350. {gapit-0.3.1 → gapit-0.5.0}/tests/data/reads2/sr_homologs.fq +0 -0
  351. {gapit-0.3.1 → gapit-0.5.0}/tests/data/reads2_db/homologs/sequences +0 -0
  352. {gapit-0.3.1 → gapit-0.5.0}/tests/data/reads_db/tinyreads/sequences +0 -0
  353. {gapit-0.3.1 → gapit-0.5.0}/tests/data/summary/empty.tsv +0 -0
  354. {gapit-0.3.1 → gapit-0.5.0}/tests/data/summary/multi_sample.tsv +0 -0
  355. {gapit-0.3.1 → gapit-0.5.0}/tests/data/summary/sample_a.csv +0 -0
  356. {gapit-0.3.1 → gapit-0.5.0}/tests/data/summary/sample_a.tsv +0 -0
  357. {gapit-0.3.1 → gapit-0.5.0}/tests/data/summary/sample_b.csv +0 -0
  358. {gapit-0.3.1 → gapit-0.5.0}/tests/data/summary/sample_b.tsv +0 -0
  359. {gapit-0.3.1 → gapit-0.5.0}/tests/golden/summary_dutch.tsv +0 -0
  360. {gapit-0.3.1 → gapit-0.5.0}/tests/golden/summary_multi.csv +0 -0
  361. {gapit-0.3.1 → gapit-0.5.0}/tests/golden/summary_multi.tsv +0 -0
  362. {gapit-0.3.1 → gapit-0.5.0}/tests/golden/tinyamr_multi_nopath.csv +0 -0
  363. {gapit-0.3.1 → gapit-0.5.0}/tests/golden/tinyamr_multi_nopath.tsv +0 -0
  364. {gapit-0.3.1 → gapit-0.5.0}/tests/parity/corpus/01_exact_and_junk.fa +0 -0
  365. {gapit-0.3.1 → gapit-0.5.0}/tests/parity/corpus/02_mutated.fa +0 -0
  366. {gapit-0.3.1 → gapit-0.5.0}/tests/parity/corpus/03_truncated.fa +0 -0
  367. {gapit-0.3.1 → gapit-0.5.0}/tests/parity/run_summary_parity.py +0 -0
  368. {gapit-0.3.1 → gapit-0.5.0}/tests/test_blast_parse.py +0 -0
  369. {gapit-0.3.1 → gapit-0.5.0}/tests/test_blast_pipeline.py +0 -0
  370. {gapit-0.3.1 → gapit-0.5.0}/tests/test_cli_completion.py +0 -0
  371. {gapit-0.3.1 → gapit-0.5.0}/tests/test_cli_db_build.py +0 -0
  372. {gapit-0.3.1 → gapit-0.5.0}/tests/test_cli_schema.py +0 -0
  373. {gapit-0.3.1 → gapit-0.5.0}/tests/test_cli_screen_jobs.py +0 -0
  374. {gapit-0.3.1 → gapit-0.5.0}/tests/test_config.py +0 -0
  375. {gapit-0.3.1 → gapit-0.5.0}/tests/test_db.py +0 -0
  376. {gapit-0.3.1 → gapit-0.5.0}/tests/test_db_fetch.py +0 -0
  377. {gapit-0.3.1 → gapit-0.5.0}/tests/test_db_headers.py +0 -0
  378. {gapit-0.3.1 → gapit-0.5.0}/tests/test_dbbuild.py +0 -0
  379. {gapit-0.3.1 → gapit-0.5.0}/tests/test_dbcodec.py +0 -0
  380. {gapit-0.3.1 → gapit-0.5.0}/tests/test_fasta.py +0 -0
  381. {gapit-0.3.1 → gapit-0.5.0}/tests/test_hits.py +0 -0
  382. {gapit-0.3.1 → gapit-0.5.0}/tests/test_mcp_protocol.py +0 -0
  383. {gapit-0.3.1 → gapit-0.5.0}/tests/test_minimap.py +0 -0
  384. {gapit-0.3.1 → gapit-0.5.0}/tests/test_mol_type.py +0 -0
  385. {gapit-0.3.1 → gapit-0.5.0}/tests/test_oversubscription.py +0 -0
  386. {gapit-0.3.1 → gapit-0.5.0}/tests/test_paf.py +0 -0
  387. {gapit-0.3.1 → gapit-0.5.0}/tests/test_paf_identity.py +0 -0
  388. {gapit-0.3.1 → gapit-0.5.0}/tests/test_provider_argannot.py +0 -0
  389. {gapit-0.3.1 → gapit-0.5.0}/tests/test_provider_bacmet2.py +0 -0
  390. {gapit-0.3.1 → gapit-0.5.0}/tests/test_provider_card.py +0 -0
  391. {gapit-0.3.1 → gapit-0.5.0}/tests/test_provider_ecoh.py +0 -0
  392. {gapit-0.3.1 → gapit-0.5.0}/tests/test_provider_ecoli_vf.py +0 -0
  393. {gapit-0.3.1 → gapit-0.5.0}/tests/test_provider_megares.py +0 -0
  394. {gapit-0.3.1 → gapit-0.5.0}/tests/test_provider_ncbi.py +0 -0
  395. {gapit-0.3.1 → gapit-0.5.0}/tests/test_provider_plasmidfinder.py +0 -0
  396. {gapit-0.3.1 → gapit-0.5.0}/tests/test_provider_resfinder.py +0 -0
  397. {gapit-0.3.1 → gapit-0.5.0}/tests/test_provider_upec_expec_vf.py +0 -0
  398. {gapit-0.3.1 → gapit-0.5.0}/tests/test_provider_vfdb.py +0 -0
  399. {gapit-0.3.1 → gapit-0.5.0}/tests/test_provider_victors.py +0 -0
  400. {gapit-0.3.1 → gapit-0.5.0}/tests/test_reads_aggregate.py +0 -0
  401. {gapit-0.3.1 → gapit-0.5.0}/tests/test_reads_integration.py +0 -0
  402. {gapit-0.3.1 → gapit-0.5.0}/tests/test_reads_interval_union.py +0 -0
  403. {gapit-0.3.1 → gapit-0.5.0}/tests/test_reads_streaming.py +0 -0
  404. {gapit-0.3.1 → gapit-0.5.0}/tests/test_records.py +0 -0
  405. {gapit-0.3.1 → gapit-0.5.0}/tests/test_report.py +0 -0
  406. {gapit-0.3.1 → gapit-0.5.0}/tests/test_screen_integration.py +0 -0
  407. {gapit-0.3.1 → gapit-0.5.0}/tests/test_screening_reads_unit.py +0 -0
  408. {gapit-0.3.1 → gapit-0.5.0}/tests/test_seqconvert.py +0 -0
  409. {gapit-0.3.1 → gapit-0.5.0}/tests/test_seqconvert_differential.py +0 -0
  410. {gapit-0.3.1 → gapit-0.5.0}/tests/test_summary.py +0 -0
  411. {gapit-0.3.1 → gapit-0.5.0}/tests/test_summary_formats.py +0 -0
  412. {gapit-0.3.1 → gapit-0.5.0}/tests/test_tsv.py +0 -0
  413. {gapit-0.3.1 → gapit-0.5.0}/tests/test_version.py +0 -0
@@ -1,7 +1,7 @@
1
1
  # AGENTS.md — gapit
2
2
 
3
3
  > Python reimplementation of [abricate](https://github.com/tseemann/abricate): mass screening of
4
- > contigs for antimicrobial resistance and virulence genes. **Agent-first**: every output is
4
+ > contigs and reads for known genes. **Agent-first**: every output is
5
5
  > machine-readable (JSON / Markdown) by design, not as an afterthought.
6
6
 
7
7
  ## 1. Mission
@@ -62,7 +62,7 @@ gapit/
62
62
  │ ├── __init__.py
63
63
  │ ├── cli.py # typer entrypoint: screen / summary / db / setupdb / schema / mcp
64
64
  │ ├── config.py # datadir resolution, defaults, env vars
65
- │ ├── dispatch.py # shared CLI dispatch (error envelope → exit codes) + --datadir option
65
+ │ ├── dispatch.py # shared CLI dispatch (error envelope → exit codes) + --datadir option + --output target
66
66
  │ ├── proctools.py # external-tool plumbing: argv subprocess runner + stderr notes
67
67
  │ ├── fasta.py # streaming FASTA reader + shared gz/bz2 text opener
68
68
  │ ├── seqconvert.py # native input normalization: fa/fq/gbk/embl (±gz/bz2) → FASTA
@@ -70,21 +70,40 @@ gapit/
70
70
  │ ├── dbcodec.py # gapit/v1 tagged-header codec (percent-encoded ids)
71
71
  │ ├── records.py # records.jsonl truth store + gapit.manifest/1 provenance
72
72
  │ ├── dbbuild.py # deterministic native-db build pipeline with self-check
73
- │ ├── db_ops.py # db use-cases: provider fetch + list (shared CLI + MCP; no typer)
73
+ │ ├── clusterbuild.py # cluster-db build pipeline: GBK/GFF → locus FASTA + features.json + typing copy
74
+ │ ├── cluster.py # cluster-screening engine core: minimap2 asm20 → per-locus/per-gene calls
75
+ │ ├── cluster_math.py # cs-walk → union coverage/identity math + verdicts (pure functions)
76
+ │ ├── db_ops.py # db use-cases: fetch + list (shared CLI + MCP; no typer)
74
77
  │ ├── db_query_ops.py # db use-cases: search + outdated over installed DBs (shared CLI + MCP)
75
- │ ├── db_build_ops.py # db use-case: custom FASTA+TSV → native db build (shared CLI + MCP)
78
+ │ ├── db_build_ops.py # db use-case: custom FASTA+TSV → gene db, GBK/GFF → cluster db (shared CLI + MCP)
79
+ │ ├── gbfeatures.py # GenBank FEATURES/ORIGIN parser → LocusFeatures/GeneFeature + gapit.features/1
80
+ │ ├── gffparse.py # GFF3 parser (embedded ##FASTA or sidecar) → the same locus/gene models
81
+ │ ├── typing_models.py # gapit.typing schema (rules + named schemes; /1 degrades to one default scheme)
82
+ │ ├── typing_rules.py # gapit.typing rule models (weighted_genes/exact_set/cluster_match/learned_linear) + reference checks
83
+ │ ├── typing_decide.py # typing decision layer: ranking, control-gene gate, unique-group mixed override
84
+ │ ├── typing_results.py # typing evaluation-result models (PhenotypeDetail, SchemeCall)
85
+ │ ├── typing_engine.py # typing evaluation, cluster path: rule scoring → phenotype call + breakdown
86
+ │ ├── typing_gene.py # typing evaluation, gene path (DEC markers): hits → per-scheme report phenotypes
87
+ │ ├── bundled.py # bundled databases: discovery + materialize-into-datadir (public-domain panels)
76
88
  │ ├── blast.py # blastn invocation + tabular output parsing
77
89
  │ ├── hits.py # Hit model, identity/coverage computation, filtering, dedup
90
+ │ ├── fragments.py # opt-in --merge-fragments cross-contig gene-fragment merging
78
91
  │ ├── minimap.py # COVERAGE_MAP construction (exact abricate arithmetic)
79
92
  │ ├── minimap2_run.py # minimap2 invocation layer for reads mode (streaming PAF, --cs/NM tags)
80
93
  │ ├── paf.py # PAF row parsing + interval arithmetic (minimap2 output boundary)
81
94
  │ ├── report.py # Report model: the canonical in-memory result
82
- │ ├── screening.py # blastn screen use-case + shared engine helpers (OutputFormat, AlignerEnum)
95
+ │ ├── engines.py # shared OutputFormat / AlignerEnum (leaf module for the three engines)
96
+ │ ├── screening.py # blastn screen use-case + the shared run_screen dispatcher
97
+ │ ├── screening_cluster.py # cluster screen use-case: kind guards, typing wiring, rendering
83
98
  │ ├── screening_reads.py # minimap2 use-cases: --r1/--r2 reads + --aligner minimap2 assemblies
84
- │ ├── reads.py # FASTQ mode: minimap2 PAF parsing, coverage breadth/depth, presence
99
+ │ ├── typing_input.py # `gapit typing` input: screen TSV/CSV → per-FILE folded GeneCalls
100
+ │ ├── typing_ops.py # `gapit typing` use-case: resolve db, run the engine, render
101
+ │ ├── reads.py # FASTQ mode: minimap2 PAF parsing, coverage breadth/depth, presence
85
102
  │ ├── summary.py # summary core: parse report tables into a gene matrix
86
103
  │ ├── cmd_screen.py # `gapit screen` CLI (registered from cli.py)
104
+ │ ├── cmd_screen_reads_args.py # reads-mode CLI arg rules (comma split + flag rejects)
87
105
  │ ├── cmd_summary.py # `gapit summary` CLI (registered from cli.py)
106
+ │ ├── cmd_typing.py # `gapit typing` CLI (registered from cli.py)
88
107
  │ ├── cmd_db.py # `gapit db` command group (fetch | list; registers the subcommands)
89
108
  │ ├── cmd_db_install.py # `gapit db install`: SHA256-verified local-file install
90
109
  │ ├── cmd_db_build.py # `gapit db build` CLI (custom FASTA → native db)
@@ -95,14 +114,19 @@ gapit/
95
114
  │ ├── mcp_schemas.py # MCP tools/list declarations (names, descriptions, inputSchemas)
96
115
  │ ├── errors.py # typed errors + JSON error envelope
97
116
  │ ├── formats/
98
- │ │ ├── tsv.py # abricate-compatible TSV/CSV
117
+ │ │ ├── tsv.py # abricate-compatible TSV/CSV (phenotype-free in every typing version)
99
118
  │ │ ├── json.py # versioned JSON (gapit.report/1 et al.)
119
+ │ │ ├── reads_json.py # versioned JSON (gapit.reads/1, gapit.reads/2)
100
120
  │ │ ├── md.py # Markdown (human + agent readable, YAML frontmatter)
121
+ │ │ ├── cluster.py # gapit.cluster/1 models + JSON/TSV renderers (typed variant)
122
+ │ │ ├── cluster_md.py # gapit.cluster/1 Markdown renderer (Phenotype column when typed)
123
+ │ │ ├── typing_result.py # gapit.typing_result/1 models + TSV/JSON/MD renderers
101
124
  │ │ ├── schemas.py # registered output models behind `gapit schema`
102
125
  │ │ └── summary.py # summary matrix renderers (TSV/CSV/JSON/MD)
103
- │ ├── providers/ # 12 DB providers + common.py helpers + snapshots.py loader
104
- │ ├── data/snapshots/ # bundled card + vfdb snapshot archives (.tar.gz)
126
+ │ ├── providers/ # 19 database provider modules (12 gene + 7 kaptive cluster) + cluster_common.py + common.py
105
127
  │ └── py.typed
128
+ ├── scripts/
129
+ │ └── cluster_calibration.py # developer calibration harness for typed cluster dbs
106
130
  └── tests/
107
131
  ├── data/ # tiny synthetic db + contigs + reads (fast, offline)
108
132
  ├── golden/ # expected outputs incl. abricate reference TSVs
@@ -131,7 +155,8 @@ This is what distinguishes gapit from abricate. Treat it as a public API.
131
155
 
132
156
  - **Formats**: `--format tsv|csv|json|md` (default `tsv` for abricate compatibility).
133
157
  - **JSON**: top-level `"schema": "gapit.report/1"`; schema introspectable via
134
- `gapit schema report | reads | reads2 | summary | list | error | version`. Keys are snake_case,
158
+ `gapit schema report | reads | reads2 | summary | list | error | version` (plus
159
+ `cluster | features | typing | typing_result`). Keys are snake_case,
135
160
  units explicit (`identity_pct`, `coverage_pct`). Semver the schema; never rename or
136
161
  retype a field in a minor bump.
137
162
  - **Markdown**: YAML frontmatter (tool version, db, params, ISO-8601 UTC timestamp) + tables a
@@ -139,14 +164,30 @@ This is what distinguishes gapit from abricate. Treat it as a public API.
139
164
  - **Errors**: failures print a JSON envelope to stderr
140
165
  `{"schema": "gapit.error/1", "code": "...", "message": "...", "context": {...}}` and exit with a
141
166
  documented non-zero code (2 = usage, 3 = missing dependency, 4 = db error, 5 = input error).
167
+ - **Typing** `[gapit-extension]`: two-stage designation — `gapit screen -o result.tsv --db NAME`
168
+ detects genes (screen output is phenotype-free; typed and untyped gene dbs screen
169
+ byte-identically), then `gapit typing result.tsv [-D|-f|-o|-q]` designates from the screen
170
+ table (`gapit.typing_result/1`; cluster dbs refuse — their typing rides the screen).
171
+ No typing MCP tool yet (future work).
142
172
  - **DB acquisition** `[gapit-extension]`: `gapit db fetch|list|search|outdated|build|install` —
143
- provider fetch (bundled card/vfdb snapshots install offline; `--from-source` forces upstream),
144
- provider listing, records.jsonl gene search, staleness report, custom FASTA→native-db build,
145
- and SHA256-verified local-file install.
173
+ database fetch from the provider catalog (every provider downloads from upstream at fetch
174
+ time — nothing catalog-side is bundled inside the wheel beyond the sanctioned exceptions,
175
+ a license-compliance requirement: CARD/VFDB terms are non-commercial and Kaptive is GPL,
176
+ so none of those may ride an MIT distribution; the sanctioned exceptions are the five
177
+ content-provenance-audited bundles under `src/gapit/data/dbs/` — the public-domain
178
+ `ecoli_dec` panel plus four permissively licensed provider snapshots (`ncbi` public
179
+ domain, `resfinder` Apache-2.0, `ecoh` BSD-3-Clause, `upec_expec_vf` MIT; GPL/NC content
180
+ is never bundled) — materialized into the datadir on first use via `bundled.py`, with
181
+ `db fetch <name>` still the fresh-upstream refresh path),
182
+ database listing,
183
+ records.jsonl gene search, staleness
184
+ report, custom FASTA→native-db build, GBK/GFF→cluster-db build (`--typing` installs a
185
+ validated `gapit.typing/1` or `/2` spec on either kind), the four download-on-fetch kaptive cluster providers
186
+ (GPL content, never bundled), and SHA256-verified local-file install.
146
187
  - **MCP** `[gapit-extension]`: `gapit mcp` / `gapit-mcp` stdio server exposing nine tools:
147
188
  read-only `screen` (incl. `aligner minimap2` assembly survey), `screen_reads` (FASTQ via
148
189
  minimap2), `summary`, `schema`, `db_list`, `db_search`, `db_outdated`, plus the datadir-mutating
149
- `db_fetch` (installs provider databases; may download) and `db_build` (writes a custom db);
190
+ `db_fetch` (installs databases from the provider catalog; may download) and `db_build` (writes a custom db);
150
191
  tool failures carry the `gapit.error/1` envelope.
151
192
  - **stdout purity**: data on stdout, diagnostics on stderr, always. `--quiet` only affects stderr.
152
193
  - **Self-description**: `gapit --version --json`, `gapit db list --json`, `gapit schema` — an agent
@@ -175,7 +216,9 @@ This is what distinguishes gapit from abricate. Treat it as a public API.
175
216
  query contigs against one db → 15-field
176
217
  tabular hits → filter by identity / coverage thresholds → **dedup hits sharing identical
177
218
  `(contig, qstart, qend)`** (first/best BLAST row wins) → one TSV row per surviving hit.
178
- abricate does **not** merge overlapping intervals — do not "improve" this on the default path.
219
+ abricate does **not** merge overlapping intervals — do not "improve" this on the default path (the
220
+ opt-in `--merge-fragments` cross-contig extension is the one sanctioned exception:
221
+ `fragments.py`).
179
222
  - Key computed fields: `%COVERAGE = 100*(length-gaps)/slen` (filtered unrounded, displayed
180
223
  `%.2f`), `%IDENTITY` (BLAST pident, never post-filtered), `COVERAGE_MAP` (15-char minimap),
181
224
  `GAPS`. Exact formulas, the dedup rule, and the minimap arithmetic live in `SPEC.md` — when
@@ -0,0 +1,473 @@
1
+ # Changelog
2
+
3
+ All notable changes to gapit are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this
6
+ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.5.0] - 2026-10-02
9
+
10
+ ### Breaking
11
+
12
+ - **`--format md` now streams per file, and the Markdown layout lost its run totals (MD goldens
13
+ and docs regenerated).** The Markdown frontmatter was dynamic — `files:`/`hits:` counts (and
14
+ the cluster report's all-files summary table) only exist once every file has screened, which
15
+ forced the renderer to buffer the whole document until the end. The frontmatter is now STATIC
16
+ metadata only (`schema`, `tool`, `created_at`, `db`, thresholds — everything knowable before
17
+ file 1): it prints first and each file's section (heading, table, merge-fragment lines; on
18
+ cluster databases the file's own summary row plus its gene table, replacing the global summary
19
+ table) prints the moment that file completes — head-of-line in input order under `--jobs`,
20
+ exactly like the tsv rows, with `--output` flushing per chunk. Run totals now live only in the
21
+ JSON document (`gapit.report/1` `files[]`/`hits`, `gapit.cluster/1`), which stays a single
22
+ buffered document by design. Update any parser that read `files:`/`hits:` from Markdown
23
+ frontmatter or expected the cluster summary table above the sections; per-file content is
24
+ unchanged byte-for-byte. Reads-mode Markdown (one document per run by construction) and
25
+ `gapit typing`'s Markdown are unchanged.
26
+
27
+ - **`gapit screen --db` is now required (no default).** The silent `ncbi` default could
28
+ auto-materialize a bundled 8.4k-record database as a hidden side effect of a bare
29
+ `gapit screen contigs.fa`; a screen now refuses to run (typer usage error, exit 2) until
30
+ `--db NAME` is given explicitly. The MCP `screen`/`screen_reads` tools mirror the change:
31
+ `db` moved into each inputSchema's `required` array (default removed), and an absent
32
+ `db` returns the `gapit.error/1` USAGE_ERROR envelope. Update any invocation that relied
33
+ on the default.
34
+ - **`gapit screen` no longer embeds phenotypes — designation moved to the new `gapit typing`
35
+ command (one-cycle revert; the embedded surfaces never released).** Screening a typed gene
36
+ database is now pure gene detection, byte-identical to screening an untyped one in every
37
+ format: the earlier-this-cycle `PHENOTYPE` column on the report TSV/CSV, the
38
+ `files[].phenotypes` object of `gapit.report/1`, and the Markdown phenotype lines are all
39
+ gone (the typing engine itself — rules, schemes, gates, compose — is unchanged, and
40
+ `typing.json` still ships with databases). The reads-mode guard that rejected typed gene
41
+ dbs (`gene-path typing is contig-mode only`) is gone with it: `--r1/--r2` and
42
+ `--aligner minimap2` screen typed gene databases like any other. The cluster path is
43
+ untouched — typed cluster databases keep their integrated designation (the
44
+ `gapit.cluster/1` phenotype block and the typed-only TSV `PHENOTYPE` column). The MCP
45
+ `screen` tool returns the pure report on typed gene dbs (a typing MCP tool is future
46
+ work). If you consumed `files[].phenotypes` from pre-release builds, switch to
47
+ `gapit typing` (below).
48
+
49
+ ### Added
50
+
51
+ - **`gapit typing RESULT.tsv [RESULT2.tsv ...]` — designation from screen results (the
52
+ rightsholder's two-stage CLI design).** Stage 1: `gapit screen -o result.tsv --db NAME`
53
+ detects genes; stage 2: `gapit typing result.tsv` reads the gapit/abricate screen table
54
+ (TSV or auto-detected CSV, several tables merge by their FILE column), resolves NAME from
55
+ the rows' shared `DATABASE` column under `--datadir` (bundled databases still materialize
56
+ on first use), folds every `(FILE, GENE)` to its best row by `(%IDENTITY, %COVERAGE)`
57
+ (first row wins ties — the same per-gene fold the report hits received), and runs the
58
+ existing typing engine over each FILE's genes. Output: default TSV with columns `FILE`,
59
+ `SCHEME`, `PHENOTYPE`, `CONFIDENCE`, `SCORE`, `RUNNER_UP`, `NOTES` (ambiguous calls
60
+ render `-` and carry the candidate pair in NOTES; streamed per input file), `--format
61
+ json` as the new versioned **`gapit.typing_result/1`** document (`{schema, tool,
62
+ created_at, source, db, files[].phenotypes}` — full score breakdowns, introspectable via
63
+ `gapit schema typing_result`, also registered in the MCP `schema` tool), and
64
+ `--format md` (frontmatter + the same seven-column table); `-o FILE`/`-q` behave as
65
+ everywhere. Typed errors: mixed `DATABASE` values `DATABASE_MISMATCH`, a table with no
66
+ data rows `TYPING_NO_DATA` (a screened-no-hits file has no rows — the database is only
67
+ knowable from them), a database without a `typing.json` `TYPING_NO_SCHEME`, and a cluster
68
+ database `TYPING_CLUSTER_DB` (its typing is integrated in `gapit screen`). Equivalence is
69
+ locked end to end: the DEC matrix, serotyping fixtures, and the bundled `ecoli_dec`
70
+ assert the command's calls equal the calls the inline engine produced before the move,
71
+ with new goldens (`typing_markers.*`, `typing_serotyping.tsv`, `ecoli_dec_typing.tsv`).
72
+ The table also arrives on stdin: `gapit screen 1.fna --db NAME | gapit typing` types the
73
+ piped output with no file arguments (stdin must not be a terminal — a bare invocation at
74
+ a terminal still prints help), the explicit `gapit typing -` marker reads stdin even
75
+ under a terminal (until EOF), mixing `-` with file arguments is a usage error (v1:
76
+ either stdin or files), a piped table's JSON `source` renders as `["-"]`, and an empty
77
+ pipe is the usual `TYPING_NO_DATA` naming `-`. The three delivery forms (file, `-`,
78
+ pipe) are locked byte-identical.
79
+ - **Short single-dash aliases for every CLI option (rightsholder UX directive).** Each option
80
+ on every command now pairs a short form with its long form — `--help`/`-h` style, e.g.
81
+ `gapit screen contigs.fa -d ncbi -f json` for `--db ncbi --format json`. Letters follow the
82
+ first-letter convention with uppercase on collision (`--db`/`-d` vs `--datadir`/`-D`;
83
+ `--minid`/`-i` vs `--min-identity`/`-I`), mnemonics where the first letter is taken
84
+ (`--min-gene-cov`/`-g`, `--read-type`/`-x`, `--r1`/`-1`), and `-v` for `--debug` (verbose).
85
+ Deliberate exceptions: boolean negative halves stay long-only (`--no-merge-fragments`) and
86
+ the typer-managed completion flags are untouched. Long forms are unchanged and remain the
87
+ documented canonical spelling; a regression test walks the built command tree proving every
88
+ option has a unique per-command short and byte-compares short vs long invocations.
89
+ - **`gapit screen --output PATH` writes the report to a file (all engines, including
90
+ reads mode).** The file opens on the first output byte — truncating any existing file
91
+ (v1 overwrite semantics, never append) — every streamed chunk is flushed, and stdout
92
+ then carries no data (stderr diagnostics unchanged). An in-batch failure on file *k*
93
+ leaves files 1..*k-1*'s already-streamed output persisted in the file (or printed, on
94
+ stdout) before the typed error envelope and documented exit code; a run failing before
95
+ any output (usage/dependency/db errors) creates no file.
96
+ - **Per-file streaming emission for tsv/csv.** `gapit screen` (blastn gene path and
97
+ cluster path) now emits results in input order as each file completes instead of
98
+ buffering everything until the end: the TSV/CSV header prints once screening starts and
99
+ each file's rows print the moment its file finishes — head-of-line under `--jobs N > 1`
100
+ (file *i* waits for 1..*i*, so output bytes stay identical to sequential runs).
101
+ Markdown sections are computed per file but the document (frontmatter totals) is emitted
102
+ once at the end; JSON stays a single buffered document. Chunk concatenation is
103
+ byte-identical to the former buffered render — goldens and abricate parity are
104
+ untouched. The use-cases gained an optional `emit: Callable[[str], None]` sink (default
105
+ `None` = buffered return exactly as before, so MCP and library callers are unchanged).
106
+
107
+ - **Bundled databases — four audited provider snapshots join `ecoli_dec` in the wheel
108
+ (five bundles total).** `ncbi` (8373 records, public domain), `resfinder` (3206,
109
+ Apache-2.0), `ecoh` (597, BSD-3-Clause), and `upec_expec_vf` (77, MIT) now ship under
110
+ `src/gapit/data/dbs/<name>/` as point-in-time snapshots produced by the `db fetch`
111
+ provider pipeline itself (gapit/v1 headers; snapshot date recorded in `bundled.json`
112
+ as `snapshotted`, the metadata model's new field). `db fetch <name>` remains the
113
+ fresh-upstream update path for all four: it re-downloads the latest upstream content
114
+ and (with `--force`) overwrites the materialized datadir copy, whose manifest then
115
+ drops the `bundled` source stamp; a regression test pins the snapshot↔fetch
116
+ byte-identity for `resfinder` against a committed copy of the exact upstream archive,
117
+ and the provenance guard now scans ALL five bundles' headers for `VF*`/`VFDB`/`ARO:`
118
+ markers. `db list` merges registry-and-bundled names into ONE bundled-section row
119
+ (STATUS `bundled` → `installed (N)`; JSON `source: "bundled"`); registry rows for
120
+ non-bundled providers stay byte-identical. Wheel size 170 KiB → 1.5 MiB (+1.3 MiB for
121
+ the four snapshots; their `sequences` are ~13 MiB uncompressed). `db outdated` stays
122
+ manifest-based (bundled-vs-upstream staleness comparison is future work).
123
+ - **Bundled databases — `ecoli_dec` ships install-time ready (zero-network first use).**
124
+ A new mechanism (`gapit.bundled`) lets license-clean, public-domain databases ride the
125
+ wheel under `src/gapit/data/dbs/<name>/` (`sequences` + optional `typing.json` +
126
+ `bundled.json` metadata: name, description, vendor, dbtype). The first database to use
127
+ it is `ecoli_dec`: the 17-record diarrheagenic E. coli marker panel with the dual-scheme
128
+ `gapit.typing/2` designation (gb4789_6 + risk_monitoring) — after the 2026-10 provenance
129
+ audit re-sourced all records to NCBI/DDBJ primary submissions. When `--db` names a
130
+ bundled database that is absent from the datadir, the screen path materializes it first
131
+ (one quiet-respecting stderr note, then the standard gene-build pipeline: records.jsonl,
132
+ gapit/v1 sequences, BLAST index, typing copy, manifest stamped with the additive
133
+ `source: "bundled"` field); a completely missing datadir is bootstrapped on this path
134
+ only. `gapit setupdb` materializes every bundled database alongside indexing; both paths
135
+ are idempotent (no-op once the manifest exists). `db list` gains a bundled section
136
+ between the registry rows and local extras on all four surfaces (TSV, rich table,
137
+ `--json`, MCP `db_list`): STATUS `bundled` before materialization, `installed (N)`
138
+ after, JSON `source: "bundled"` — registry and local rows stay byte-identical. Wheel
139
+ size 159 KiB → 170 KiB (+11 KiB for the panel).
140
+ - **DEC dual-scheme designation + the `requires_any` exact_set primitive.** The
141
+ diarrheagenic E. coli placeholder is replaced by the real designation as TWO schemes over
142
+ one gene database (`tests/data/typing/schemes/dec.json`, the typing/2 multi-scheme
143
+ showcase): `gb4789_6` (GB 4789.6-2016 panel semantics — EAEC is any-of aggR/pic/astA)
144
+ and `risk_monitoring` (最新食品安全风险监测方案 — aggR mandatory), both exact
145
+ semantics (cutoff 1.0, margin 0.0) with the `uidA` control gene, the `non-DEC` fallback,
146
+ and one severity-ordered rule ladder (EHEC > STEC/EPEC > ETEC > EIEC > EAEC; hybrids
147
+ surface as the runner_up; `EPEC_atypical` declared after EHEC/STEC so stx+ isolates never
148
+ land there). To encode it, `exact_set` rules gained an optional `requires_any` any-of
149
+ gate (satisfied iff all `requires` present AND, when the set is non-empty, at least one
150
+ `requires_any` present AND no `excludes` present; `requires` is now optional when
151
+ `requires_any` carries the constraint; the three sets must be pairwise disjoint and not
152
+ all empty — `TYPING_MALFORMED` otherwise; additive within typing/2, no schema bump).
153
+ The synthetic fixture `dec.fa` carries all 14 gene names plus duplicate pic/sth records
154
+ mirroring the rightsholder db (duplicate records collapse by gene name:
155
+ `-culling_limit 1` keeps the best subject, the engine folds one call per name). The
156
+ definitional matrix is locked end to end — including the headline divergence
157
+ (pic+astA+uidA → EAEC under gb4789_6, non-DEC under risk_monitoring, golden
158
+ `gene_dec_pic_astA`) — and hybrid severity ties (stx2a+escV+aggR → EHEC with EAEC at
159
+ 1.0 as runner_up). No output-schema, TSV, or parity changes.
160
+ - **typing/2 cycle complete — the scheme cookbook (stage 3)**, consolidating the typing/2
161
+ story: stage 1 promoted the typing document to `gapit.typing/2` named multi-scheme
162
+ documents (a `/1` document degrades to one anonymous `default` scheme; gene-kind builds
163
+ gained `--typing`, one call per scheme — first keyed into gapit.report/1's phenotypes
164
+ object, later moved to the `gapit typing` command), stage 2 added the six rule/scheme
165
+ primitives (entry below), and stage 3 proves the framework encodes real designation
166
+ schemes: six researched schemes as validated example documents with synthetic marker
167
+ fixtures in `tests/data/typing/schemes/`, each self-checked end to end by the new
168
+ `test_typing_schemes*.py` suites (build fixture db → screen → asserted phenotype calls)
169
+ with goldens for one representative call per scheme (doumith 4b, shigella mixed, the
170
+ vp O:K compose, cholerae inaba). The cookbook: the complete Doumith Listeria table
171
+ (Doumith et al. 2004, incl. the 4b*/IVb-v1 HGT caveat falling back to NT), a
172
+ ShigaTyper-semantics Shigella/EIEC skeleton (Wu et al. 2019: ipaH_c control, wzx
173
+ unique-group mixed calls, sonnei form I/II with the exact-tie ordering, the lacY EIEC
174
+ approximation with the S. boydii 9/15 exemptions), the meningotype serogroup panel
175
+ (Mothershed et al. 2004 + the synG EX7E allele-probe trick at identity_floor 99.5),
176
+ the Vibrio parahaemolyticus O/K Kaptive pattern (van der Graaf-van Bloois et al. 2023:
177
+ cluster_match bands, the O3/O13 combined label, OUT/KUT fallbacks, per-scheme databases
178
+ — a cluster db carries exactly one scheme), V. cholerae O1/O139 + Ogawa/Inaba (wbeT
179
+ single-SNP allele floor, the negative-wbeT Inaba rule, Hikojima not determinable, the
180
+ wbfZ junction-gene trap note), and a documented DEC placeholder awaiting the
181
+ rightsholder's curated panel. New bilingual docs page `docs/typing.md` / `typing.zh.md`
182
+ (framework reference, primitive tables, the cookbook with citations, the allele
183
+ probe-trick section and its future allele_match successor, calibration pointer), wired
184
+ into mkdocs nav (EN + zh), the doc indexes, and the databases pages. No schema, output,
185
+ or TSV parity changes; parity 15/15 + summary 6/6 unchanged.
186
+ - typing/2 stage-2 rule primitives for declarative phenotype scoring (additive; existing
187
+ rule semantics, outputs, and goldens untouched): the `exact_set` rule (deterministic
188
+ boolean gene-set match with `requires`/`excludes` and 90/90-default identity/coverage
189
+ floors — a 1.0 tie involving a satisfied exact_set resolves by declaration order
190
+ instead of the ambiguity margin), optional `coverage_floor` on `weighted_genes` and
191
+ `exact_set`, scheme-level `control_gene` (absent control gene zeroes the scheme to its
192
+ fallback with a "control gene absent" note), scheme-level `unique_group` +
193
+ `mixed_phenotype` (multiple present group genes call the mixed phenotype with the pair
194
+ in `ambiguous`), `compose` schemes rendering `"{o_group}:{k_group}"` from sibling
195
+ schemes' calls (fallback strings flow through; an ambiguous ingredient yields a null
196
+ composition carrying that ingredient's variants), and rule-level `notes` surfaced
197
+ verbatim on winning phenotype calls. All new fields validate (`TYPING_MALFORMED`,
198
+ unknown gene references `TYPING_UNKNOWN_GENE`); rule models split into
199
+ `gapit.typing_rules` and the decision layer into `gapit.typing_decide` at the 250-LOC
200
+ ceiling.
201
+ - `gapit db list` renders a styled rich table (title "Databases"; cyan Provider, status-tinted
202
+ Status, yellow DBTYPE columns) when stdout is an interactive terminal. Piped or redirected
203
+ output keeps the byte-identical TSV, and `--json` is unchanged.
204
+ - Provider license metadata surfaced in `gapit db list --json` (`license` per provider when
205
+ pinned) and stamped into the build manifest (card, vfdb, ecoli_vf, kaptive).
206
+ - `vendor` field in `gapit.dblist/1` entries: the upstream maintainer organisation behind
207
+ every provider (NCBI, DTU CGE, Kaptive (klebgenomics), ...). Additive; `name` still
208
+ carries the database name passed to `--db`.
209
+
210
+ ### Changed
211
+
212
+ - Uniform help-on-bare: commands that require input now print their full help when
213
+ invoked with no arguments at all — `gapit screen`, `summary`, `schema`, `db`,
214
+ `db fetch`, `db install`, `db build`, `db search` (typer `no_args_is_help`). The
215
+ help exits 2, the same code the bare root app has always used under click's
216
+ no-args-is-help semantics (recorded reality; the pre-change bare `screen`/`summary`
217
+ also exited 2, but with a `gapit.error/1` envelope instead of help, and bare
218
+ `schema`/`db install`/`db build`/`db search` raised click missing-argument errors).
219
+ Invocations with flags present but input missing keep their typed usage-error
220
+ envelopes (exit 2). Commands valid with no arguments (`mcp`, `setupdb`, `db list`,
221
+ `db outdated`) are unchanged. Breaking for `db fetch`: an omitted NAME no longer
222
+ installs the default set — the default-set download is now explicit
223
+ (`gapit db fetch all`, same DEFAULT_DBS order and receipts; bare fetch prints help,
224
+ and `db fetch --flags` without a NAME is a typed usage error), because a bare
225
+ invocation silently starting a multi-database download was a footgun. The MCP
226
+ `db_fetch` tool aligns: `name` is required and accepts the literal `all`. Docs
227
+ updated in step (EN + zh); no output schemas or goldens changed.
228
+
229
+ - Terminology sweep after the NAME/PROVIDER column split: user-facing text now reserves
230
+ PROVIDER for the upstream maintainer organisation and consistently calls the `--db`
231
+ value the database NAME. `gapit db fetch` help reads "Fetch and build database(s)"
232
+ with a "Database name" `[NAME]` argument help, `gapit db list` help reads "List known
233
+ databases (NAME, upstream PROVIDER) and their installed state", the `db` group help
234
+ says "database fetch" (was "provider fetch"), `db install` help says "no database
235
+ names" (was "no provider IDs"), and the MCP `db_fetch`/`db_list` tool descriptions use
236
+ database-name phrasing. The unknown-name error from `gapit db fetch` / the `db_fetch`
237
+ tool now reads `unknown database: NAME (available: ...)` with context key `db` (was
238
+ `unknown provider: ...` with context key `provider`); the error CODE stays `USAGE_ERROR`.
239
+ Docs updated in step (EN + zh). No flags, output schemas, exit codes, or internal
240
+ identifiers changed; the `gapit.dblist/1` `providers` array key is untouched.
241
+
242
+ - `gapit db list` TSV header is now `NAME PROVIDER STATUS DBTYPE DESCRIPTION`: the old
243
+ PROVIDER column actually held the database name users pass to `--db`, so it is renamed
244
+ NAME, and a new PROVIDER column names the upstream maintainer organisation (the `vendor`
245
+ above). Breaking for TSV consumers (header change, 4 → 5 columns); the rich table gained
246
+ the same NAME/PROVIDER split and `gapit.dblist/1` `name` is unchanged.
247
+
248
+ - card and vfdb unbundled to download-on-fetch providers (license compliance: their
249
+ non-commercial upstream terms — McMaster's for CARD, CC BY-NC for VFDB — are incompatible
250
+ with redistribution inside the MIT-licensed wheel). `ecoli_vf` pins its true license
251
+ (`CC BY-NC 4.0 (VFDB-derived content)` — the repo is labeled Apache but its README states
252
+ the content is taken from the VFDB). The bundled-snapshot archives, the snapshot-first
253
+ install path, the monthly snapshot-refresh CI workflow, and the `snapshot-update` /
254
+ `stale+snapshot-update` `db outdated` statuses are gone; `db outdated` now reports `ok`
255
+ or `stale` only.
256
+ - Kaptive cluster providers renamed/expanded to the seven official Kaptive v3 install
257
+ keywords — `kpsc_k`, `kpsc_o`, `kosc_k`, `kosc_o`, `ab_k`, `ab_o`, `ecoli_kps`
258
+ (K. pneumoniae species complex K/O, K. oxytoca species complex K/O, A. baumannii K/OC,
259
+ E. coli group 2+3 capsular polysaccharide loci) — each sourcing its raw GenBank file
260
+ from `main` of the actively curated per-species upstream repos
261
+ (klebgenomics.github.io/Kaptive/db/overview.html#available-databases), so fetches track
262
+ current curation instead of the frozen v2.0.9 archives the four old providers pinned.
263
+ Still GPL-3.0 download-on-fetch, never bundled; manifests record the new source URL,
264
+ license, and citation note (Kaptive/Wyres et al. 2020). The upstream `.toml`
265
+ identity-threshold metadata is not fetched in v1 (a future `typing.json` source).
266
+
267
+ ### Removed
268
+
269
+ - `gapit db fetch --from-source` flag (meaningless now that no bundled snapshots exist:
270
+ every fetch downloads from upstream).
271
+
272
+ ### Fixed
273
+
274
+ - **DEC panel provenance cleaning.** The original 17-record DEC panel carried two
275
+ VFDB-derived records (spotted past header inspection) plus VF-flavored metadata; all
276
+ records were re-sourced from NCBI/DDBJ primary submissions (100% same-allele, 5
277
+ replacements: bfpB, pic ×2, astA, stx2b, and the sth/stp/lt accessions re-verified),
278
+ and a regression test now mechanically asserts no `VF*` tags ride the bundled headers.
279
+
280
+ ## [0.4.0] - 2026-09-30
281
+
282
+ ### Added
283
+
284
+ - **Gene-cluster databases and cluster screening** (stages 1–3; the blastn gene path and
285
+ all existing outputs are untouched — parity stays byte-identical):
286
+ - `gapit db build NAME input.gbk|input.gff3` detects the input kind by suffix and builds
287
+ a `kind: cluster` database — locus FASTA `sequences`, `gapit.features/1` feature table
288
+ (`features.json`), makeblastdb index, manifest `kind: cluster` — with `--kind
289
+ gene|cluster` to override (usage error on contradiction). New parsers (no Biopython):
290
+ GenBank FEATURES/ORIGIN (Bakta/modern and kaptive-style source-note labels) and GFF3
291
+ (embedded `##FASTA` or sidecar); compound `join()` CDS locations are rejected with a
292
+ typed error.
293
+ - `gapit screen --db <cluster db>` dispatches to the minimap2 `asm20` cluster engine:
294
+ per-gene present/partial/absent verdicts (`--min-gene-cov`/`--min-gene-id`, default
295
+ 90/90), cs-based union coverage/identity, cross-contig fragmentation resilience, and a
296
+ best-locus call above `--min-cluster-cov` (default 96). Output is the new
297
+ `gapit.cluster/1` document (json), the cluster TSV/CSV (one row per file), or
298
+ Markdown; kind-mismatched flags are usage errors; reads mode rejects cluster
299
+ databases. The MCP `screen` tool gains `minGeneCov`/`minGeneId`/`minClusterCov`.
300
+ - `--typing FILE` installs a validated `gapit.typing/1` declarative scoring spec into a
301
+ cluster db (`typing.json`). Screening a typed database annotates every best call with
302
+ a `phenotype` and an additive `phenotype_detail` breakdown (score, confidence,
303
+ per-rule components, runner-up, ambiguity pair); the TSV gains a PHENOTYPE column
304
+ (typed runs only — untyped output stays byte-identical). Three rule kinds —
305
+ `weighted_genes`, `cluster_match`, `learned_linear` (schema only; no training code) —
306
+ behind a `cutoff` + `ambiguity_margin` + `fallback` decision layer. Unknown gene/locus
307
+ references fail with `TYPING_UNKNOWN_GENE` at build AND screen time.
308
+ - Four kaptive cluster providers, `kaptive_k`, `kaptive_o`, `kaptive_ak`, `kaptive_oc`
309
+ (Klebsiella K/O and A. baumannii K/OC antigen loci; Wyres et al. 2020 — cite Kaptive).
310
+ The database content is GPL-3.0, so nothing is bundled: fetch downloads the pinned
311
+ Kaptive v2.0.9 GenBank files and builds cluster databases; manifests record the
312
+ source URL, `license`, and citation `note`. No typing model ships with them yet
313
+ (locus calls only, phenotype null).
314
+ - `scripts/cluster_calibration.py`: developer harness that screens a typed cluster db
315
+ against a labels TSV and prints the per-expected-phenotype score distribution, the
316
+ called×expected agreement matrix, and the divergence list (the v1 loop for future
317
+ learned_linear training).
318
+ - `gapit screen --merge-fragments` (blastn contig mode only; off by default): merge gene
319
+ fragments split across contig boundaries into one reported hit when their union subject
320
+ coverage reaches `--mincov`. Merged rows carry additive optional `merged` and `fragments`
321
+ fields in `gapit.report/1` JSON plus a Markdown detail line; the default path (and all
322
+ existing output) is untouched. The MCP `screen` tool gains the matching `mergeFragments`
323
+ boolean parameter.
324
+
325
+ ## [0.3.1] - 2026-09-28
326
+
327
+ ### Added
328
+
329
+ - `-h` now works as an alias for `--help` on every command (root, subcommands,
330
+ and nested `db` sub-app).
331
+
332
+ ## [0.3.0] - 2026-09-28
333
+
334
+ ### Removed
335
+
336
+ - `gapit list` command and the `gapit.list/1` schema (breaking; rightsholder decision to
337
+ drop abricate `--list` strict parity for this surface). `gapit db list` / `gapit.dblist/1`
338
+ is the single listing surface; `gapit schema` now introspects six documents.
339
+
340
+ ## [0.2.2] - 2026-09-24
341
+
342
+ ### Security
343
+
344
+ - minimap2 input paths are passed as absolute paths, so a file named like an option
345
+ (e.g. `-d`) can no longer inject minimap2 flags; the child process no longer inherits
346
+ stdin (the MCP protocol stream).
347
+
348
+ ### Changed
349
+
350
+ - `--minid`/`--mincov` with `--aligner minimap2` or `--r1/--r2` are now a usage error
351
+ (exit 2) instead of being silently ignored.
352
+ - MCP `screen` (blastn) reuses the CLI use-case; its validation messages now match the CLI.
353
+ - MCP `screen_reads` passes read arrays natively, so filenames containing commas work.
354
+
355
+ ### Fixed
356
+
357
+ - `gapit db list` now also lists databases installed into the datadir outside the provider
358
+ catalog: `db build` products (gene and cluster kinds) and manifest-less directories
359
+ (abricate-style or `db install` bytes) render after the registry entries, sorted by name,
360
+ with PROVIDER `local`, the record count from the manifest (FASTA count when absent), and
361
+ DBTYPE from the manifest / BLAST index suffix / letter heuristic. The gapit.dblist/1 JSON
362
+ gains them inside `providers` behind the additive `source: "local"` field — registry
363
+ entries simply lack the field, so pre-existing output is byte-identical; TSV, rich table,
364
+ and the MCP `db_list` tool share the same rows.
365
+ - MCP server replies `-32600`/`-32602` to malformed requests that carry an `id` instead of
366
+ silently dropping them.
367
+ - A truncated gzip reads file raises a typed `INVALID_READS_FORMAT` error (exit 5) instead
368
+ of `UNEXPECTED` (exit 1).
369
+
370
+ ## [0.2.1] - 2026-09-22
371
+
372
+ ### Changed
373
+
374
+ - License changed from GPL-2.0-only to MIT (rightsholder decision; behavioral
375
+ reimplementation status unchanged).
376
+
377
+ ## [0.2.0] - 2026-09-22
378
+
379
+ Development window: 2026-09-15 to 2026-09-22 (PLAN.md Phases 1 through 8 and post-phase
380
+ hardening).
381
+
382
+ ### Added
383
+
384
+ - Screening core: `any2fasta` to `blastn` pipeline with SPEC-exact hit processing, and
385
+ byte-compatible TSV against abricate 1.4.0 (PLAN Phases 1-3, 2026-09-15). Parity is
386
+ checked on a genome corpus with `pixi run -e parity parity` (6/6 byte-identical).
387
+ - Agent-facing outputs: `--format json|md` with versioned schemas (`gapit.report/1`,
388
+ `gapit.reads/1`, `gapit.summary/1`, `gapit.list/1`, `gapit.version/1`), the
389
+ `gapit.error/1` stderr envelope with documented exit codes, and introspection via
390
+ `gapit schema report|reads|summary|list|error|version` (2026-09-16).
391
+ - FASTQ reads mode via minimap2: `gapit screen --r1/--r2 --read-type sr|map-ont|map-hifi`;
392
+ presence is called on alignment breadth (2026-09-16).
393
+ - Summary matrix mode: `gapit summary` emits TSV/CSV/JSON/MD; byte parity with
394
+ `abricate --summary` via `pixi run -e parity summary-parity` (2026-09-17).
395
+ - `gapit db install`: checksum-verified (SHA256), atomic local-file installation
396
+ (2026-09-17).
397
+ - Native `gapit/v1` database format: tagged-header codec, `records.jsonl` truth store
398
+ with `gapit.manifest/1` provenance, deterministic build pipeline with self-check, and
399
+ `.mmi` BLAST index build with version-gated reuse (2026-09-18).
400
+ - 12 database providers (ncbi, card, resfinder, argannot, plasmidfinder, megares, ecoh,
401
+ vfdb, ecoli_vf, bacmet2, victors, upec_expec_vf) with offline-tested transforms
402
+ (2026-09-18).
403
+ - Bundled card and vfdb snapshots: a bare `gapit db fetch` installs the default set with
404
+ zero network; `--from-source` forces upstream download (2026-09-18).
405
+ - CLI hardening: shell completions, `--debug` argv echo on stderr, and `--jobs` parallel
406
+ screening across inputs with input-order stdout (2026-09-18).
407
+ - CI: gates matrix (lint, fmt, typecheck, test on Python 3.11 / 3.13 / 3.14) plus a
408
+ parity job that byte-diffs against real abricate (2026-09-18).
409
+ - MCP stdio server: `gapit mcp` subcommand and `gapit-mcp` console script, hand-rolled
410
+ JSON-RPC 2.0 with zero new dependencies; read-only tools `screen`, `summary`,
411
+ `schema`, `db_list` (2026-09-18).
412
+ - Conda recipe (`recipe/meta.yaml`) for PyPI/bioconda packaging (2026-09-18).
413
+ - Custom database construction: `gapit db build NAME FASTA` builds a screening-ready native
414
+ database from plain, abricate `~~~`, or `gapit|` FASTA (auto-detected), with optional
415
+ `--tsv` metadata (accession, function classes) and `--dbtype` override; guide with worked
416
+ examples in `docs/custom-db.md` (2026-09-19).
417
+ - `--aligner blastn|minimap2` engine selector on `gapit screen`: defaults follow the input
418
+ (blastn for contig files, minimap2 for `--r1`/`--r2` reads); `--aligner minimap2` screens
419
+ positional assembly FASTA through the minimap2 engine, `--aligner blastn` with `--r1`/`--r2`
420
+ is a usage error (2026-09-19).
421
+ - `gapit db outdated`: staleness report over installed databases (age vs `--days`, newer
422
+ bundled snapshot) as a TSV table or `gapit.dboutdated/1` JSON document (2026-09-20).
423
+ - `gapit db search TERM`: case-insensitive gene/accession/function/product lookup across
424
+ installed databases' `records.jsonl`, with `--field`, `--exact`, `--db`, `--limit` and
425
+ JSONL output (2026-09-20).
426
+ - MCP database tools `db_fetch`, `db_build`, `db_search`, `db_outdated`: the MCP server now
427
+ exposes the `db` commands alongside the analysis tools, so agents can self-provision and
428
+ inspect databases mid-session; `mcp.py` split into protocol (`mcp.py`) and tool
429
+ implementations (`mcp_tools.py`) with zero wire change for the existing tools (2026-09-20).
430
+ - CI snapshot refresh: monthly scheduled workflow (`.github/workflows/snapshot-refresh.yml`)
431
+ re-fetching card and vfdb from upstream, regenerating the bundled tars only when the
432
+ records changed, and opening a review PR (2026-09-20).
433
+ - Reads-mode opt-in alignment filtering: `gapit screen --min-identity/--min-mapq` (reads
434
+ engine only) drops PAF alignments below the thresholds before aggregation and emits the new
435
+ `gapit.reads/2` document (params gain both thresholds; gene entries gain
436
+ `mean_identity_pct`, the alignment-length-weighted mean identity; introspectable via
437
+ `gapit schema reads2`). Both flags off keeps `gapit.reads/1` byte-identical, and the
438
+ identity floor fixes the documented family-splitting over-calls on homologous genes
439
+ (2026-09-20).
440
+ - MCP reads tools: new `screen_reads` tool (FASTQ lanes via minimap2 → `gapit.reads/1`,
441
+ `min_identity`/`min_mapq` > 0 → `gapit.reads/2`) and new `screen` arguments
442
+ `aligner`/`min_breadth`/`min_identity`/`min_mapq` (`aligner minimap2` = fast assembly
443
+ survey). Both delegate to the shared reads use-cases with `quiet` stderr; additive
444
+ `gapit.mcp` contract — nine tools, the other eight wire-identical, no output-schema
445
+ version bump (2026-09-22).
446
+
447
+ ### Changed
448
+
449
+ - `any2fasta` is no longer a runtime dependency: input normalization (FASTA/FASTQ/GenBank/EMBL,
450
+ plain/gz/bz2 → FASTA) is native (`seqconvert.py`, perl-extracted semantics) and blastn reads the
451
+ converted FASTA on stdin. Parsed-record equivalence with the binary is differentially tested
452
+ with the parity env on PATH (abricate provides any2fasta transitively), and `.fa` parity
453
+ remains byte-identical (2026-09-21).
454
+ - Screening and reads paths route `gapit/v1` tagged headers to the native codec; legacy
455
+ abricate `~~~` headers keep the frozen parser, so abricate-built datadirs screen
456
+ identically. The reverse does not hold: gapit-built databases are unreadable by
457
+ abricate (accepted trade-off).
458
+ - A bare `gapit db fetch` installs the bundled default set (card, vfdb) instead of
459
+ downloading; `--from-source` restores the upstream fetch path.
460
+ - `gapit setupdb` honors the `gapit.manifest/1` dbtype on reindex (manifest-less abricate
461
+ dirs keep the mol_type heuristic), and reads/minimap2-assembly screening now rejects the
462
+ blastn-only flags `--fofn`, `--noheader`, `--nopath`, `--jobs N>1` with usage errors
463
+ (exit 2) instead of silently ignoring them (2026-09-22).
464
+
465
+ ### Removed
466
+
467
+ - `--csv` flag on `gapit screen`; use `--format csv` instead (breaking: the flag is now
468
+ rejected as an unknown option, exit 2) (2026-09-19).
469
+
470
+ ### Fixed
471
+
472
+ - Summary mode auto-detects TSV vs CSV per input file, avoiding the upstream quirk where
473
+ a global `--csv` flag mangles mixed-format input sets.