thth 2.13.1__tar.gz → 2.13.2__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 (456) hide show
  1. {thth-2.13.1 → thth-2.13.2}/PKG-INFO +1 -1
  2. thth-2.13.2/tests/test_v2132_send_inflight_hint.py +67 -0
  3. thth-2.13.2/tests/test_v2132_threads_create_timeout.py +84 -0
  4. thth-2.13.2/tests/test_v2132_threads_create_unknown.py +90 -0
  5. thth-2.13.2/thth/VERSION +1 -0
  6. {thth-2.13.1 → thth-2.13.2}/thth/adapters/threads_media.py +60 -10
  7. {thth-2.13.1 → thth-2.13.2}/thth/cli.py +6 -0
  8. {thth-2.13.1 → thth-2.13.2}/thth/core.py +6 -1
  9. {thth-2.13.1 → thth-2.13.2}/thth/inflight.py +10 -0
  10. {thth-2.13.1 → thth-2.13.2}/thth/media_delivery.py +4 -0
  11. thth-2.13.1/thth/VERSION +0 -1
  12. {thth-2.13.1 → thth-2.13.2}/.gitignore +0 -0
  13. {thth-2.13.1 → thth-2.13.2}/LICENSE +0 -0
  14. {thth-2.13.1 → thth-2.13.2}/README.md +0 -0
  15. {thth-2.13.1 → thth-2.13.2}/accounts.example/bluesky.json +0 -0
  16. {thth-2.13.1 → thth-2.13.2}/accounts.example/mastodon.json +0 -0
  17. {thth-2.13.1 → thth-2.13.2}/accounts.example/threads.json +0 -0
  18. {thth-2.13.1 → thth-2.13.2}/accounts.example/x.json +0 -0
  19. {thth-2.13.1 → thth-2.13.2}/bin/thth +0 -0
  20. {thth-2.13.1 → thth-2.13.2}/bin/thth-remote +0 -0
  21. {thth-2.13.1 → thth-2.13.2}/bin/thth-run +0 -0
  22. {thth-2.13.1 → thth-2.13.2}/mcp/server.py +0 -0
  23. {thth-2.13.1 → thth-2.13.2}/pyproject.toml +0 -0
  24. {thth-2.13.1 → thth-2.13.2}/skills/thth/SKILL.md +0 -0
  25. {thth-2.13.1 → thth-2.13.2}/skills/thth-admin/SKILL.md +0 -0
  26. {thth-2.13.1 → thth-2.13.2}/systemd/thth@.service +0 -0
  27. {thth-2.13.1 → thth-2.13.2}/tests/__init__.py +0 -0
  28. {thth-2.13.1 → thth-2.13.2}/tests/conftest.py +0 -0
  29. {thth-2.13.1 → thth-2.13.2}/tests/coordination_snapshot.py +0 -0
  30. {thth-2.13.1 → thth-2.13.2}/tests/fixtures/GraphemeBreakTest-17.0.0.txt +0 -0
  31. {thth-2.13.1 → thth-2.13.2}/tests/fixtures/build_injection_eval.py +0 -0
  32. {thth-2.13.1 → thth-2.13.2}/tests/fixtures/callback/worker_responses.json +0 -0
  33. {thth-2.13.1 → thth-2.13.2}/tests/fixtures/injection_eval.json +0 -0
  34. {thth-2.13.1 → thth-2.13.2}/tests/fixtures/umami-bile.md +0 -0
  35. {thth-2.13.1 → thth-2.13.2}/tests/helpers/__init__.py +0 -0
  36. {thth-2.13.1 → thth-2.13.2}/tests/helpers/fake_oauth_server.py +0 -0
  37. {thth-2.13.1 → thth-2.13.2}/tests/helpers/fake_push_adapter.py +0 -0
  38. {thth-2.13.1 → thth-2.13.2}/tests/helpers/fake_redirect_server.py +0 -0
  39. {thth-2.13.1 → thth-2.13.2}/tests/helpers/fake_search_adapter.py +0 -0
  40. {thth-2.13.1 → thth-2.13.2}/tests/helpers/fake_threads_reader.py +0 -0
  41. {thth-2.13.1 → thth-2.13.2}/tests/helpers/fake_threads_writes.py +0 -0
  42. {thth-2.13.1 → thth-2.13.2}/tests/helpers/hold_lock.py +0 -0
  43. {thth-2.13.1 → thth-2.13.2}/tests/helpers/hold_repo_lock.py +0 -0
  44. {thth-2.13.1 → thth-2.13.2}/tests/helpers/worker_probe.mjs +0 -0
  45. {thth-2.13.1 → thth-2.13.2}/tests/test_27_acceptance_fixes.py +0 -0
  46. {thth-2.13.1 → thth-2.13.2}/tests/test_account_name_check.py +0 -0
  47. {thth-2.13.1 → thth-2.13.2}/tests/test_account_report.py +0 -0
  48. {thth-2.13.1 → thth-2.13.2}/tests/test_accounts_dir.py +0 -0
  49. {thth-2.13.1 → thth-2.13.2}/tests/test_adapter_boundary.py +0 -0
  50. {thth-2.13.1 → thth-2.13.2}/tests/test_admin_http_mcp.py +0 -0
  51. {thth-2.13.1 → thth-2.13.2}/tests/test_admin_log.py +0 -0
  52. {thth-2.13.1 → thth-2.13.2}/tests/test_admin_notifications.py +0 -0
  53. {thth-2.13.1 → thth-2.13.2}/tests/test_admin_repairs.py +0 -0
  54. {thth-2.13.1 → thth-2.13.2}/tests/test_admin_report.py +0 -0
  55. {thth-2.13.1 → thth-2.13.2}/tests/test_after_cli.py +0 -0
  56. {thth-2.13.1 → thth-2.13.2}/tests/test_analytics_comparison.py +0 -0
  57. {thth-2.13.1 → thth-2.13.2}/tests/test_analytics_report.py +0 -0
  58. {thth-2.13.1 → thth-2.13.2}/tests/test_api_diagnostic.py +0 -0
  59. {thth-2.13.1 → thth-2.13.2}/tests/test_api_error_body.py +0 -0
  60. {thth-2.13.1 → thth-2.13.2}/tests/test_app_env_cli.py +0 -0
  61. {thth-2.13.1 → thth-2.13.2}/tests/test_approval.py +0 -0
  62. {thth-2.13.1 → thth-2.13.2}/tests/test_approve_cmd.py +0 -0
  63. {thth-2.13.1 → thth-2.13.2}/tests/test_ask.py +0 -0
  64. {thth-2.13.1 → thth-2.13.2}/tests/test_atlas_fifth_review.py +0 -0
  65. {thth-2.13.1 → thth-2.13.2}/tests/test_atlas_fourth_review.py +0 -0
  66. {thth-2.13.1 → thth-2.13.2}/tests/test_atlas_review.py +0 -0
  67. {thth-2.13.1 → thth-2.13.2}/tests/test_atlas_second_review.py +0 -0
  68. {thth-2.13.1 → thth-2.13.2}/tests/test_atlas_third_review.py +0 -0
  69. {thth-2.13.1 → thth-2.13.2}/tests/test_audit1_fixes.py +0 -0
  70. {thth-2.13.1 → thth-2.13.2}/tests/test_audit2_fixes.py +0 -0
  71. {thth-2.13.1 → thth-2.13.2}/tests/test_audit_b_counterexamples.py +0 -0
  72. {thth-2.13.1 → thth-2.13.2}/tests/test_audit_b_m1_semantics.py +0 -0
  73. {thth-2.13.1 → thth-2.13.2}/tests/test_audit_b_n1_depth.py +0 -0
  74. {thth-2.13.1 → thth-2.13.2}/tests/test_audit_b_r1_closure.py +0 -0
  75. {thth-2.13.1 → thth-2.13.2}/tests/test_audit_v201.py +0 -0
  76. {thth-2.13.1 → thth-2.13.2}/tests/test_audit_v23_details.py +0 -0
  77. {thth-2.13.1 → thth-2.13.2}/tests/test_auth.py +0 -0
  78. {thth-2.13.1 → thth-2.13.2}/tests/test_auth_identity_required.py +0 -0
  79. {thth-2.13.1 → thth-2.13.2}/tests/test_behind_remote.py +0 -0
  80. {thth-2.13.1 → thth-2.13.2}/tests/test_bluesky_adapter.py +0 -0
  81. {thth-2.13.1 → thth-2.13.2}/tests/test_bluesky_secret_scrub.py +0 -0
  82. {thth-2.13.1 → thth-2.13.2}/tests/test_board_needs_review.py +0 -0
  83. {thth-2.13.1 → thth-2.13.2}/tests/test_board_running.py +0 -0
  84. {thth-2.13.1 → thth-2.13.2}/tests/test_bundle.py +0 -0
  85. {thth-2.13.1 → thth-2.13.2}/tests/test_charcount.py +0 -0
  86. {thth-2.13.1 → thth-2.13.2}/tests/test_cli_entrypoint.py +0 -0
  87. {thth-2.13.1 → thth-2.13.2}/tests/test_cli_help.py +0 -0
  88. {thth-2.13.1 → thth-2.13.2}/tests/test_cli_vm_path.py +0 -0
  89. {thth-2.13.1 → thth-2.13.2}/tests/test_collect.py +0 -0
  90. {thth-2.13.1 → thth-2.13.2}/tests/test_collect_engagements.py +0 -0
  91. {thth-2.13.1 → thth-2.13.2}/tests/test_collect_runs.py +0 -0
  92. {thth-2.13.1 → thth-2.13.2}/tests/test_collect_sent.py +0 -0
  93. {thth-2.13.1 → thth-2.13.2}/tests/test_comparability.py +0 -0
  94. {thth-2.13.1 → thth-2.13.2}/tests/test_control_chars_refused.py +0 -0
  95. {thth-2.13.1 → thth-2.13.2}/tests/test_conversation_paging.py +0 -0
  96. {thth-2.13.1 → thth-2.13.2}/tests/test_count_for.py +0 -0
  97. {thth-2.13.1 → thth-2.13.2}/tests/test_docs_links.py +0 -0
  98. {thth-2.13.1 → thth-2.13.2}/tests/test_doctor.py +0 -0
  99. {thth-2.13.1 → thth-2.13.2}/tests/test_doctor_all_permissions.py +0 -0
  100. {thth-2.13.1 → thth-2.13.2}/tests/test_doctor_next_step.py +0 -0
  101. {thth-2.13.1 → thth-2.13.2}/tests/test_duplicate_front_matter_keys.py +0 -0
  102. {thth-2.13.1 → thth-2.13.2}/tests/test_editorial_audit.py +0 -0
  103. {thth-2.13.1 → thth-2.13.2}/tests/test_editorial_n3_n4.py +0 -0
  104. {thth-2.13.1 → thth-2.13.2}/tests/test_engagements.py +0 -0
  105. {thth-2.13.1 → thth-2.13.2}/tests/test_external_acceptance.py +0 -0
  106. {thth-2.13.1 → thth-2.13.2}/tests/test_fake_api.py +0 -0
  107. {thth-2.13.1 → thth-2.13.2}/tests/test_form_spec.py +0 -0
  108. {thth-2.13.1 → thth-2.13.2}/tests/test_form_spec_cli.py +0 -0
  109. {thth-2.13.1 → thth-2.13.2}/tests/test_forms.py +0 -0
  110. {thth-2.13.1 → thth-2.13.2}/tests/test_fresh_install.py +0 -0
  111. {thth-2.13.1 → thth-2.13.2}/tests/test_front_matter_injection.py +0 -0
  112. {thth-2.13.1 → thth-2.13.2}/tests/test_healthcheck_notifications.py +0 -0
  113. {thth-2.13.1 → thth-2.13.2}/tests/test_hypotheses.py +0 -0
  114. {thth-2.13.1 → thth-2.13.2}/tests/test_hypothesis_boundaries.py +0 -0
  115. {thth-2.13.1 → thth-2.13.2}/tests/test_hypothesis_units.py +0 -0
  116. {thth-2.13.1 → thth-2.13.2}/tests/test_impact_cli.py +0 -0
  117. {thth-2.13.1 → thth-2.13.2}/tests/test_inbox_granted_scopes.py +0 -0
  118. {thth-2.13.1 → thth-2.13.2}/tests/test_incident_notifications.py +0 -0
  119. {thth-2.13.1 → thth-2.13.2}/tests/test_independent_thread_review.py +0 -0
  120. {thth-2.13.1 → thth-2.13.2}/tests/test_independent_topic_review.py +0 -0
  121. {thth-2.13.1 → thth-2.13.2}/tests/test_independent_topic_review_r2.py +0 -0
  122. {thth-2.13.1 → thth-2.13.2}/tests/test_inflight.py +0 -0
  123. {thth-2.13.1 → thth-2.13.2}/tests/test_inflight_tag_body_hash.py +0 -0
  124. {thth-2.13.1 → thth-2.13.2}/tests/test_jst.py +0 -0
  125. {thth-2.13.1 → thth-2.13.2}/tests/test_lint.py +0 -0
  126. {thth-2.13.1 → thth-2.13.2}/tests/test_list_projections.py +0 -0
  127. {thth-2.13.1 → thth-2.13.2}/tests/test_llm_trial.py +0 -0
  128. {thth-2.13.1 → thth-2.13.2}/tests/test_llm_trial_engage.py +0 -0
  129. {thth-2.13.1 → thth-2.13.2}/tests/test_lock.py +0 -0
  130. {thth-2.13.1 → thth-2.13.2}/tests/test_m2_independent.py +0 -0
  131. {thth-2.13.1 → thth-2.13.2}/tests/test_maintain.py +0 -0
  132. {thth-2.13.1 → thth-2.13.2}/tests/test_mastodon_adapter.py +0 -0
  133. {thth-2.13.1 → thth-2.13.2}/tests/test_mastodon_visibility.py +0 -0
  134. {thth-2.13.1 → thth-2.13.2}/tests/test_max_per_run.py +0 -0
  135. {thth-2.13.1 → thth-2.13.2}/tests/test_mcp.py +0 -0
  136. {thth-2.13.1 → thth-2.13.2}/tests/test_mcp_robustness.py +0 -0
  137. {thth-2.13.1 → thth-2.13.2}/tests/test_measured.py +0 -0
  138. {thth-2.13.1 → thth-2.13.2}/tests/test_media_accounts.py +0 -0
  139. {thth-2.13.1 → thth-2.13.2}/tests/test_media_next_steps.py +0 -0
  140. {thth-2.13.1 → thth-2.13.2}/tests/test_media_roundtrip.py +0 -0
  141. {thth-2.13.1 → thth-2.13.2}/tests/test_mismatch_diagnostics.py +0 -0
  142. {thth-2.13.1 → thth-2.13.2}/tests/test_n5_reply_null_element.py +0 -0
  143. {thth-2.13.1 → thth-2.13.2}/tests/test_n6_replies_incomplete_ledger.py +0 -0
  144. {thth-2.13.1 → thth-2.13.2}/tests/test_n7_doctor_error_body.py +0 -0
  145. {thth-2.13.1 → thth-2.13.2}/tests/test_no_limits.py +0 -0
  146. {thth-2.13.1 → thth-2.13.2}/tests/test_observation_provenance.py +0 -0
  147. {thth-2.13.1 → thth-2.13.2}/tests/test_operations_handoff.py +0 -0
  148. {thth-2.13.1 → thth-2.13.2}/tests/test_packaging.py +0 -0
  149. {thth-2.13.1 → thth-2.13.2}/tests/test_preview.py +0 -0
  150. {thth-2.13.1 → thth-2.13.2}/tests/test_production_mode.py +0 -0
  151. {thth-2.13.1 → thth-2.13.2}/tests/test_pull_cli.py +0 -0
  152. {thth-2.13.1 → thth-2.13.2}/tests/test_queue.py +0 -0
  153. {thth-2.13.1 → thth-2.13.2}/tests/test_quiet_hours.py +0 -0
  154. {thth-2.13.1 → thth-2.13.2}/tests/test_r2_r4_r5.py +0 -0
  155. {thth-2.13.1 → thth-2.13.2}/tests/test_read_cli_bare_runtimeerror.py +0 -0
  156. {thth-2.13.1 → thth-2.13.2}/tests/test_reason_adoption.py +0 -0
  157. {thth-2.13.1 → thth-2.13.2}/tests/test_redact.py +0 -0
  158. {thth-2.13.1 → thth-2.13.2}/tests/test_redirect_token_leak.py +0 -0
  159. {thth-2.13.1 → thth-2.13.2}/tests/test_refresh.py +0 -0
  160. {thth-2.13.1 → thth-2.13.2}/tests/test_refresh_destination.py +0 -0
  161. {thth-2.13.1 → thth-2.13.2}/tests/test_rejudge_new.py +0 -0
  162. {thth-2.13.1 → thth-2.13.2}/tests/test_rejudge_r2_r3.py +0 -0
  163. {thth-2.13.1 → thth-2.13.2}/tests/test_replies.py +0 -0
  164. {thth-2.13.1 → thth-2.13.2}/tests/test_replies_refresh.py +0 -0
  165. {thth-2.13.1 → thth-2.13.2}/tests/test_repo_lock.py +0 -0
  166. {thth-2.13.1 → thth-2.13.2}/tests/test_repo_sync.py +0 -0
  167. {thth-2.13.1 → thth-2.13.2}/tests/test_report_checkout_import.py +0 -0
  168. {thth-2.13.1 → thth-2.13.2}/tests/test_report_http.py +0 -0
  169. {thth-2.13.1 → thth-2.13.2}/tests/test_report_isolation.py +0 -0
  170. {thth-2.13.1 → thth-2.13.2}/tests/test_report_service.py +0 -0
  171. {thth-2.13.1 → thth-2.13.2}/tests/test_reverse_audit.py +0 -0
  172. {thth-2.13.1 → thth-2.13.2}/tests/test_review_case_id_cluster_m2.py +0 -0
  173. {thth-2.13.1 → thth-2.13.2}/tests/test_review_case_id_cluster_r2.py +0 -0
  174. {thth-2.13.1 → thth-2.13.2}/tests/test_review_cli.py +0 -0
  175. {thth-2.13.1 → thth-2.13.2}/tests/test_review_evidence_account.py +0 -0
  176. {thth-2.13.1 → thth-2.13.2}/tests/test_review_form_spec_and_case_id.py +0 -0
  177. {thth-2.13.1 → thth-2.13.2}/tests/test_review_provenance.py +0 -0
  178. {thth-2.13.1 → thth-2.13.2}/tests/test_review_records.py +0 -0
  179. {thth-2.13.1 → thth-2.13.2}/tests/test_revoke.py +0 -0
  180. {thth-2.13.1 → thth-2.13.2}/tests/test_roundtrip.py +0 -0
  181. {thth-2.13.1 → thth-2.13.2}/tests/test_run_missing_env.py +0 -0
  182. {thth-2.13.1 → thth-2.13.2}/tests/test_run_record_failclosed.py +0 -0
  183. {thth-2.13.1 → thth-2.13.2}/tests/test_runs_collected.py +0 -0
  184. {thth-2.13.1 → thth-2.13.2}/tests/test_runs_read_rows.py +0 -0
  185. {thth-2.13.1 → thth-2.13.2}/tests/test_schedule_multiple.py +0 -0
  186. {thth-2.13.1 → thth-2.13.2}/tests/test_schedule_view.py +0 -0
  187. {thth-2.13.1 → thth-2.13.2}/tests/test_scopes_source_requested.py +0 -0
  188. {thth-2.13.1 → thth-2.13.2}/tests/test_search_engage_targets.py +0 -0
  189. {thth-2.13.1 → thth-2.13.2}/tests/test_search_media_routes.py +0 -0
  190. {thth-2.13.1 → thth-2.13.2}/tests/test_secret_value_redact.py +0 -0
  191. {thth-2.13.1 → thth-2.13.2}/tests/test_secrets_grep.py +0 -0
  192. {thth-2.13.1 → thth-2.13.2}/tests/test_security_small_fixes.py +0 -0
  193. {thth-2.13.1 → thth-2.13.2}/tests/test_select.py +0 -0
  194. {thth-2.13.1 → thth-2.13.2}/tests/test_selfupdate.py +0 -0
  195. {thth-2.13.1 → thth-2.13.2}/tests/test_send.py +0 -0
  196. {thth-2.13.1 → thth-2.13.2}/tests/test_send_cli.py +0 -0
  197. {thth-2.13.1 → thth-2.13.2}/tests/test_send_control_chars.py +0 -0
  198. {thth-2.13.1 → thth-2.13.2}/tests/test_send_media.py +0 -0
  199. {thth-2.13.1 → thth-2.13.2}/tests/test_send_visibility.py +0 -0
  200. {thth-2.13.1 → thth-2.13.2}/tests/test_sent_integrity.py +0 -0
  201. {thth-2.13.1 → thth-2.13.2}/tests/test_server_json.py +0 -0
  202. {thth-2.13.1 → thth-2.13.2}/tests/test_site.py +0 -0
  203. {thth-2.13.1 → thth-2.13.2}/tests/test_skill_doc.py +0 -0
  204. {thth-2.13.1 → thth-2.13.2}/tests/test_study_report.py +0 -0
  205. {thth-2.13.1 → thth-2.13.2}/tests/test_systemd.py +0 -0
  206. {thth-2.13.1 → thth-2.13.2}/tests/test_thread_publish.py +0 -0
  207. {thth-2.13.1 → thth-2.13.2}/tests/test_thread_read.py +0 -0
  208. {thth-2.13.1 → thth-2.13.2}/tests/test_threadrun.py +0 -0
  209. {thth-2.13.1 → thth-2.13.2}/tests/test_threads_read_permissions.py +0 -0
  210. {thth-2.13.1 → thth-2.13.2}/tests/test_threadshape.py +0 -0
  211. {thth-2.13.1 → thth-2.13.2}/tests/test_thth_root.py +0 -0
  212. {thth-2.13.1 → thth-2.13.2}/tests/test_token_exists.py +0 -0
  213. {thth-2.13.1 → thth-2.13.2}/tests/test_token_scopes_record.py +0 -0
  214. {thth-2.13.1 → thth-2.13.2}/tests/test_token_set.py +0 -0
  215. {thth-2.13.1 → thth-2.13.2}/tests/test_topic.py +0 -0
  216. {thth-2.13.1 → thth-2.13.2}/tests/test_topic_advice.py +0 -0
  217. {thth-2.13.1 → thth-2.13.2}/tests/test_topic_cli.py +0 -0
  218. {thth-2.13.1 → thth-2.13.2}/tests/test_topic_models.py +0 -0
  219. {thth-2.13.1 → thth-2.13.2}/tests/test_topic_review_fixes.py +0 -0
  220. {thth-2.13.1 → thth-2.13.2}/tests/test_topic_shelf_observers.py +0 -0
  221. {thth-2.13.1 → thth-2.13.2}/tests/test_topic_store.py +0 -0
  222. {thth-2.13.1 → thth-2.13.2}/tests/test_topics_record_concurrent.py +0 -0
  223. {thth-2.13.1 → thth-2.13.2}/tests/test_topics_tool.py +0 -0
  224. {thth-2.13.1 → thth-2.13.2}/tests/test_trial_frictions.py +0 -0
  225. {thth-2.13.1 → thth-2.13.2}/tests/test_v210_admin_transaction.py +0 -0
  226. {thth-2.13.1 → thth-2.13.2}/tests/test_v210_approve_account.py +0 -0
  227. {thth-2.13.1 → thth-2.13.2}/tests/test_v210_json_contract.py +0 -0
  228. {thth-2.13.1 → thth-2.13.2}/tests/test_v210_length.py +0 -0
  229. {thth-2.13.1 → thth-2.13.2}/tests/test_v210_lock_wait.py +0 -0
  230. {thth-2.13.1 → thth-2.13.2}/tests/test_v210_mastodon_scopes.py +0 -0
  231. {thth-2.13.1 → thth-2.13.2}/tests/test_v210_mentions.py +0 -0
  232. {thth-2.13.1 → thth-2.13.2}/tests/test_v210_post_urls.py +0 -0
  233. {thth-2.13.1 → thth-2.13.2}/tests/test_v210_repo_paths.py +0 -0
  234. {thth-2.13.1 → thth-2.13.2}/tests/test_v210_reposts.py +0 -0
  235. {thth-2.13.1 → thth-2.13.2}/tests/test_v210_study_add.py +0 -0
  236. {thth-2.13.1 → thth-2.13.2}/tests/test_v210_tool_version.py +0 -0
  237. {thth-2.13.1 → thth-2.13.2}/tests/test_v210_unanswered.py +0 -0
  238. {thth-2.13.1 → thth-2.13.2}/tests/test_v210_unanswered_scope.py +0 -0
  239. {thth-2.13.1 → thth-2.13.2}/tests/test_v210_where_arguments.py +0 -0
  240. {thth-2.13.1 → thth-2.13.2}/tests/test_v210_where_filters.py +0 -0
  241. {thth-2.13.1 → thth-2.13.2}/tests/test_v210_who_arguments.py +0 -0
  242. {thth-2.13.1 → thth-2.13.2}/tests/test_v211_auth_integration.py +0 -0
  243. {thth-2.13.1 → thth-2.13.2}/tests/test_v211_authflow.py +0 -0
  244. {thth-2.13.1 → thth-2.13.2}/tests/test_v211_bluesky_stdin.py +0 -0
  245. {thth-2.13.1 → thth-2.13.2}/tests/test_v211_doctor_binding.py +0 -0
  246. {thth-2.13.1 → thth-2.13.2}/tests/test_v211_mastodon_auth.py +0 -0
  247. {thth-2.13.1 → thth-2.13.2}/tests/test_v211_x_auth.py +0 -0
  248. {thth-2.13.1 → thth-2.13.2}/tests/test_v212_approval_relay.py +0 -0
  249. {thth-2.13.1 → thth-2.13.2}/tests/test_v212_ask_coordination.py +0 -0
  250. {thth-2.13.1 → thth-2.13.2}/tests/test_v212_budget.py +0 -0
  251. {thth-2.13.1 → thth-2.13.2}/tests/test_v212_budget_auth.py +0 -0
  252. {thth-2.13.1 → thth-2.13.2}/tests/test_v212_budget_mcp.py +0 -0
  253. {thth-2.13.1 → thth-2.13.2}/tests/test_v212_deletion.py +0 -0
  254. {thth-2.13.1 → thth-2.13.2}/tests/test_v212_job_completion_fault.py +0 -0
  255. {thth-2.13.1 → thth-2.13.2}/tests/test_v212_leave.py +0 -0
  256. {thth-2.13.1 → thth-2.13.2}/tests/test_v212_leave_gate.py +0 -0
  257. {thth-2.13.1 → thth-2.13.2}/tests/test_v212_leave_providers.py +0 -0
  258. {thth-2.13.1 → thth-2.13.2}/tests/test_v212_leave_token_safety.py +0 -0
  259. {thth-2.13.1 → thth-2.13.2}/tests/test_v212_mastodon_guide.py +0 -0
  260. {thth-2.13.1 → thth-2.13.2}/tests/test_v212_mcp_compat.py +0 -0
  261. {thth-2.13.1 → thth-2.13.2}/tests/test_v212_missing_token.py +0 -0
  262. {thth-2.13.1 → thth-2.13.2}/tests/test_v212_read_coordination.py +0 -0
  263. {thth-2.13.1 → thth-2.13.2}/tests/test_v212_server_writes.py +0 -0
  264. {thth-2.13.1 → thth-2.13.2}/tests/test_v212_token_parent.py +0 -0
  265. {thth-2.13.1 → thth-2.13.2}/tests/test_v212_write_storage.py +0 -0
  266. {thth-2.13.1 → thth-2.13.2}/tests/test_v2131_send_dry_run.py +0 -0
  267. {thth-2.13.1 → thth-2.13.2}/tests/test_v2131_threads_publish_wait.py +0 -0
  268. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_acceptance_fixes.py +0 -0
  269. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_adts_asf.py +0 -0
  270. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_approval_attachments.py +0 -0
  271. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_attachment_kinds.py +0 -0
  272. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_bluesky_external.py +0 -0
  273. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_bluesky_media.py +0 -0
  274. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_bluesky_metadata.py +0 -0
  275. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_bluesky_metadata_uri.py +0 -0
  276. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_bluesky_metadata_video.py +0 -0
  277. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_bluesky_record.py +0 -0
  278. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_bluesky_record_video.py +0 -0
  279. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_bluesky_video.py +0 -0
  280. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_bluesky_webm_named.py +0 -0
  281. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_bmff_typed_metadata.py +0 -0
  282. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_budget_lock.py +0 -0
  283. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_capabilities.py +0 -0
  284. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_carryover_timeout.py +0 -0
  285. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_graphemes.py +0 -0
  286. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_mastodon_auth_media.py +0 -0
  287. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_mastodon_bmff_audio.py +0 -0
  288. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_mastodon_flac.py +0 -0
  289. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_mastodon_gif.py +0 -0
  290. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_mastodon_link.py +0 -0
  291. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_mastodon_media.py +0 -0
  292. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_mastodon_mp3.py +0 -0
  293. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_mastodon_ogg_opus.py +0 -0
  294. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_mastodon_ogg_vorbis.py +0 -0
  295. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_mastodon_poll.py +0 -0
  296. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_mastodon_primary_size_boundary.py +0 -0
  297. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_mastodon_quote.py +0 -0
  298. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_mastodon_thumbnail.py +0 -0
  299. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_mastodon_wav.py +0 -0
  300. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_mastodon_webm_audio.py +0 -0
  301. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_mastodon_webm_video.py +0 -0
  302. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_media_cleanup.py +0 -0
  303. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_media_formats.py +0 -0
  304. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_media_foundation.py +0 -0
  305. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_media_prepared.py +0 -0
  306. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_media_relay.py +0 -0
  307. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_media_relay_refusals.py +0 -0
  308. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_media_upload.py +0 -0
  309. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_receipt_deadline.py +0 -0
  310. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_review_followups.py +0 -0
  311. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_stage810_audit.py +0 -0
  312. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_static_diagnostics.py +0 -0
  313. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_stop_observation.py +0 -0
  314. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_systemd_worker.py +0 -0
  315. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_threads_ghost.py +0 -0
  316. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_threads_gif.py +0 -0
  317. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_threads_link.py +0 -0
  318. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_threads_media.py +0 -0
  319. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_threads_media_spoiler.py +0 -0
  320. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_threads_poll.py +0 -0
  321. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_threads_quote.py +0 -0
  322. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_threads_quote_media.py +0 -0
  323. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_threads_replies.py +0 -0
  324. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_threads_text.py +0 -0
  325. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_threads_text_spoiler.py +0 -0
  326. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_threads_video.py +0 -0
  327. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_transport_review.py +0 -0
  328. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_video_typed_metadata.py +0 -0
  329. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_vorbis_comment_boundary.py +0 -0
  330. {thth-2.13.1 → thth-2.13.2}/tests/test_v213_webm_schema_boundary.py +0 -0
  331. {thth-2.13.1 → thth-2.13.2}/tests/test_v21b_approved_writes.py +0 -0
  332. {thth-2.13.1 → thth-2.13.2}/tests/test_v28_tags.py +0 -0
  333. {thth-2.13.1 → thth-2.13.2}/tests/test_v31_analysis.py +0 -0
  334. {thth-2.13.1 → thth-2.13.2}/tests/test_v31_collection.py +0 -0
  335. {thth-2.13.1 → thth-2.13.2}/tests/test_value_domains_shown.py +0 -0
  336. {thth-2.13.1 → thth-2.13.2}/tests/test_version.py +0 -0
  337. {thth-2.13.1 → thth-2.13.2}/tests/test_where_cli.py +0 -0
  338. {thth-2.13.1 → thth-2.13.2}/tests/test_who_cli.py +0 -0
  339. {thth-2.13.1 → thth-2.13.2}/tests/test_writeback_rebase.py +0 -0
  340. {thth-2.13.1 → thth-2.13.2}/tests/test_writeback_validate.py +0 -0
  341. {thth-2.13.1 → thth-2.13.2}/tests/test_x_metrics.py +0 -0
  342. {thth-2.13.1 → thth-2.13.2}/thth/__init__.py +0 -0
  343. {thth-2.13.1 → thth-2.13.2}/thth/__main__.py +0 -0
  344. {thth-2.13.1 → thth-2.13.2}/thth/_grapheme_data.py +0 -0
  345. {thth-2.13.1 → thth-2.13.2}/thth/account_cli.py +0 -0
  346. {thth-2.13.1 → thth-2.13.2}/thth/account_report.py +0 -0
  347. {thth-2.13.1 → thth-2.13.2}/thth/accounts.py +0 -0
  348. {thth-2.13.1 → thth-2.13.2}/thth/adapters/__init__.py +0 -0
  349. {thth-2.13.1 → thth-2.13.2}/thth/adapters/auth_mastodon.py +0 -0
  350. {thth-2.13.1 → thth-2.13.2}/thth/adapters/auth_threads.py +0 -0
  351. {thth-2.13.1 → thth-2.13.2}/thth/adapters/auth_x.py +0 -0
  352. {thth-2.13.1 → thth-2.13.2}/thth/adapters/base.py +0 -0
  353. {thth-2.13.1 → thth-2.13.2}/thth/adapters/bluesky.py +0 -0
  354. {thth-2.13.1 → thth-2.13.2}/thth/adapters/bluesky_media.py +0 -0
  355. {thth-2.13.1 → thth-2.13.2}/thth/adapters/bluesky_video.py +0 -0
  356. {thth-2.13.1 → thth-2.13.2}/thth/adapters/mastodon.py +0 -0
  357. {thth-2.13.1 → thth-2.13.2}/thth/adapters/mastodon_media.py +0 -0
  358. {thth-2.13.1 → thth-2.13.2}/thth/adapters/threads.py +0 -0
  359. {thth-2.13.1 → thth-2.13.2}/thth/admin_log.py +0 -0
  360. {thth-2.13.1 → thth-2.13.2}/thth/admin_notifications.py +0 -0
  361. {thth-2.13.1 → thth-2.13.2}/thth/admin_report.py +0 -0
  362. {thth-2.13.1 → thth-2.13.2}/thth/after_cli.py +0 -0
  363. {thth-2.13.1 → thth-2.13.2}/thth/analytics_comparison.py +0 -0
  364. {thth-2.13.1 → thth-2.13.2}/thth/analytics_report.py +0 -0
  365. {thth-2.13.1 → thth-2.13.2}/thth/analytics_shapes.py +0 -0
  366. {thth-2.13.1 → thth-2.13.2}/thth/analytics_threads.py +0 -0
  367. {thth-2.13.1 → thth-2.13.2}/thth/api_diagnostic.py +0 -0
  368. {thth-2.13.1 → thth-2.13.2}/thth/appconfig.py +0 -0
  369. {thth-2.13.1 → thth-2.13.2}/thth/appenv.py +0 -0
  370. {thth-2.13.1 → thth-2.13.2}/thth/approval.py +0 -0
  371. {thth-2.13.1 → thth-2.13.2}/thth/approval_jobs.py +0 -0
  372. {thth-2.13.1 → thth-2.13.2}/thth/approval_relay.py +0 -0
  373. {thth-2.13.1 → thth-2.13.2}/thth/ask.py +0 -0
  374. {thth-2.13.1 → thth-2.13.2}/thth/ask_cli.py +0 -0
  375. {thth-2.13.1 → thth-2.13.2}/thth/audioformats.py +0 -0
  376. {thth-2.13.1 → thth-2.13.2}/thth/authclients.py +0 -0
  377. {thth-2.13.1 → thth-2.13.2}/thth/authflow.py +0 -0
  378. {thth-2.13.1 → thth-2.13.2}/thth/authpassword.py +0 -0
  379. {thth-2.13.1 → thth-2.13.2}/thth/bluesky_metadata.py +0 -0
  380. {thth-2.13.1 → thth-2.13.2}/thth/budget_x.py +0 -0
  381. {thth-2.13.1 → thth-2.13.2}/thth/bundle.py +0 -0
  382. {thth-2.13.1 → thth-2.13.2}/thth/collect.py +0 -0
  383. {thth-2.13.1 → thth-2.13.2}/thth/collection_context.py +0 -0
  384. {thth-2.13.1 → thth-2.13.2}/thth/collection_status.py +0 -0
  385. {thth-2.13.1 → thth-2.13.2}/thth/deletion.py +0 -0
  386. {thth-2.13.1 → thth-2.13.2}/thth/doctor.py +0 -0
  387. {thth-2.13.1 → thth-2.13.2}/thth/ebmlaudio.py +0 -0
  388. {thth-2.13.1 → thth-2.13.2}/thth/ebmlvideo.py +0 -0
  389. {thth-2.13.1 → thth-2.13.2}/thth/engagements.py +0 -0
  390. {thth-2.13.1 → thth-2.13.2}/thth/flacformats.py +0 -0
  391. {thth-2.13.1 → thth-2.13.2}/thth/forms.py +0 -0
  392. {thth-2.13.1 → thth-2.13.2}/thth/graphemes.py +0 -0
  393. {thth-2.13.1 → thth-2.13.2}/thth/handoff_cursor.py +0 -0
  394. {thth-2.13.1 → thth-2.13.2}/thth/healthcheck.py +0 -0
  395. {thth-2.13.1 → thth-2.13.2}/thth/httpsafe.py +0 -0
  396. {thth-2.13.1 → thth-2.13.2}/thth/incident.py +0 -0
  397. {thth-2.13.1 → thth-2.13.2}/thth/jst.py +0 -0
  398. {thth-2.13.1 → thth-2.13.2}/thth/leave.py +0 -0
  399. {thth-2.13.1 → thth-2.13.2}/thth/leave_gate.py +0 -0
  400. {thth-2.13.1 → thth-2.13.2}/thth/lint.py +0 -0
  401. {thth-2.13.1 → thth-2.13.2}/thth/lock.py +0 -0
  402. {thth-2.13.1 → thth-2.13.2}/thth/maintain.py +0 -0
  403. {thth-2.13.1 → thth-2.13.2}/thth/managed_repo.py +0 -0
  404. {thth-2.13.1 → thth-2.13.2}/thth/measured.py +0 -0
  405. {thth-2.13.1 → thth-2.13.2}/thth/media.py +0 -0
  406. {thth-2.13.1 → thth-2.13.2}/thth/media_capabilities.py +0 -0
  407. {thth-2.13.1 → thth-2.13.2}/thth/media_cleanup.py +0 -0
  408. {thth-2.13.1 → thth-2.13.2}/thth/media_relay.py +0 -0
  409. {thth-2.13.1 → thth-2.13.2}/thth/media_uploads.py +0 -0
  410. {thth-2.13.1 → thth-2.13.2}/thth/mediaformats.py +0 -0
  411. {thth-2.13.1 → thth-2.13.2}/thth/mpeg_audio.py +0 -0
  412. {thth-2.13.1 → thth-2.13.2}/thth/oauth.py +0 -0
  413. {thth-2.13.1 → thth-2.13.2}/thth/oggformats.py +0 -0
  414. {thth-2.13.1 → thth-2.13.2}/thth/operations_handoff.py +0 -0
  415. {thth-2.13.1 → thth-2.13.2}/thth/postid.py +0 -0
  416. {thth-2.13.1 → thth-2.13.2}/thth/queuefile.py +0 -0
  417. {thth-2.13.1 → thth-2.13.2}/thth/read_coordination.py +0 -0
  418. {thth-2.13.1 → thth-2.13.2}/thth/read_window.py +0 -0
  419. {thth-2.13.1 → thth-2.13.2}/thth/redact.py +0 -0
  420. {thth-2.13.1 → thth-2.13.2}/thth/replies.py +0 -0
  421. {thth-2.13.1 → thth-2.13.2}/thth/report.py +0 -0
  422. {thth-2.13.1 → thth-2.13.2}/thth/report_details.py +0 -0
  423. {thth-2.13.1 → thth-2.13.2}/thth/report_http.py +0 -0
  424. {thth-2.13.1 → thth-2.13.2}/thth/report_isolation.py +0 -0
  425. {thth-2.13.1 → thth-2.13.2}/thth/report_service.py +0 -0
  426. {thth-2.13.1 → thth-2.13.2}/thth/retract_cli.py +0 -0
  427. {thth-2.13.1 → thth-2.13.2}/thth/runs.py +0 -0
  428. {thth-2.13.1 → thth-2.13.2}/thth/scopes.py +0 -0
  429. {thth-2.13.1 → thth-2.13.2}/thth/secrets_fs.py +0 -0
  430. {thth-2.13.1 → thth-2.13.2}/thth/select.py +0 -0
  431. {thth-2.13.1 → thth-2.13.2}/thth/selfupdate.py +0 -0
  432. {thth-2.13.1 → thth-2.13.2}/thth/sent.py +0 -0
  433. {thth-2.13.1 → thth-2.13.2}/thth/server_files.py +0 -0
  434. {thth-2.13.1 → thth-2.13.2}/thth/server_writes.py +0 -0
  435. {thth-2.13.1 → thth-2.13.2}/thth/stop_observation.py +0 -0
  436. {thth-2.13.1 → thth-2.13.2}/thth/study_cli.py +0 -0
  437. {thth-2.13.1 → thth-2.13.2}/thth/study_report.py +0 -0
  438. {thth-2.13.1 → thth-2.13.2}/thth/systemd_gen.py +0 -0
  439. {thth-2.13.1 → thth-2.13.2}/thth/tags.py +0 -0
  440. {thth-2.13.1 → thth-2.13.2}/thth/thread_read.py +0 -0
  441. {thth-2.13.1 → thth-2.13.2}/thth/threadrun.py +0 -0
  442. {thth-2.13.1 → thth-2.13.2}/thth/threads_read_cli.py +0 -0
  443. {thth-2.13.1 → thth-2.13.2}/thth/threadshape.py +0 -0
  444. {thth-2.13.1 → thth-2.13.2}/thth/threadthrow.py +0 -0
  445. {thth-2.13.1 → thth-2.13.2}/thth/tool_version.py +0 -0
  446. {thth-2.13.1 → thth-2.13.2}/thth/topic_advice.py +0 -0
  447. {thth-2.13.1 → thth-2.13.2}/thth/topic_cli.py +0 -0
  448. {thth-2.13.1 → thth-2.13.2}/thth/topic_models.py +0 -0
  449. {thth-2.13.1 → thth-2.13.2}/thth/topic_store.py +0 -0
  450. {thth-2.13.1 → thth-2.13.2}/thth/topics.py +0 -0
  451. {thth-2.13.1 → thth-2.13.2}/thth/unanswered.py +0 -0
  452. {thth-2.13.1 → thth-2.13.2}/thth/vorbisformats.py +0 -0
  453. {thth-2.13.1 → thth-2.13.2}/thth/where_cli.py +0 -0
  454. {thth-2.13.1 → thth-2.13.2}/thth/who_cli.py +0 -0
  455. {thth-2.13.1 → thth-2.13.2}/thth/writeback.py +0 -0
  456. {thth-2.13.1 → thth-2.13.2}/thth/x_metrics.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: thth
