textflowkit 0.1.11__tar.gz → 0.1.13__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 (236) hide show
  1. {textflowkit-0.1.11 → textflowkit-0.1.13}/.github/workflows/ci.yml +13 -2
  2. textflowkit-0.1.13/AGENTS.md +19 -0
  3. {textflowkit-0.1.11 → textflowkit-0.1.13}/CHANGELOG.md +92 -0
  4. {textflowkit-0.1.11 → textflowkit-0.1.13}/PKG-INFO +172 -15
  5. {textflowkit-0.1.11 → textflowkit-0.1.13}/README.md +171 -14
  6. {textflowkit-0.1.11 → textflowkit-0.1.13}/docs/adapters.md +72 -4
  7. {textflowkit-0.1.11 → textflowkit-0.1.13}/docs/architecture.md +79 -2
  8. {textflowkit-0.1.11 → textflowkit-0.1.13}/docs/assets/architecture-overview.svg +1 -1
  9. {textflowkit-0.1.11 → textflowkit-0.1.13}/docs/assets/whistle-resume.svg +5 -5
  10. {textflowkit-0.1.11 → textflowkit-0.1.13}/docs/index.html +73 -12
  11. {textflowkit-0.1.11 → textflowkit-0.1.13}/docs/install.md +59 -4
  12. {textflowkit-0.1.11 → textflowkit-0.1.13}/docs/release-checklist.md +54 -5
  13. {textflowkit-0.1.11 → textflowkit-0.1.13}/docs/roadmap.md +22 -1
  14. {textflowkit-0.1.11 → textflowkit-0.1.13}/docs/streaming.md +4 -4
  15. {textflowkit-0.1.11 → textflowkit-0.1.13}/docs/user-manual.md +175 -16
  16. textflowkit-0.1.13/docs/verification/whistle-coverage-20261019.md +77 -0
  17. textflowkit-0.1.13/docs/verification/windows-sources-20261019.md +51 -0
  18. textflowkit-0.1.13/packaging/windows/README.md +78 -0
  19. textflowkit-0.1.13/packaging/windows/THIRD-PARTY-NOTICES.txt +46 -0
  20. textflowkit-0.1.13/packaging/windows/assets.lock.json +56 -0
  21. textflowkit-0.1.13/packaging/windows/launch.py +140 -0
  22. textflowkit-0.1.13/packaging/windows/source-materials.json +39 -0
  23. textflowkit-0.1.13/packaging/windows/textflowkit.iss +77 -0
  24. {textflowkit-0.1.11 → textflowkit-0.1.13}/pyproject.toml +6 -1
  25. textflowkit-0.1.13/scripts/build_windows_installer.py +160 -0
  26. textflowkit-0.1.13/scripts/prepare_windows_payload.py +1010 -0
  27. textflowkit-0.1.13/scripts/run_deepseek_worker.py +110 -0
  28. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/__init__.py +1 -1
  29. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/checkpoint.py +1 -1
  30. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/service.py +3 -0
  31. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/streaming_process.py +4 -3
  32. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/whistle.py +223 -21
  33. textflowkit-0.1.13/src/textflowkit/core/windows_process.py +24 -0
  34. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/sources/acquire.py +4 -1
  35. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/ui/app.py +101 -0
  36. textflowkit-0.1.13/src/textflowkit/ui/cleanup.py +306 -0
  37. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/ui/launcher.py +3 -0
  38. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/ui/static/app.css +7 -0
  39. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/ui/static/app.js +6 -0
  40. textflowkit-0.1.13/src/textflowkit/ui/static/cleanup.js +151 -0
  41. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/ui/static/index.html +23 -0
  42. textflowkit-0.1.13/tests/fixtures/whistle_seam_regressions.json +3767 -0
  43. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_sdist_allowlist.py +4 -0
  44. textflowkit-0.1.13/tests/test_ui_cleanup.py +452 -0
  45. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_ui_packaging.py +5 -2
  46. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_whistle_engine.py +13 -13
  47. textflowkit-0.1.13/tests/test_whistle_seams.py +187 -0
  48. textflowkit-0.1.13/tests/test_windows_installer.py +512 -0
  49. textflowkit-0.1.13/tests/test_windows_payload.py +483 -0
  50. {textflowkit-0.1.11 → textflowkit-0.1.13}/.dockerignore +0 -0
  51. {textflowkit-0.1.11 → textflowkit-0.1.13}/.env.example +0 -0
  52. {textflowkit-0.1.11 → textflowkit-0.1.13}/.gitattributes +0 -0
  53. {textflowkit-0.1.11 → textflowkit-0.1.13}/.github/dependabot.yml +0 -0
  54. {textflowkit-0.1.11 → textflowkit-0.1.13}/.github/workflows/publish-pypi.yml +0 -0
  55. {textflowkit-0.1.11 → textflowkit-0.1.13}/.gitignore +0 -0
  56. {textflowkit-0.1.11 → textflowkit-0.1.13}/.pre-commit-config.yaml +0 -0
  57. {textflowkit-0.1.11 → textflowkit-0.1.13}/CONTRIBUTING.md +0 -0
  58. {textflowkit-0.1.11 → textflowkit-0.1.13}/Dockerfile +0 -0
  59. {textflowkit-0.1.11 → textflowkit-0.1.13}/LEGAL.md +0 -0
  60. {textflowkit-0.1.11 → textflowkit-0.1.13}/LICENSE +0 -0
  61. {textflowkit-0.1.11 → textflowkit-0.1.13}/SECURITY.md +0 -0
  62. {textflowkit-0.1.11 → textflowkit-0.1.13}/compose.yaml +0 -0
  63. {textflowkit-0.1.11 → textflowkit-0.1.13}/docs/.nojekyll +0 -0
  64. {textflowkit-0.1.11 → textflowkit-0.1.13}/docs/404.html +0 -0
  65. {textflowkit-0.1.11 → textflowkit-0.1.13}/docs/assets/live-streaming-flow.svg +0 -0
  66. {textflowkit-0.1.11 → textflowkit-0.1.13}/docs/assets/local-ui-flow.svg +0 -0
  67. {textflowkit-0.1.11 → textflowkit-0.1.13}/docs/site-deployment.md +0 -0
  68. {textflowkit-0.1.11 → textflowkit-0.1.13}/docs/sources.md +0 -0
  69. {textflowkit-0.1.11 → textflowkit-0.1.13}/scripts/fetch_published_fonts.py +0 -0
  70. {textflowkit-0.1.11 → textflowkit-0.1.13}/scripts/smoke_installed_wheel.py +0 -0
  71. {textflowkit-0.1.11 → textflowkit-0.1.13}/scripts/smoke_live_youtube.py +0 -0
  72. {textflowkit-0.1.11 → textflowkit-0.1.13}/scripts/verify_readme_release.py +0 -0
  73. {textflowkit-0.1.11 → textflowkit-0.1.13}/scripts/verify_release_ci.py +0 -0
  74. {textflowkit-0.1.11 → textflowkit-0.1.13}/scripts/verify_release_versions.py +0 -0
  75. {textflowkit-0.1.11 → textflowkit-0.1.13}/scripts/write_release_manifest.py +0 -0
  76. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/adapters/__init__.py +0 -0
  77. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/adapters/http_server.py +0 -0
  78. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/adapters/mcp_server.py +0 -0
  79. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/adapters/streaming_ws.py +0 -0
  80. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/assets/README.md +0 -0
  81. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/assets/selftest-speech.wav +0 -0
  82. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/cli.py +0 -0
  83. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/__init__.py +0 -0
  84. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/batch.py +0 -0
  85. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/bind.py +0 -0
  86. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/cancel.py +0 -0
  87. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/diarize.py +0 -0
  88. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/engine.py +0 -0
  89. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/executor.py +0 -0
  90. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/jobs.py +0 -0
  91. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/model.py +0 -0
  92. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/paths.py +0 -0
  93. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/pipeline.py +0 -0
  94. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/retrieval.py +0 -0
  95. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/runner.py +0 -0
  96. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/sqlite_store.py +0 -0
  97. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/startup.py +0 -0
  98. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/stream_worker.py +0 -0
  99. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/streaming.py +0 -0
  100. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/streaming_assets.py +0 -0
  101. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/streaming_events.py +0 -0
  102. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/submission.py +0 -0
  103. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/timeutil.py +0 -0
  104. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/translate.py +0 -0
  105. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/core/whistle_assets.py +0 -0
  106. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/render/__init__.py +0 -0
  107. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/render/_cue_layout.py +0 -0
  108. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/render/_cue_text.py +0 -0
  109. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/render/_rename_excl.py +0 -0
  110. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/render/_rename_noreplace.py +0 -0
  111. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/render/docx.py +0 -0
  112. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/render/markdown.py +0 -0
  113. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/render/pdf.py +0 -0
  114. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/render/srt.py +0 -0
  115. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/render/txt.py +0 -0
  116. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/render/vtt.py +0 -0
  117. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/sources/__init__.py +0 -0
  118. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/sources/detect.py +0 -0
  119. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/sources/scratch.py +0 -0
  120. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/ui/__init__.py +0 -0
  121. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/ui/capabilities.py +0 -0
  122. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/ui/ownership.py +0 -0
  123. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/ui/paths.py +0 -0
  124. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/ui/security.py +0 -0
  125. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/ui/static/streaming-capture-worklet.js +0 -0
  126. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/ui/static/streaming-example.html +0 -0
  127. {textflowkit-0.1.11 → textflowkit-0.1.13}/src/textflowkit/ui/uploads.py +0 -0
  128. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/__init__.py +0 -0
  129. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/ollama_stub.py +0 -0
  130. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_acquire.py +0 -0
  131. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_adapters.py +0 -0
  132. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_admission_ownership.py +0 -0
  133. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_atomic_resume.py +0 -0
  134. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_atomic_resume_aba.py +0 -0
  135. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_batch.py +0 -0
  136. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_batch_item_boundary.py +0 -0
  137. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_batch_resume_shared.py +0 -0
  138. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_bind.py +0 -0
  139. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_cancellation_finalization.py +0 -0
  140. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_checkpoint.py +0 -0
  141. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_checkpoint_single_copy.py +0 -0
  142. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_cli.py +0 -0
  143. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_cli_batch_feedback.py +0 -0
  144. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_cli_owning_recovery.py +0 -0
  145. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_cli_resume_batch.py +0 -0
  146. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_cli_stage_feedback.py +0 -0
  147. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_cli_stdout_format.py +0 -0
  148. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_confined_decoder_boundary.py +0 -0
  149. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_confined_indirect_media.py +0 -0
  150. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_confined_resume_boundary.py +0 -0
  151. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_container_example.py +0 -0
  152. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_cue_layout.py +0 -0
  153. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_diarize.py +0 -0
  154. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_diarize_example_flags.py +0 -0
  155. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_diarize_token_docs.py +0 -0
  156. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_docx_publication_identity.py +0 -0
  157. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_done_output_integrity.py +0 -0
  158. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_empty_formats_resume.py +0 -0
  159. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_engine_adapters.py +0 -0
  160. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_engine_cache.py +0 -0
  161. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_engine_faster.py +0 -0
  162. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_engine_quiet.py +0 -0
  163. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_executor.py +0 -0
  164. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_executor_store_failure.py +0 -0
  165. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_export.py +0 -0
  166. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_export_file_mode.py +0 -0
  167. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_export_preflight.py +0 -0
  168. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_faster_whisper_docs.py +0 -0
  169. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_fetch_published_fonts.py +0 -0
  170. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_font_notices.py +0 -0
  171. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_http_host_boundary.py +0 -0
  172. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_http_trusted_proxy.py +0 -0
  173. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_job_progress.py +0 -0
  174. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_jobs.py +0 -0
  175. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_landing_commands.py +0 -0
  176. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_landing_page.py +0 -0
  177. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_legal_summary.py +0 -0
  178. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_linux_no_hardlink.py +0 -0
  179. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_live_smoke_script.py +0 -0
  180. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_macos_no_hardlink.py +0 -0
  181. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_mcp_batch_cookie_docs.py +0 -0
  182. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_mcp_http_boundary.py +0 -0
  183. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_mcp_protocol_cleanliness.py +0 -0
  184. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_mcp_terminal_guidance.py +0 -0
  185. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_mcp_tool_descriptions.py +0 -0
  186. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_mcp_work_root.py +0 -0
  187. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_model.py +0 -0
  188. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_partial_output_resume.py +0 -0
  189. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_partial_pdf_resume.py +0 -0
  190. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_paths.py +0 -0
  191. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_pipeline_integrity.py +0 -0
  192. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_pipeline_resume_setup.py +0 -0
  193. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_production_browser_cookies.py +0 -0
  194. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_publish_ci_gate.py +0 -0
  195. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_publish_fonts_wiring.py +0 -0
  196. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_publish_manifest_wiring.py +0 -0
  197. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_publish_workflow_gate.py +0 -0
  198. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_readme_layout.py +0 -0
  199. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_readme_release_guard.py +0 -0
  200. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_release_boundaries.py +0 -0
  201. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_release_manifest.py +0 -0
  202. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_release_surfaces.py +0 -0
  203. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_render.py +0 -0
  204. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_retrieval.py +0 -0
  205. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_service_profile.py +0 -0
  206. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_site_not_found.py +0 -0
  207. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_sources.py +0 -0
  208. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_stage_reuse_resume.py +0 -0
  209. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_startup_recovery.py +0 -0
  210. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_stdio_protocol.py +0 -0
  211. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_streaming_assets.py +0 -0
  212. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_streaming_browser_lifecycle.py +0 -0
  213. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_streaming_core.py +0 -0
  214. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_streaming_example.py +0 -0
  215. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_streaming_repairs.py +0 -0
  216. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_streaming_transport.py +0 -0
  217. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_streaming_u5_repairs.py +0 -0
  218. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_streaming_ui_integration.py +0 -0
  219. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_submission.py +0 -0
  220. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_submission_validation.py +0 -0
  221. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_translate.py +0 -0
  222. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_translate_completeness.py +0 -0
  223. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_ui_assets_and_capabilities.py +0 -0
  224. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_ui_consoleless_logging.py +0 -0
  225. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_ui_existing_routes_unchanged.py +0 -0
  226. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_ui_launcher.py +0 -0
  227. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_ui_ownership_and_shutdown.py +0 -0
  228. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_ui_real_serve.py +0 -0
  229. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_ui_security.py +0 -0
  230. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_ui_submission_and_download.py +0 -0
  231. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_ui_uploads.py +0 -0
  232. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_verify_release_versions.py +0 -0
  233. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_whistle_assets.py +0 -0
  234. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_whistle_defaults.py +0 -0
  235. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_whistle_job_resume.py +0 -0
  236. {textflowkit-0.1.11 → textflowkit-0.1.13}/tests/test_windows_no_hardlink.py +0 -0