3
- Version: 2.13.1
3
+ Version: 2.13.2
4
4
  Summary: 承認済みの投稿だけを投げる門(Threads・Bluesky・Mastodon)。人が承認し、記録は利用者の git に残る。
5
5
  Project-URL: Homepage, https://thth.me
6
6
  Project-URL: Source, https://github.com/aokings/thth
@@ -0,0 +1,67 @@
1
+ """2.13.2 実機直し: inflight が残っているなら、dry-run でも断って次の一歩を言う。
2
+
3
+ 作成の時間切れ(`media_creating_timeout`)は inflight を `unknown` のまま
4
+ 残す。そのあと `thth send` を打った人が最初に見るのがここ——2.13.1 までは
5
+ `--production` なしだと digest まで出して 0 で終わり、残っていることを一言も
6
+ 言わなかった。`--production` を付ければ断るが、理由 1 行だけで「どうすれば
7
+ いいか」は無かった。
8
+ """
9
+ import pytest
10
+ from thth import accounts, cli, core, inflight, media, media_delivery, read_coordination
11
+ from tests.test_v213_threads_media import env, wire
12
+
13
+
14
+ @pytest.fixture
15
+ def send(env, monkeypatch):
16
+ monkeypatch.setattr(core, '_append_run', lambda *a, **k: None)
17
+ monkeypatch.setattr(read_coordination, 'invoke',
18
+ lambda args, name, fn=None: fn() if fn else args.func(args))
19
+ return lambda *extra: cli.main(['send', 'alpha', '--media', 'a.png', '--alt', '説明', *extra])
20
+
21
+
22
+ def seed_unknown(env, reason='media_creating_timeout'):
23
+ """作成の時間切れが残す journal と同じ形(phase `unknown`・remote_ids 空)。"""
24
+ state = accounts.state_dir_for('alpha')
25
+ manifest = media.manifest_for({'media': [{'file': 'a.png', 'alt': '説明'}]}, env[0])
26
+ inflight.write(state, file='(send)', started='2030-01-01T00:00:00+09:00')
27
+ media_delivery._progress('alpha', manifest, 'https://graph.invalid', 'unknown',
28
+ remote_ids=[], reason=reason)
29
+ return state
30
+
31
+
32
+ @pytest.mark.parametrize('extra', [(), ('--production',)])
33
+ def test_send_refuses_and_says_what_to_do(env, send, wire, capsys, extra):
34
+ seed_unknown(env)
35
+ assert send(*extra) == 1
36
+ shown = capsys.readouterr()
37
+ output = shown.out + shown.err
38
+ assert 'inflight が残っています' in output
39
+ assert inflight.NEXT_STEP in output
40
+ # 断ったのだから digest も本文の下見も出ない。媒体には一度も触らない。
41
+ assert 'digest: ' not in output and not wire['calls'] and not env[3]['upload']
42
+ # 次の一歩は 1 行だけ。
43
+ assert len([line for line in output.splitlines() if line.startswith('次の一歩')]) == 1
44
+
45
+
46
+ def test_the_refusal_stays_static(env, send, capsys):
47
+ seed_unknown(env)
48
+ assert send() == 1
49
+ shown = capsys.readouterr()
50
+ output = shown.out + shown.err
51
+ # repo の実パスもアカウントの state パスも映さない(既存の静的の約束)。
52
+ assert str(env[2]) not in output and str(accounts.state_dir_for('alpha')) not in output
53
+
54
+
55
+ def test_the_inflight_is_left_exactly_as_it_was(env, send):
56
+ state = seed_unknown(env)
57
+ before = inflight.read(state)
58
+ assert send() == 1 and send('--production') == 1
59
+ assert inflight.read(state) == before
60
+
61
+
62
+ def test_without_an_inflight_the_dry_run_still_shows_the_digest(env, send, capsys):
63
+ assert send() == 0
64
+ shown = capsys.readouterr()
65
+ output = shown.out + shown.err
66
+ assert 'digest: ' in output and 'inflight が残っています' not in output
67
+ assert inflight.NEXT_STEP not in output
@@ -0,0 +1,84 @@
1
+ """2.13.2 実機直し: container の作成は Meta の取り込みを待つ(10 秒では足りない)。
2
+
3
+ 実機 2026-09-22(masaru-threads・`--media docs/media/photo.jpg`): `POST
4
+ /{user}/threads` に `image_url` を渡すと、Meta はその POST を開いたまま
5
+ thth.me/R2 から画像を取りに行く。2.13.0 の同じ添付は通ったのに 2.13.1 は
6
+ `media_creating_failed`(phase `unknown`・`remote_ids=[]`)で落ちた——違いは
7
+ Meta の取り込みにかかった時間で、こちらの 10 秒(`adapter.timeout`)が短い。
8
+ """
9
+ import time
10
+ import pytest
11
+ from thth.adapters import threads_media as tm
12
+ from tests.test_v213_threads_media import env, wire, invoke, posts
13
+
14
+
15
+ @pytest.fixture
16
+ def clock(monkeypatch):
17
+ """凍った時計。`time.sleep` と偽 Graph の遅れだけが進める。"""
18
+ state = {'now': 0.0}
19
+ monkeypatch.setattr(tm.time, 'monotonic', lambda: state['now'])
20
+ monkeypatch.setattr(tm.time, 'sleep', lambda seconds: state.update(now=state['now'] + seconds))
21
+ return state
22
+
23
+
24
+ def sockets(monkeypatch):
25
+ """各 HTTP 呼び出しに渡った socket の締切(方式・パス・秒)を並べる。"""
26
+ seen = []
27
+ original = tm._transport.open
28
+ def open_request(request, timeout=None, **kwargs):
29
+ seen.append((request.get_method(), request.full_url.split('?')[0], timeout))
30
+ return original(request, timeout=timeout, **kwargs)
31
+ monkeypatch.setattr(tm._transport, 'open', open_request)
32
+ return seen
33
+
34
+
35
+ def test_a_creation_slower_than_the_adapter_timeout_still_lands(env, wire):
36
+ # 実機の再現: 作成だけが `adapter.timeout` より長くかかる。
37
+ env[1].timeout = 0.3
38
+ wire['on_create'] = lambda: time.sleep(1.0)
39
+ result, journal, _ = invoke(env)
40
+ assert result.post_id == '100' and journal['media']['phase'] == 'published'
41
+ assert len(posts(wire, '/threads_publish')) == 1
42
+
43
+
44
+ def test_only_the_creation_gets_the_long_budget(env, wire, monkeypatch):
45
+ seen = sockets(monkeypatch)
46
+ assert invoke(env)[0].post_id == '100'
47
+ # 作成は 90 秒。状態の問い合わせも公開も adapter の 10 秒のまま。
48
+ assert [t for m, u, t in seen if m == 'POST' and u.endswith('/threads')] == [tm.CREATE_TIMEOUT_SECONDS]
49
+ assert [t for m, u, t in seen if m == 'GET'] == [env[1].timeout]
50
+ assert [t for m, u, t in seen if u.endswith('/threads_publish')] == [env[1].timeout]
51
+
52
+
53
+ @pytest.mark.parametrize('raw,seconds', [
54
+ (None, 90.0), ('120', 120.0), ('90.5', 90.5),
55
+ ('10', 10.0), ('9', 10.0), ('0', 10.0), ('-5', 10.0),
56
+ ('600', 600.0), ('601', 600.0), ('86400', 600.0),
57
+ ('', 90.0), ('abc', 90.0), ('inf', 90.0), ('nan', 90.0),
58
+ ])
59
+ def test_the_override_is_read_and_clamped(monkeypatch, raw, seconds):
60
+ monkeypatch.delenv('THTH_THREADS_CREATE_TIMEOUT_SECONDS', raising=False)
61
+ if raw is not None:
62
+ monkeypatch.setenv('THTH_THREADS_CREATE_TIMEOUT_SECONDS', raw)
63
+ assert tm.create_timeout() == seconds
64
+
65
+
66
+ def test_the_override_reaches_the_creation_socket(env, wire, monkeypatch):
67
+ monkeypatch.setenv('THTH_THREADS_CREATE_TIMEOUT_SECONDS', '900')
68
+ seen = sockets(monkeypatch)
69
+ assert invoke(env)[0].post_id == '100'
70
+ assert [t for m, u, t in seen if m == 'POST' and u.endswith('/threads')] == [600.0]
71
+
72
+
73
+ def test_the_poll_deadline_counts_the_time_the_creation_took(env, wire, monkeypatch, clock):
74
+ # 画像の持ち時間は 120 秒。作成に 40 秒使ったら、問い合わせに残るのは 80 秒。
75
+ monkeypatch.setattr(tm, 'POLL_INTERVAL', 10.0)
76
+ wire['poll'] = [(200, {'status': 'IN_PROGRESS'})] * 60
77
+ wire['on_create'] = lambda: clock.update(now=clock['now'] + 40.0)
78
+ result, journal, _ = invoke(env)
79
+ assert result.error == 'media_processing_timeout' and result.failure == 'media_held'
80
+ # 作成を数えなければ 160 秒・12 回になる。
81
+ assert clock['now'] == tm.POLL_SECONDS
82
+ assert len([c for c in wire['calls'] if c[0] == 'GET']) == 8
83
+ assert not posts(wire, '/threads_publish') and env[3]['results'] == [False]
84
+
@@ -0,0 +1,90 @@
1
+ """2.13.2 実機直し: 作成の時間切れは「出ていないこと」ではない。
2
+
3
+ Meta は `POST /{user}/threads` を開いたまま媒体を取りに行くので、こちらが
4
+ socket を諦めたあとに向こうで container ができていることがある。phase は
5
+ `unknown` のまま——そのうえで理由を `media_creating_timeout` と名指し、
6
+ `thth send` が「確かめてから消す」と言えるようにする。
7
+ """
8
+ import threading
9
+ import urllib.error
10
+ import pytest
11
+ from thth import media_delivery
12
+ from thth.adapters import threads_media as tm
13
+ from tests.test_v213_media_foundation import png
14
+ from tests.test_v213_threads_media import env, wire, invoke, posts
15
+
16
+ STEP = '次の一歩: 媒体が画像/動画を取り込むのに時間がかかっています。しばらくして inflight を確認し、投稿が無ければ消してから再実行'
17
+
18
+
19
+ @pytest.fixture
20
+ def stall():
21
+ """偽 Graph を黙らせる掛け金。試験が終わったら必ず外す(daemon を残さない)。"""
22
+ gate = threading.Event()
23
+ try:
24
+ yield lambda: gate.wait(10)
25
+ finally:
26
+ gate.set()
27
+
28
+
29
+ @pytest.mark.parametrize('error,timed_out', [
30
+ (TimeoutError('slow'), True),
31
+ (urllib.error.URLError(TimeoutError('slow')), True),
32
+ (urllib.error.URLError(ConnectionResetError('reset')), False),
33
+ (OSError('broken'), False),
34
+ (urllib.error.HTTPError('http://x.invalid', 408, 'Request Timeout', None, None), False),
35
+ ])
36
+ def test_only_a_socket_timeout_counts_as_one(error, timed_out):
37
+ assert tm.socket_timed_out(error) is timed_out
38
+
39
+
40
+ def test_a_creation_that_never_answers_is_unknown_and_named_as_a_timeout(env, wire, monkeypatch, stall):
41
+ monkeypatch.setattr(tm, 'create_timeout', lambda: 0.3)
42
+ wire['on_create'] = stall
43
+ result, journal, _ = invoke(env)
44
+ assert result.post_id is None and result.failure == 'media_ambiguous'
45
+ assert result.error == 'media_creating_timeout'
46
+ assert journal['media']['phase'] == 'unknown' and journal['media']['reason'] == 'media_creating_timeout'
47
+ # container ができたかどうかは分からない: 覚えている id は無く、公開もしない。
48
+ assert journal['media']['remote_ids'] == [] and not posts(wire, '/threads_publish')
49
+ # 付与も引き上げない(引き上げれば向こうにできた container が確実に死ぬ)。
50
+ assert env[3]['results'] == []
51
+ assert media_delivery.next_step(result.error) == STEP
52
+
53
+
54
+ def test_the_carousel_parent_timeout_is_named_the_same_way(env, wire, monkeypatch, stall):
55
+ (env[2] / 'b.png').write_bytes(png())
56
+ monkeypatch.setattr(tm, 'create_timeout', lambda: 0.3)
57
+ created = []
58
+ def on_create():
59
+ created.append(1)
60
+ if len(created) == 3:
61
+ stall()
62
+ wire['on_create'] = on_create
63
+ fm = {'media': [{'file': 'a.png', 'alt': '点'}, {'file': 'b.png', 'alt': '別の点'}]}
64
+ result, journal, _ = invoke(env, fm)
65
+ assert result.error == 'media_creating_carousel_timeout' and result.failure == 'media_ambiguous'
66
+ assert journal['media']['phase'] == 'unknown' and journal['media']['remote_ids'] == ['11', '12']
67
+ assert not posts(wire, '/threads_publish') and env[3]['results'] == []
68
+ assert media_delivery.next_step(result.error) == STEP
69
+
70
+
71
+ def test_other_creation_failures_keep_the_generic_reason(env, wire, monkeypatch):
72
+ original = tm._transport.open
73
+ def open_request(request, timeout=None, **kwargs):
74
+ if request.get_method() == 'POST' and request.full_url.endswith('/threads'):
75
+ raise urllib.error.URLError(ConnectionResetError('reset'))
76
+ return original(request, timeout=timeout, **kwargs)
77
+ monkeypatch.setattr(tm._transport, 'open', open_request)
78
+ result, journal, _ = invoke(env)
79
+ assert result.error == 'media_creating_failed' and result.failure == 'media_ambiguous'
80
+ assert journal['media']['phase'] == 'unknown'
81
+ assert media_delivery.next_step(result.error) is None
82
+
83
+
84
+ def test_a_slow_poll_is_not_a_creation_timeout(env, wire, monkeypatch, stall):
85
+ # 時間切れを名指すのは作成だけ。問い合わせの時間切れは既存の扱いのまま。
86
+ env[1].timeout = 0.3
87
+ wire['on_poll'] = stall
88
+ result, journal, _ = invoke(env)
89
+ assert result.error == 'media_processing_failed' and result.failure == 'media_held'
90
+ assert journal['media']['phase'] == 'held' and journal['media']['remote_ids'] == ['11']
@@ -0,0 +1 @@
1
+ 2.13.2
@@ -6,6 +6,7 @@ boundary is an adjudicated temporary contract, not a verified API integer cap.
6
6
  from __future__ import annotations
7
7
  import json
8
8
  import math
9
+ import os
9
10
  import re
10
11
  import time
11
12
  import urllib.error
@@ -23,6 +24,16 @@ POLL_SECONDS=120.0
23
24
  VIDEO_POLL_SECONDS=1800.0
24
25
  MAX_VIDEO_BYTES=1_000_000_000
25
26
  POLL_INTERVAL=2.0
27
+ # Container creation with media is not our round trip. Meta fetches the image or
28
+ # the video from the grant URL **while the POST is open**, so the socket has to
29
+ # outlive that fetch. The adapter's own 10 s was enough on 2026-09-20 and not
30
+ # enough on 2026-09-22 for the same file — the difference is Meta's fetch, not
31
+ # ours, and Meta's own documentation describes media processing taking up to a
32
+ # minute for an image and longer for a video. Status polls and the publish POST
33
+ # keep the adapter's timeout: those are ordinary round trips.
34
+ CREATE_TIMEOUT_SECONDS=90.0
35
+ CREATE_TIMEOUT_MIN=10.0
36
+ CREATE_TIMEOUT_MAX=600.0
26
37
 
27
38
 
28
39
  def require(ok,reason):
@@ -187,13 +198,42 @@ class NoRedirect(httpsafe.SameOriginRedirectHandler):
187
198
  _transport=httpsafe.build_opener(NoRedirect())