@@ -45,9 +45,20 @@ jobs:
45
45
  if: runner.os == 'Linux'
46
46
  run: sudo apt-get update && sudo apt-get install -y ffmpeg
47
47
 
48
- - name: Install ffmpeg (Windows)
48
+ - name: Install pinned ffmpeg (Windows)
49
49
  if: runner.os == 'Windows'
50
- run: choco install ffmpeg --no-progress -y
50
+ shell: python
51
+ run: |
52
+ import os, runpy
53
+ from pathlib import Path
54
+ ns = runpy.run_path('scripts/prepare_windows_payload.py')
55
+ spec = ns['load_asset_lock'](Path('packaging/windows/assets.lock.json'))['assets']['ffmpeg']
56
+ cache = Path(os.environ['RUNNER_TEMP']) / 'textflowkit-ci-ffmpeg'
57
+ archive = ns['_download_locked_asset'](cache, spec)
58
+ destination = cache / 'payload'
59
+ ns['prepare_ffmpeg_archive'](archive, destination)
60
+ with open(os.environ['GITHUB_PATH'], 'a', encoding='utf-8') as f:
61
+ f.write(str(destination / 'bin') + '\n')
51
62
 
52
63
  - name: Install ffmpeg (macOS)
53
64
  if: runner.os == 'macOS'