188
199
 
189
200
 
190
- def _json(adapter,method,path,params,*,timeout=None):
201
+ def create_timeout():
202
+ """The socket budget for a container creation, clamped to [10, 600] seconds.
203
+
204
+ An unreadable or out-of-range `THTH_THREADS_CREATE_TIMEOUT_SECONDS` falls
205
+ back to the built-in figure rather than refusing: the override exists to let
206
+ the operator widen the window on a slow day, not to stop a send.
207
+ """
208
+ raw=os.environ.get('THTH_THREADS_CREATE_TIMEOUT_SECONDS')
209
+ if raw is None:return CREATE_TIMEOUT_SECONDS
210
+ try:value=float(raw)
211
+ except (TypeError,ValueError):return CREATE_TIMEOUT_SECONDS
212
+ if not math.isfinite(value):return CREATE_TIMEOUT_SECONDS
213
+ return min(max(value,CREATE_TIMEOUT_MIN),CREATE_TIMEOUT_MAX)
214
+
215
+
216
+ def socket_timed_out(error):
217
+ """Did this call run out of time on the socket? Never the provider's text.
218
+
219
+ `urllib` wraps a connect timeout in `URLError`; a read timeout arrives bare.
220
+ An `HTTPError` is an answer, however slow it was, so it is never a timeout.
221
+ """
222
+ if isinstance(error,urllib.error.HTTPError):return False
223
+ if isinstance(error,TimeoutError):return True
224
+ return isinstance(error,urllib.error.URLError) and isinstance(getattr(error,'reason',None),TimeoutError)
225
+
226
+
227
+ def _json(adapter,method,path,params,*,timeout=None,socket_timeout=None):
191
228
  values={**params,'access_token':adapter.access_token}
192
229
  data=urllib.parse.urlencode(values).encode()
193
230
  url=adapter.base_url+path
194
231
  if method=='GET':url+='?'+data.decode();data=None
195
232
  request=urllib.request.Request(url,data=data,method=method)
196
- with leave_gate.urlopen(_transport.open,request,timeout=adapter.timeout if timeout is None else min(adapter.timeout,timeout)) as response:
233
+ # `socket_timeout` replaces the adapter's figure (creation); `timeout`
234
+ # only ever narrows whichever figure applies (the poll's own deadline).
235
+ budget=adapter.timeout if socket_timeout is None else socket_timeout
236
+ with leave_gate.urlopen(_transport.open,request,timeout=budget if timeout is None else min(budget,timeout)) as response:
197
237
  code=response.status;raw=response.read(1024*1024+1)
198
238
  require(code==200 and len(raw)<=1024*1024,'media_response_invalid')
199
239
  result=json.loads(raw);require(type(result) is dict and not result.get('error'),'media_response_invalid')
@@ -244,8 +284,11 @@ def publish(adapter,post,*,before_publish=None,on_container_created=None):
244
284
  if min((g['expires_at']/1000-time.time() for g in grants),default=float('inf'))<=remaining:break
245
285
  time.sleep(remaining)
246
286
 