@@ -0,0 +1,19 @@
1
+ # TextFlowKit agent instructions
2
+
3
+ Scott's current bounded completion contract governs this work. Follow the active task and repository-required CI; preserve unrelated work and credentials. Keep one concise execution record, reuse unaffected evidence, and distinguish prepared, executed, verified and delivered work. A documented blocker remains incomplete. Do not invent adjacent features or weaken checks.
4
+
5
+ ## Roles and delegation
6
+
7
+ The main assistant coordinates, plans and oversees. A worker invoked for an implementation unit performs that assigned unit directly; it is not another coordinator. Do not launch nested workers or automatic review/fan-out unless the owner or assignment explicitly authorizes it. Default to serial execution and one release candidate.
8
+
9
+ ## Model selection
10
+
11
+ Follow Scott's active task selection; do not impose a project-wide Ollama default. His normal substantial-work/coordination preference is gpt-6.1-sol at medium, with gpt-6-luna at xhigh for small bounded work when available. Do not spawn a worker merely to switch models or add providers without authorization.
12
+
13
+ For the explicitly authorized current Whistle release and issue #31 source-recovery work, Scott requested Ollama `deepseek-v4.1-flash:1017-cloud`, reasoning OFF. `scripts/run_deepseek_worker.py` is an explicit opt-in runner for those assigned DeepSeek units: it sends `think: false`, allows no model fallback, and records the actual response model. Ollama currently returns canonical ID `deepseek-v4.1-flash:1017` without the `-cloud` transport suffix. Do not confuse a worker's self-description with the transport receipts. Preserve existing DeepSeek integrations with reasoning off, but do not turn this task-specific instruction into the default for unrelated future work.
14
+
15
+ This does not change the application's transcription or AI-cleanup defaults. Whistle remains the default transcription engine.
16
+
17
+ ## Scope and delivery safeguards
18
+
19
+ Preserve unfinished work. Workers must not push, merge, tag, publish, release, stop unrelated processes, or change global configuration unless that unit is explicitly authorized to do so. The coordinating release task has Scott's push/merge/tag/publication authorization and separately his authorization to complete issue #31. Keep scratch, caches and build outputs outside the checkout. Verify process identity before acting on a PID; record ownership and terminal result for background jobs. Follow enforced controls rather than disguising a rejected action.
@@ -1,5 +1,97 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.1.13 — 2026-10-19
4
+
5
+ Core: 0.1.13; unchanged optional fonts: 0.1.6. Whistle missing-speech fixes and a
6
+ native Windows installer distributed with matching FFmpeg sources and notices.
7
+
8
+ - Bound native Whistle decode inputs to 15 seconds with 11-second owned cores
9
+ and up to two seconds of context per side. The former 30-second inputs
10
+ reproducibly omitted passages recovered by shorter inputs. Window policy is
11
+ part of resume identity; partial progress from the old plan requires a fresh
12
+ run. The engine and pinned model remain Whistle.
13
+ - Check short gaps with a bounded, differently framed native decode. Add words
14
+ only between two matching timed anchors; retain original words/repetitions,
15
+ skip long pauses, and cap extra calls per core. Record recovery counts.
16
+ - Correct Whistle shared-context assembly when independently estimated word
17
+ timestamps cause both neighboring cores to keep or discard the same occurrence.
18
+ Match occurrences one-to-one; preserve real repeated speech and leave ambiguous
19
+ collapsed repetitions untouched rather than using global text deduplication.
20
+ - Persist raw boundary context in Whistle progress schema 2 so resumed assembly
21
+ matches uninterrupted output. Old schema-1 partial runs require a fresh start;
22
+ completed jobs remain unchanged. Default engine remains Whistle.
23
+ - The native 30-second omission cases remain reproducible upstream; shorter
24
+ input windows and anchored gap checks mitigate them in TextFlowKit without
25
+ changing the engine or model weights.
26
+ - Verification on one four-hour public meeting (1310 native cores, 18 min 34 s
27
+ native decode, 34,723 final words): the two long missing passages were
28
+ restored (2 to 50 and 0 to 47 words), 62 short-gap checks accepted 7 for 53
29
+ added words, resume after cores 350 and 700 reproduced exact word text and
30
+ timings, and no invalid bounds or backwards starts remained. Focused suite:
31
+ 113 passed. Full suite: 2,097 passed, 18 skipped; skips are not passes. This is
32
+ coverage evidence for one recording, not human WER or perfect accuracy; normal
33
+ spelling errors remain. See
34
+ [the verification note](docs/verification/whistle-coverage-20261019.md).
35
+
36
+ - Package matching FFmpeg sources, pinned build recipes, dependency archives and full notices alongside the Windows installer; record source hashes and preserve compatible DLL replacement. See [source verification](docs/verification/windows-sources-20261019.md).
37
+
38
+ ## v0.1.12 — 2026-10-17
39
+
40
+ Core: 0.1.12; unchanged optional fonts: 0.1.6. The native Windows installer has been built and tested locally. The installer recipe ships in v0.1.12; the EXE remains local-only until unresolved corresponding-source compliance review is cleared. No public installer download link is available.
41
+
42
+ ### Optional local UI proofreading (v0.1.12)
43
+
44
+ - Add explicit post-transcription local Ollama proofreading with an installed-tag
45
+ picker; prefer `qwen3.5:9b` only when installed (size/performance fit unverified),
46
+ otherwise require selection.
47
+ No model downloads, cloud tags, paid provider, telemetry or new package dependency.
48
+ - Preserve original jobs and exports; persist a separate original-hash-bound AI
49
+ variant with provider/model/time provenance, source segment IDs/timestamps, no
50
+ inherited word alignment, comparison/original-only views and corrected TXT/copy.
51
+ - Bound background work and validate complete JSON/segment coverage atomically.
52
+ One cleanup at a time; fail without partial output. Normal shutdown drains work;
53
+ interrupted leases expire. AI corrections require human review.
54
+
55
+ - Validation history: the first cold full-UI attempt ended in a generic error; a
56
+ later hot 39-segment run returned zero edits despite clear spelling errors.
57
+ Final cold run (model explicitly unloaded first) completed all 39 segments in
58
+ three chunks with four changed segments at 2026-10-16 17:39:52 UTC. The original
59
+ SQLite JSON/source and IDs/timestamps matched; visible side-by-side review and
60
+ corrected TXT save were verified, with the saved file hash matching the variant.
61
+ This proves workflow completion for one run, not accuracy; “fundamental” and
62
+ “victims” were plausible guesses not verified against audio. Review against audio.
63
+
64
+ ### Native Windows installer
65
+
66
+ - Package the existing local browser UI in a native per-user installer for core
67
+ v0.1.12. Built and tested locally; public EXE publication remains gated on
68
+ corresponding-source compliance review. No public installer link is available.
69
+ - Bundle: private embeddable CPython, the UI and HTTP, export, and
70
+ streaming dependencies, the pinned Whistle model and runtime, and ffmpeg,
71
+ ffprobe, and Node. The installer is designed to need no separate Python, WSL,
72
+ or Docker installation.
73
+ - Prebundled Whistle assets and media binaries mean local file jobs need no
74
+ first-use asset download. URL media still needs network access. The default
75
+ Whistle engine supports only these seven advertised languages: `en`, `de`,
76
+ `fr`, `es`, `it`, `nl`, and `pl`.
77
+ - Per-user setup with a Start Menu entry and optional desktop shortcut; launch
78
+ starts the loopback server and opens the existing UI in the browser. It normally
79
+ needs no administrator rights, changes no global `PATH`, and has no automatic
80
+ updates.
81
+ - Keep UI data outside the app install directory and preserve it on upgrade and
82
+ uninstall. Stop server and wait before upgrade or uninstall; the candidate will
83
+ block while it is running rather than force-kill active jobs. Stop server drains
84
+ jobs, so cancel one first if it should not finish.
85
+ - Do not bundle optional `openai-whisper` or diarization dependencies; their
86
+ documented optional paths remain available through the Python package. Bundled
87
+ streaming dependencies do not change the opt-in default; physical browser
88
+ microphone capture remains unverified.
89
+ - The installer bundle includes third-party license and notice files,
90
+ including FFmpeg LGPL notices and corresponding-source information. Verify
91
+ exact notices and source-distribution details against final binaries before
92
+ publication.
93
+ - The candidate is unsigned, so Windows may show a SmartScreen warning.
94
+
3
95
  ## v0.1.11 — 2026-10-06