247
- def wait(container,*,video=False):
248
- deadline=time.monotonic()+(VIDEO_POLL_SECONDS if video else POLL_SECONDS)
287
+ def wait(container,*,video=False,since=None):
288
+ # 待ちの期限は**作成を始めた時刻**から数える。作成が 40 秒かかったなら
289
+ # 画像の 120 秒のうち残りは 80 秒——作成が長引いた分だけ全体が延びると、
290
+ # 付与の期限(画像 600 秒・動画 1800 秒)との関係が実行ごとに変わる。
291
+ deadline=(time.monotonic() if since is None else since)+(VIDEO_POLL_SECONDS if video else POLL_SECONDS)
249
292
  while True:
250
293
  veto();remaining=min(deadline-time.monotonic(),min((g['expires_at']/1000-time.time() for g in grants),default=float('inf')))
251
294
  require(remaining>0,'media_processing_timeout')
@@ -279,17 +322,18 @@ def publish(adapter,post,*,before_publish=None,on_container_created=None):
279
322
  params={'media_type':'VIDEO' if is_video else 'IMAGE','video_url' if is_video else 'image_url':grant['url'],'alt_text':item.manifest['alt']}
280
323
  if len(post.media_files)>1:params['is_carousel_item']='true'
281
324
  else:params.update(common)
282
- container=identifier(_json(adapter,'POST','/'+adapter.user_id+'/threads',params))
283
- ids.append(container);record('processing',index=index);wait(container,video=is_video);record('ready',index=index)
325
+ since=time.monotonic()
326
+ container=identifier(_json(adapter,'POST','/'+adapter.user_id+'/threads',params,socket_timeout=create_timeout()))
327
+ ids.append(container);record('processing',index=index);wait(container,video=is_video,since=since);record('ready',index=index)
284
328
  if typed is not None:
285
329
  veto();record('creating')
286
330
  container=identifier(_json(adapter,'POST','/'+adapter.user_id+'/threads',{'media_type':'TEXT',**common,**typed}))
287
331
  ids.append(container);record('processing');wait(container);record('ready')
288
332
  else:container=ids[0]
289
333
  if len(ids)>1:
290
- veto();record('creating_carousel')
291
- container=identifier(_json(adapter,'POST','/'+adapter.user_id+'/threads',{'media_type':'CAROUSEL','children':','.join(ids),**common}))
292
- record('processing_carousel',container_id=container);wait(container,video=any(i.manifest['kind']=='video' for i in post.media_files));record('ready',container_id=container)
334
+ veto();record('creating_carousel');since=time.monotonic()
335
+ container=identifier(_json(adapter,'POST','/'+adapter.user_id+'/threads',{'media_type':'CAROUSEL','children':','.join(ids),**common},socket_timeout=create_timeout()))
336
+ record('processing_carousel',container_id=container);wait(container,video=any(i.manifest['kind']=='video' for i in post.media_files),since=since);record('ready',container_id=container)
293
337
  if on_container_created:on_container_created(container)