4
96
 
5
97
  Optional native live streaming supports **Windows x86_64 only**. Core version:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: textflowkit
3
- Version: 0.1.11
3
+ Version: 0.1.13
4
4
  Summary: Cross-platform media transcription toolkit: URL or file in, timestamped transcripts and subtitle files out.
5
5
  Project-URL: Homepage, https://www.textflowkit.org/
6
6
  Project-URL: Issues, https://github.com/scottconverse/textflowkit/issues
@@ -73,7 +73,7 @@ Cross-platform media transcription toolkit. **One core, one CLI, thin adapters.*
73
73
  [User manual](https://github.com/scottconverse/textflowkit/blob/main/docs/user-manual.md) ·
74
74
  [Developer and integration manual](https://github.com/scottconverse/textflowkit/blob/main/docs/adapters.md)
75
75
 
76
- **Current release: [v0.1.11](https://github.com/scottconverse/textflowkit/releases/tag/v0.1.11).**
76
+ **Current release: [v0.1.13](https://github.com/scottconverse/textflowkit/releases/tag/v0.1.13).**
77
77
 
78
78
  The [static site deployment](https://github.com/scottconverse/textflowkit/blob/main/docs/site-deployment.md) is hosted on Cloudflare
79
79
  Pages. GitHub remains the source and CI host; the website does not run the
@@ -134,7 +134,7 @@ DOCX and PDF are available through the optional `export` extra.
134
134
 
135
135
  ## Architecture
136
136
 
137
- ![TextFlowKit shared-core architecture: five thin entry points feed one core. The CLI, Python API, MCP, HTTP API, and the local browser UI (a fifth door that mounts the existing HTTP app under /api and shares the same job store, adding transport only, not a new pipeline) sit above one core that acquires and decodes media, transcribes with the default Whistle engine or an explicitly selected openai-whisper, keeps job state and resume checkpoints in an optional SQLite store, adds optional speaker or translation postprocessing, and publishes TXT, SRT, VTT, JSON, Markdown, and optional DOCX/PDF exports.](https://raw.githubusercontent.com/scottconverse/textflowkit/v0.1.11/docs/assets/architecture-overview.svg)
137
+ ![TextFlowKit shared-core architecture: five thin entry points feed one core. The CLI, Python API, MCP, HTTP API, and the local browser UI (a fifth door that mounts the existing HTTP app under /api and shares the same job store, adding transport only, not a new pipeline) sit above one core that acquires and decodes media, transcribes with the default Whistle engine or an explicitly selected openai-whisper, keeps job state and resume checkpoints in an optional SQLite store, adds optional speaker or translation postprocessing, and publishes TXT, SRT, VTT, JSON, Markdown, and optional DOCX/PDF exports.](https://raw.githubusercontent.com/scottconverse/textflowkit/v0.1.13/docs/assets/architecture-overview.svg)
138
138
 
139
139
  The design principle is **one shared core, thin doors**. Everything of substance
140
140
  lives in the core; the interfaces are thin — the local browser UI is a fifth door
@@ -158,7 +158,7 @@ see [docs/architecture.md](https://github.com/scottconverse/textflowkit/blob/mai
158
158
 
159
159
  ## Live microphone streaming (opt-in)
160
160
 
161
- In v0.1.11, live streaming supports **Windows x86_64 only**. When
161
+ In v0.1.13, live streaming supports **Windows x86_64 only**. When
162
162
  `TEXTFLOWKIT_STREAMING=1` is set, the developer HTTP app serves a `/stream`
163
163
  WebSocket and the local UI serves `/api/stream`, both transcribing a live microphone
164
164
  as you speak. A **runnable, self-hosted browser example** ships at
@@ -167,7 +167,7 @@ as you speak. A **runnable, self-hosted browser example** ships at
167
167
  No CDN, no analytics, no external fetch. Requires the `streaming` extra:
168
168
 
169
169
  ```bash
170
- python -m pip install "textflowkit[streaming]==0.1.11"
170
+ python -m pip install "textflowkit[streaming]==0.1.13"
171
171
  ```
172
172
 
173
173
  It is **off by default** — with the switch unset the endpoint does not exist — and
@@ -233,6 +233,40 @@ installs `textflowkit-fonts` for offline multilingual PDF rendering:
233
233
  python -m pip install 'textflowkit[export]'
234
234
  ```
235
235
 
236
+ ## Windows desktop installer (v0.1.13)
237
+
238
+ [Download Windows x64 setup](https://github.com/scottconverse/textflowkit/releases/download/v0.1.13/TextFlowKit-0.1.13-windows-x64-setup.exe) · [Matching sources and notices](https://github.com/scottconverse/textflowkit/releases/tag/v0.1.13)
239
+
240
+ An installer for the existing local browser workspace accompanies core v0.1.13. The Windows installer and its matching FFmpeg source and notice bundles are distributed together through the [v0.1.13 release](https://github.com/scottconverse/textflowkit/releases/tag/v0.1.13). The Python package remains supported for developers and integrations.
241
+
242
+ The installer is designed to run without a separately installed Python, WSL, or
243
+ Docker. Its bundle includes a private embeddable CPython runtime, the
244
+ browser UI and HTTP, export, and streaming dependencies, the pinned Whistle model
245
+ and runtime, and ffmpeg, ffprobe, and Node. The setup installs per user,
246
+ creates a Start Menu shortcut, and offers an optional desktop shortcut. Opening
247
+ the shortcut will start the local server and open the existing browser UI at
248
+ localhost. It is designed to need no administrator rights in normal use, change
249
+ no global `PATH`, and avoid automatic updates.
250
+
251
+ The pinned Whistle assets and media binaries are prebundled, so local file jobs
252
+ need no first-use asset download. URL sources still need their normal network
253
+ access. The default Whistle engine supports only these seven advertised languages:
254
+ `en`, `de`, `fr`, `es`, `it`, `nl`, and `pl`. Optional `openai-whisper` and diarization dependencies are not
255
+ bundled; those features remain documented for the Python package when separately
256
+ installed and configured. Streaming dependencies are bundled, but live streaming
257
+ remains opt-in and physical browser microphone capture has not been verified.
258
+
259
+ The installer is designed to keep UI data outside the application install
260
+ directory and preserve it on upgrades and uninstall. Stop the UI server with
261
+ **Stop server** and wait for it to exit before upgrading or uninstalling; the
262
+ installer will block while it is running rather than force-killing active jobs.
263
+ Cancel a job first if it should not drain to completion. The bundle also
264
+ includes third-party license and notice files, including FFmpeg's LGPL notices
265
+ and corresponding-source information. Check exact notices and source-distribution
266
+ details in the matching source bundles distributed with this release. The installer is
267
+ unsigned, so Windows may show a SmartScreen warning. See the [installer candidate
268
+ notes](https://github.com/scottconverse/textflowkit/blob/main/docs/install.md#windows-desktop-installer-v0113).
269
+
236
270
  ## Python API
237
271
 
238
272
  The same pipeline used by the CLI and adapters is available to Python callers:
@@ -328,7 +362,7 @@ textflowkit export ./transcript.json --format vtt
328
362
  needs no PyTorch, so a fresh `pip install textflowkit` stays small and pulls no
329
363
  torch; `openai-whisper` is an explicitly selectable opt-in engine.
330
364
 
331
- ![Whistle bounded block run and durable resume: a decoded PCM WAV is split into 26-second cores with up to 2 seconds of context (each clip ≤ 30 s), each core runs as one owned child with forced telemetry-off flags, a partial checkpoint is written after each core, and a resume validates the source and decoded-WAV hashes then re-runs only the unfinished cores.](https://raw.githubusercontent.com/scottconverse/textflowkit/v0.1.11/docs/assets/whistle-resume.svg)
365
+ ![Whistle bounded block run and durable resume: a decoded PCM WAV is split into 11-second cores with up to 2 seconds of context (each clip ≤ 15 s), each core runs as one owned child with forced telemetry-off flags, a partial checkpoint is written after each core, and a resume validates the source and decoded-WAV hashes then re-runs only the unfinished cores.](https://raw.githubusercontent.com/scottconverse/textflowkit/v0.1.13/docs/assets/whistle-resume.svg)
332
366
 
333
367
  - **CPU only, no torch.** It runs a pinned native binary and downloads one pinned
334
368
  model on first use. Naming a GPU device is refused rather than silently
@@ -341,16 +375,26 @@ torch; `openai-whisper` is an explicitly selectable opt-in engine.
341
375
  Apple Silicon. **Intel Macs are not supported**; a request there is refused
342
376
  with a message that names the explicit `whisper` engine instead. No WSL layer
343
377
  is involved.
344
- - **How it works:** long audio is split into 26-second cores with up to 2 seconds
345
- of context on each side, so every standalone clip is ≤ 30 seconds (the native
346
- CLI's limit). Overlap words are selected by core midpoint rather than text
347
- deduplication, so repeated spoken phrases are preserved.
378
+ - **How it works:** long audio is split into 11-second cores with up to 2 seconds
379
+ of context on each side, so every standalone clip is ≤ 15 seconds. This conservative
380
+ ceiling avoids reproduced omissions on 30-second inputs. Midpoints provide initial ownership; shared-context matching
381
+ reconciles duplicate or dropped occurrences when neighboring timestamps
382
+ disagree. This is not global text deduplication: real repetitions and ambiguous
383
+ recognition are preserved. The 15-second ceiling and this assembly behavior ship
384
+ in v0.1.13; neither recovers speech the native recognizer never emits.
385
+ - **Speech-gap check (v0.1.13).** Short gaps between recognized words receive a
386
+ bounded second listen with different clip boundaries. Extra words are accepted
387
+ only between matching words on both sides at nearby times. Existing words and
388
+ repetitions stay intact; long pauses do not trigger this check. The model is
389
+ still Whistle, with the same pinned weights and telemetry settings.
348
390
  - **Standalone streaming is not used.** The native `--audio-stream` mode failed its
349
391
  coverage and is never passed; only the committed standalone output is parsed.
350
392
  - **Durable block resume.** With `TEXTFLOWKIT_DB` set, a long run writes partial
351
393
  per-block checkpoints; a resume checks the source and decoded-WAV hashes and the
352
394
  config, then re-runs only the blocks that were not finished. The durable store
353
- still assumes one owning process.
395
+ still assumes one owning process. The v0.1.13 assembly policy saves raw
396
+ boundary context with schema 2; old schema-1 partial runs must be restarted,
397
+ not resumed under the new assembly policy. Existing completed jobs are unchanged.
354
398
  - **Cancellation.** A running Whistle run terminates its exact owned child
355
399
  process bounded by a per-clip timeout. A single long `openai-whisper` model call
356
400
  is still only cancellable at its next stage boundary, as documented for the
@@ -439,7 +483,7 @@ its own beyond the `http` extra. It ships with the core package as of v0.1.10:
439
483
  a regular install of the current release carries it.
440
484
 
441
485
  ```bash
442
- python -m pip install 'textflowkit[http,export]==0.1.11'
486
+ python -m pip install 'textflowkit[http,export]==0.1.13'
443
487
  textflowkit-ui
444
488
  ```
445
489
 
@@ -510,7 +554,17 @@ browser interface share the job contract without blocking a request.
510
554
 
511
555
  ## Status
512
556
 
513
- **v0.1.11 release.** Optional live streaming adds a transport-neutral
557
+ **v0.1.13 release.** Fixes reproduced Whistle speech omissions. Native decode
558
+ inputs are now bounded to 15 seconds (11-second owned cores with up to 2 seconds
559
+ of context per side), short interior speech gaps get a bounded second listen that
560
+ accepts words only between matching timed anchors, and shared-context words are
561
+ reconciled one-to-one before durable resume. Whistle remains the default engine
562
+ with the same pinned model and runtime; fonts remain 0.1.6. Progress schema 2
563
+ stores raw boundary context, so an unfinished partial job from the previous
564
+ 26-second-core plan (schema 1) must be restarted instead of resumed; completed
565
+ records are unchanged. The native Windows installer is rebuilt at v0.1.13 and
566
+ distributed with matching FFmpeg sources, notices, hashes and build instructions.
567
+ Existing optional live streaming provides a transport-neutral
514
568
  `StreamingSession` Python API, incremental transcript events, and authenticated
515
569
  loopback WebSockets (`/stream` on the developer HTTP API and `/api/stream` on the
516
570
  local UI), with a packaged browser microphone example. The native live capability
@@ -532,6 +586,22 @@ Linux/macOS, and the six other accepted languages were not verified. The public
532
586
  website remains static documentation and serves no streaming endpoint. Local source
533
587
  validation does not establish published-package or exact-commit CI results.
534
588
 
589
+ **v0.1.12 cleanup (historical).** The opt-in local Ollama proofreading path remains
590
+ as introduced in v0.1.12, covering the local browser UI only; it was not changed by
591
+ v0.1.13. It keeps the published 39-segment cleanup proof from v0.1.12 with no
592
+ audio-accuracy claim: that proof records segment/format handling, not recognition
593
+ accuracy.
594
+
595
+ **v0.1.13 Whistle coverage, omission, and resume.** The 15-second bound (11-second
596
+ cores plus up to 2 s context per side) fixes reproduced speech omissions on
597
+ 30-second inputs; the interior speech-gap second listen accepts extra words only
598
+ between matching timed anchors; shared-context words are reconciled one-to-one
599
+ before durable resume so a partial run rejoins without double ownership. Recognized
600
+ language coverage remains the same accepted set, and nothing here recovers speech
601
+ the native recognizer never emits. See
602
+ [docs/verification/whistle-coverage-20261019.md](https://github.com/scottconverse/textflowkit/blob/main/docs/verification/whistle-coverage-20261019.md)
603
+ for the run-by-run coverage, omission, and resume evidence.
604
+
535
605
  **Verification limit.** The local browser interface is covered by an automated
536
606
  suite, and the UI's behavior was proved on a **native Windows** machine in a real
537
607
  browser. No live optional-backend (translation/diarization) run through the UI is
@@ -554,7 +624,7 @@ MCP speech, seven-format exports and completed resume; the v0.1.8 runtime fixes
554
624
  were independently checked through fresh-process CLI restart probes, real SQLite
555
625
  setup-failure tests, and the full Windows test suite. Those checks are not new
556
626
  individual-harness receipts. That is the previous releases' record, not evidence
557
- for v0.1.11.
627
+ for v0.1.13.
558
628
 
559
629
  The v0.1.6 release was the post-v0.1.5 review repair set: security hardening
560
630
  for media acquisition and the HTTP and MCP adapters, safer subtitle wrapping and
@@ -573,7 +643,7 @@ and both [core](https://pypi.org/project/textflowkit/0.1.6/) and
573
643
  [fonts](https://pypi.org/project/textflowkit-fonts/0.1.6/) PyPI projects are
574
644
  live — that is the v0.1.6 release's evidence, not a receipt for a later release.
575
645
  Everything from here to the end of this section is the v0.1.6 release's
576
- historical record as published: it is not re-verified for v0.1.11, whose separate release evidence is not supplied by these historical paragraphs.
646
+ historical record as published: it is not re-verified for v0.1.13, whose separate release evidence is not supplied by these historical paragraphs.
577
647
  Merged-main CI passed 16/16 on the tagged commit; the published wheel and
578
648
  sdist digests match the GitHub release assets and their SHA-256 list; and a fresh
579
649
  Windows Python 3.12 install of `textflowkit[export,mcp,http]==0.1.6` from PyPI
@@ -610,3 +680,90 @@ limitation of liability.
610
680
 
611
681
  Issues and PRs welcome. Please read [LEGAL.md](https://github.com/scottconverse/textflowkit/blob/main/LEGAL.md) before adding a source
612
682
  adapter.
683
+
684
+
685
+ ## Optional local AI transcript cleanup (introduced in v0.1.12)
686
+
687
+ v0.1.12 adds **opt-in proofreading in the local browser UI only** (introduced in v0.1.12; unchanged in v0.1.13). After a transcription finishes, choose an
688
+ installed local Ollama model and click **Proofread with local AI**. Cleanup never
689
+ runs automatically. Ollama and cleanup models are not bundled in the installer.
690
+ The optional default preference is `qwen3.5:9b` only if already installed; its
691
+ size/performance fit has not been verified. Otherwise choose an installed local
692
+ model explicitly, such as `qwen3.8:27b-q4_K_M`. Larger models are never silently
693
+ selected. Install a model yourself through Ollama when needed; TextFlowKit does
694
+ not pull models, enable cloud tags, or use a paid provider.
695
+
696
+ The original transcript, job JSON, original copy button, search, and all existing
697
+ exports remain unchanged. Choose **Original only** or compare **source original
698
+ (left) / AI corrected (right)** in timestamp-anchored rows. Use **Copy corrected
699
+ text** or **Save corrected TXT** for the separate AI variant. The comparison
700
+ proofreads original source speech, not an optional translation. AI can make
701
+ plausible but wrong corrections, including names and facts: review against the
702
+ original and audio before using it. Prompt instructions reduce errors but do not
703
+ guarantee accuracy or resistance to instructions embedded in speech.
704
+
705
+ Corrected segments retain source start/end timestamps and stable zero-based
706
+ original segment indices. They have no inherited word alignment or translation;
707
+ **corrected word timing is not verified**. A separate persisted variant records
708
+ local provider, requested/returned model, UTC completion time, endpoint, successful
709
+ `done_reason=stop`, policy version and original SHA-256. If original job JSON
710
+ changes, its correction is invalidated. No partial replacement is published: bad,
711
+ truncated, missing, duplicated, reordered or extra segments fail the entire attempt.
712
+ A failed retry retains an earlier fully validated variant only if its original
713
+ hash still matches.
714
+
715
+ Cleanup uses a separate SQLite file named `<job database filename>.cleanup.sqlite3`
716
+ beside `TEXTFLOWKIT_DB` (or the UI default database). Include it when backing up UI
717
+ data; it contains transcript text and provenance. The canonical job store is never
718
+ updated by cleanup. Reloading/reopening a completed job retrieves its saved variant,
719
+ even if Ollama is offline. Model selection is per attempt; it is not a global
720
+ transcription/translation model setting.
721
+
722
+ Configuration is process-local environment, consistent with the existing UI:
723
+
724
+ - `TEXTFLOWKIT_CLEANUP_OLLAMA_URL`: default `http://127.0.0.1:11434`; only HTTP on
725
+ a literal loopback IP and explicit port is accepted (IPv6 `[::1]` also works).
726
+ DNS names, credentials, other paths, remote hosts and redirects are refused;
727
+ proxy environment variables are ignored by the cleanup client.
728
+ - `TEXTFLOWKIT_CLEANUP_MODEL`: optional preferred installed local tag; defaults
729
+ to `qwen3.5:9b`. If absent from installed tags, explicit selection is required.
730
+ Cloud tags and Ollama remote-model metadata are refused.
731
+
732
+ One cleanup runs at a time; the browser polls a background worker and remains
733
+ usable. Limits: 2,000 segments, 120,000 source characters, 60 chunks, at most
734
+ 1,000 UTF-8 encoded bytes per chunk and 40 segments per chunk. A small read-only
735
+ neighboring context helps with sentences spanning segments without merging them.
736
+ Generation requests use temperature 0, thinking disabled, context 8,192 and at
737
+ most 4,096 generated tokens per chunk. Requests have a 180-second socket timeout,
738
+ bounded response reads (1 MiB), and strict 64 KiB model JSON limits. The overall
739
+ work budget remains 600 seconds, checked between requests and reads; a blocking
740
+ socket operation can take up to its remaining request timeout before failure is
741
+ observed. Oversize or timeout failures leave the original available.
742
+
743
+ Normal UI shutdown drains an active cleanup (it can take several minutes); there
744
+ is no cleanup cancellation button. Abrupt process exit leaves no partial variant;
745
+ an interrupted running lease becomes retryable after at most 785 seconds from its
746
+ start. Cleanup does not restart Ollama or stop/unload other models. Model text is
747
+ rendered with DOM text nodes, never HTML. Cleanup adds no Python dependency,
748
+ telemetry, cloud provider or network destination beyond the configured local
749
+ Ollama service. Existing media acquisition/translation network behavior is separate.
750
+
751
+ ### Candidate validation status
752
+
753
+ The first cold full-UI attempt ended with a generic error and produced no variant;
754
+ the original remained intact. A subsequent hot 39-segment run returned zero text
755
+ edits despite clear source spelling errors, so it was not useful cleanup-quality
756
+ evidence. The final cold run began with the model explicitly unloaded and
757
+ completed all 39 segments in three chunks at
758
+ 2026-10-16 17:39:52 UTC. It used matching requested/returned
759
+ `qwen3.8:27b-q4_K_M` and changed four segments. The original SQLite JSON matched
760
+ the source file, with segment IDs and timestamps preserved. The in-app-browser
761
+ side-by-side comparison was visible, and **Save corrected TXT** produced a
762
+ 2,516-byte file whose SHA-256 matched the validated variant.
763
+
764
+ Observed edits included “guardrails,” “precludes,” and punctuation. “Fundamental”
765
+ and “victims” were plausible guesses, not verified against the audio. This is
766
+ measured evidence that the local full workflow completed and saved its separate
767
+ variant for this run; it does not establish transcription accuracy or general
768
+ cleanup quality. Review every correction against the audio. This is local workflow evidence,
769
+ not an audio-accuracy certification.