294
338
  # 待ってから、待ったあとの様子でもう一度確かめて、それから公開する
295
339
  # (本文の経路と同じ順序・独立検収 2026-09-11 P1-3 と同じ理由)。
@@ -316,7 +360,13 @@ def publish(adapter,post,*,before_publish=None,on_container_created=None):
316
360
  definite=endpoint or http and 400<=exc.code<500
317
361
  held=bool(ids or grants) and (phase in ('ready','processing','processing_carousel') or definite)
318
362
  uncertain=phase!='preflight' and not held and not definite
319
- reason='media_relay_endpoint_rejected' if endpoint else str(exc) if isinstance(exc,media.MediaError) else 'media_relay_failed' if isinstance(exc,(media_relay.MediaRelayError,approval_relay.RelayError)) else 'media_'+phase+('_http_'+str(exc.code) if http else '_failed')
363
+ # 作成で時間切れになったときは「container ができたかどうか分からない」。
364
+ # Meta は POST を開いたまま媒体を取りに行くので、こちらが諦めたあとに
365
+ # 作成が終わっていることがある。phase は unknown のままにしたうえで、
366
+ # 理由だけを `media_creating_timeout` と名指す——generic な `_failed` は
367
+ # 「出ていない・作り直してよい」と読まれ、container が二重に残る。
368
+ timed_out=phase in ('creating','creating_carousel') and socket_timed_out(exc)
369
+ reason='media_relay_endpoint_rejected' if endpoint else str(exc) if isinstance(exc,media.MediaError) else 'media_relay_failed' if isinstance(exc,(media_relay.MediaRelayError,approval_relay.RelayError)) else 'media_'+phase+('_http_'+str(exc.code) if http else '_timeout' if timed_out else '_failed')
320
370
  # 4xx の本文には Graph の番号が入っている。**番号だけ**を理由の尾に足す
321
371
  # ——「まだ出せない」と「その要求が不正」を運用が見分けられない限り、
322
372
  # 同じ `media_publishing_http_400` を見て打つ手が決まらない。provider の
@@ -2608,6 +2608,7 @@ def cmd_send(args) -> int:
2608
2608
  """
2609
2609
  import sys as _sys
2610
2610
  from . import core as core_mod
2611
+ from . import inflight as inflight_mod
2611
2612
  if args.text_file:
2612
2613
  vm_msg = _require_vm_path(args.text_file, what="送る本文のファイル")
2613
2614
  if vm_msg:
@@ -2657,6 +2658,11 @@ def cmd_send(args) -> int:
2657
2658
  result = outcome.get('result')
2658
2659
  if code and result is not None:
2659
2660
  lines = media_delivery_mod.refusal_lines(result)
2661
+ # inflight で止まったなら「確かめてから消す」を必ず 1 行足す。
2662
+ # 媒体の理由(`media_creating_timeout` 等)が既に次の一歩を持って
2663
+ # いるなら、そちらの方が具体的なので重ねない。
2664
+ if result.action == 'inflight' and not any(line.startswith('次の一歩') for line in lines):
2665
+ lines = [*lines, inflight_mod.NEXT_STEP]
2660
2666
  # 個別の次の一歩が既に出ているなら、一般の次の一歩は重ねない。
2661
2667
  if any(line.startswith('次の一歩') for line in printed):
2662
2668
  lines = [line for line in lines if not line.startswith('次の一歩')]
@@ -943,7 +943,12 @@ def _send_locked(account_name, account_cfg, state_dir, run_id, *, text, topic, r
943
943
  locks = ((lock_context or _account_locks(account_name, account_cfg, state_dir, wait=wait))
944
944
  if production_flag else contextlib.nullcontext())
945
945
  with locks:
946
- existing_inflight = inflight_mod.read(state_dir) if production_flag else None
946
+ # **dry-run でも断る**(実機 2026-09-22)。inflight が残ったまま
947
+ # `thth send`(`--production` なし)を打つと、digest まで出して 0 で
948
+ # 終わっていた——次に `--production` を付けたら必ず断られるのに、
949
+ # 残っていることを一言も言わない。不在の様態(`_throw_locked`)は
950
+ # 最初から様態に関わらず断っている。同じにする。
951
+ existing_inflight = inflight_mod.read(state_dir)
947
952
  if existing_inflight is not None:
948
953
  msg = f"inflight が残っています: {existing_inflight.get('file')}"
949
954
  log(msg)
@@ -10,6 +10,16 @@ import json
10
10
  import os
11
11
 
12
12
 
13
+ # 「確かめてから消す」を 1 行で(設計 §3.5・`docs/原稿_添付_2.13.md`・
14
+ # `docs/使い方_プロジェクトのセッション向け_2026-09-09.md`)。**静的な文**で、
15
+ # アカウント名もパスも値も埋め込まない(`thth send` が stderr に出す)。
16
+ # inflight が残っているのは「出たか出ていないか分からない」ということなので、
17
+ # 消してよいかを決められるのは画面を見た人だけ。
18
+ NEXT_STEP = ("次の一歩: 前回の結果が分かっていません。媒体の画面で出たかどうかを確かめ、"
19
+ "出ていれば記録してから、出ていなければ state/<アカウント>/inflight.json "
20
+ "を消してからもう一度(確かめずに消さない)")
21
+
22
+
13
23
  def path_for(state_dir: str) -> str:
14
24
  return os.path.join(state_dir, "inflight.json")
15
25
 
@@ -144,6 +144,10 @@ MEDIA_NEXT_STEPS=(
144
144
  ('unsupported_attachment','次の一歩: この媒体が受け取れない形式です。`thth forms` で受かる形を見る'),
145
145
  ('media_limit_exceeded','次の一歩: 媒体の上限を超えています。小さくするか分ける'),
146
146
  ('media_capability_unavailable','次の一歩: 媒体の上限を読めていません。instance に届くところで出し直す'),
147
+ # 作成で時間切れ(`threads_media.socket_timed_out`)。container ができたか
148
+ # どうかは分からないので、消す前に必ず確かめさせる。
149
+ ('media_creating_timeout','次の一歩: 媒体が画像/動画を取り込むのに時間がかかっています。しばらくして inflight を確認し、投稿が無ければ消してから再実行'),
150
+ ('media_creating_carousel_timeout','次の一歩: 媒体が画像/動画を取り込むのに時間がかかっています。しばらくして inflight を確認し、投稿が無ければ消してから再実行'),
147
151
  ('media: alt_too_long','次の一歩: alt が長すぎます。2000 バイト以内に縮める'),
148
152
  ('media: source_unreadable','次の一歩: 添付を repo から読めません。パスと権限を確かめる'),
149
153
  ('media: source_changed','次の一歩: 読んでいる間にファイルが変わりました。もう一度'),
thth-2.13.1/thth/VERSION DELETED
@@ -1 +0,0 @@
1
- 2.13.1
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes