thth 5.2.0__tar.gz → 5.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {thth-5.2.0 → thth-5.4.0}/PKG-INFO +2 -2
- {thth-5.2.0 → thth-5.4.0}/README.md +1 -1
- thth-5.4.0/accounts.example/instagram.json +30 -0
- {thth-5.2.0 → thth-5.4.0}/mcp/server.py +4 -1
- {thth-5.2.0 → thth-5.4.0}/skills/thth/SKILL.md +19 -0
- {thth-5.2.0 → thth-5.4.0}/skills/thth/dashboard/all.html +3 -3
- {thth-5.2.0 → thth-5.4.0}/skills/thth/dashboard/campaign.html +3 -3
- {thth-5.2.0 → thth-5.4.0}/skills/thth/dashboard/project.html +3 -3
- {thth-5.2.0 → thth-5.4.0}/skills/thth/dashboard/series.html +3 -3
- {thth-5.2.0 → thth-5.4.0}/tests/conftest.py +17 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_adapter_boundary.py +4 -2
- {thth-5.2.0 → thth-5.4.0}/tests/test_facebook_adapter.py +3 -1
- {thth-5.2.0 → thth-5.4.0}/tests/test_limits_stage2.py +3 -3
- {thth-5.2.0 → thth-5.4.0}/tests/test_limits_stage3.py +1 -1
- {thth-5.2.0 → thth-5.4.0}/tests/test_media_registry.py +16 -4
- thth-5.4.0/tests/test_meta_stage2.py +453 -0
- thth-5.4.0/tests/test_meta_stage3.py +611 -0
- thth-5.4.0/tests/test_meta_stage4.py +592 -0
- thth-5.4.0/tests/test_meta_stage6.py +438 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v210_json_contract.py +8 -0
- thth-5.4.0/thth/VERSION +1 -0
- {thth-5.2.0 → thth-5.4.0}/thth/account_cli.py +29 -3
- {thth-5.2.0 → thth-5.4.0}/thth/accounts.py +1 -1
- {thth-5.2.0 → thth-5.4.0}/thth/adapters/__init__.py +4 -1
- {thth-5.2.0 → thth-5.4.0}/thth/adapters/auth_facebook.py +41 -15
- thth-5.4.0/thth/adapters/auth_instagram.py +83 -0
- {thth-5.2.0 → thth-5.4.0}/thth/adapters/base.py +3 -0
- {thth-5.2.0 → thth-5.4.0}/thth/adapters/facebook.py +268 -120
- thth-5.4.0/thth/adapters/instagram.py +783 -0
- thth-5.4.0/thth/adapters/instagram_media.py +307 -0
- {thth-5.2.0 → thth-5.4.0}/thth/admin_log.py +5 -1
- thth-5.4.0/thth/ads/__init__.py +18 -0
- thth-5.4.0/thth/ads/auth.py +366 -0
- thth-5.4.0/thth/ads/cli.py +421 -0
- thth-5.4.0/thth/ads/graphread.py +269 -0
- thth-5.4.0/thth/ads/ledger.py +366 -0
- thth-5.4.0/thth/ads/watch.py +355 -0
- {thth-5.2.0 → thth-5.4.0}/thth/authflow.py +3 -1
- {thth-5.2.0 → thth-5.4.0}/thth/cli.py +11 -0
- {thth-5.2.0 → thth-5.4.0}/thth/collect.py +69 -1
- {thth-5.2.0 → thth-5.4.0}/thth/core.py +29 -0
- {thth-5.2.0 → thth-5.4.0}/thth/dashboard_cli.py +24 -2
- {thth-5.2.0 → thth-5.4.0}/thth/edit_cli.py +74 -0
- {thth-5.2.0 → thth-5.4.0}/thth/events_cli.py +52 -1
- {thth-5.2.0 → thth-5.4.0}/thth/leave.py +1 -1
- {thth-5.2.0 → thth-5.4.0}/thth/leave_gate.py +7 -3
- {thth-5.2.0 → thth-5.4.0}/thth/limits_config.py +1 -1
- {thth-5.2.0 → thth-5.4.0}/thth/limits_policy.py +2 -2
- {thth-5.2.0 → thth-5.4.0}/thth/lint.py +2 -1
- {thth-5.2.0 → thth-5.4.0}/thth/maintain.py +76 -3
- {thth-5.2.0 → thth-5.4.0}/thth/measured.py +4 -0
- {thth-5.2.0 → thth-5.4.0}/thth/media.py +5 -2
- {thth-5.2.0 → thth-5.4.0}/thth/media_capabilities.py +32 -1
- {thth-5.2.0 → thth-5.4.0}/thth/media_delivery.py +17 -5
- {thth-5.2.0 → thth-5.4.0}/thth/media_registry.py +15 -0
- thth-5.4.0/thth/media_traits/instagram.json +145 -0
- {thth-5.2.0 → thth-5.4.0}/thth/media_traits.py +1 -1
- thth-5.4.0/thth/meta/__init__.py +16 -0
- thth-5.4.0/thth/meta/errors.py +118 -0
- thth-5.4.0/thth/meta/graph.py +190 -0
- thth-5.4.0/thth/meta/media.py +31 -0
- thth-5.4.0/thth/meta/tokens.py +74 -0
- thth-5.4.0/thth/meta/usage.py +237 -0
- {thth-5.2.0 → thth-5.4.0}/thth/morning.py +35 -2
- {thth-5.2.0 → thth-5.4.0}/thth/oauth.py +4 -1
- {thth-5.2.0 → thth-5.4.0}/thth/queuefile.py +3 -1
- thth-5.4.0/thth/quota_cli.py +102 -0
- {thth-5.2.0 → thth-5.4.0}/thth/relay.py +5 -1
- {thth-5.2.0 → thth-5.4.0}/thth/scenario.py +2 -2
- {thth-5.2.0 → thth-5.4.0}/thth/thread_read.py +4 -0
- thth-5.4.0/thth/webhook.py +508 -0
- {thth-5.2.0 → thth-5.4.0}/thth/worker.py +5 -0
- thth-5.2.0/thth/VERSION +0 -1
- {thth-5.2.0 → thth-5.4.0}/.gitignore +0 -0
- {thth-5.2.0 → thth-5.4.0}/LICENSE +0 -0
- {thth-5.2.0 → thth-5.4.0}/accounts.example/bluesky.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/accounts.example/facebook.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/accounts.example/hatenablog.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/accounts.example/mastodon.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/accounts.example/principal-hatena.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/accounts.example/threads.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/accounts.example/x.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/bin/thth +0 -0
- {thth-5.2.0 → thth-5.4.0}/bin/thth-remote +0 -0
- {thth-5.2.0 → thth-5.4.0}/bin/thth-run +0 -0
- {thth-5.2.0 → thth-5.4.0}/pyproject.toml +0 -0
- {thth-5.2.0 → thth-5.4.0}/skills/thth/dashboard/README.md +0 -0
- {thth-5.2.0 → thth-5.4.0}/skills/thth-admin/SKILL.md +0 -0
- {thth-5.2.0 → thth-5.4.0}/systemd/thth@.service +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/__init__.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/coordination_snapshot.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/fixtures/GraphemeBreakTest-17.0.0.txt +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/fixtures/build_injection_eval.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/fixtures/callback/worker_responses.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/fixtures/injection_eval.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/fixtures/limits_stage3/README.txt +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/fixtures/limits_stage3/ledgers/vm-kopicha-hatenablog.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/fixtures/limits_stage3/ledgers/vm-kopicha-x.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/fixtures/limits_stage3/ledgers/vm-music-threads.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/fixtures/limits_stage3/principals/vm-kopicha.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/fixtures/scenario_v1_golden.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/fixtures/twitter_text_v3_weighted.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/fixtures/umami-bile.md +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/hatena_s1_flow_helpers.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/hatena_s1_helpers.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/hatena_s2_helpers.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/hatena_s2_http.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/hatena_s3_helpers.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/hatena_s4_helpers.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/hatena_s5_helpers.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/hatena_s6_helpers.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/helpers/__init__.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/helpers/fake_oauth_server.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/helpers/fake_push_adapter.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/helpers/fake_redirect_server.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/helpers/fake_search_adapter.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/helpers/fake_threads_reader.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/helpers/fake_threads_status.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/helpers/fake_threads_writes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/helpers/fake_x.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/helpers/hold_lock.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/helpers/hold_repo_lock.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/helpers/worker_probe.mjs +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_27_acceptance_fixes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_account_name_check.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_account_report.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_accounts_dir.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_admin_http_mcp.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_admin_log.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_admin_notifications.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_admin_repairs.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_admin_report.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_after_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_analytics_comparison.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_analytics_report.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_api_diagnostic.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_api_error_body.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_app_env_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_approval.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_approve_cmd.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_ask.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_assess.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_atlas_fifth_review.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_atlas_fourth_review.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_atlas_review.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_atlas_second_review.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_atlas_third_review.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_audit1_fixes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_audit2_fixes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_audit_b_counterexamples.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_audit_b_m1_semantics.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_audit_b_n1_depth.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_audit_b_r1_closure.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_audit_v201.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_audit_v23_details.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_auth.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_auth_identity_required.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_b17_remote_reads.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_behind_remote.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_bluesky_adapter.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_bluesky_secret_scrub.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_board_needs_review.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_board_running.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_branch_replies.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_bundle.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_bundle_not_type_mismatch.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_charcount.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_cli_entrypoint.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_cli_help.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_cli_vm_path.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_collect.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_collect_engagements.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_collect_runs.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_collect_sent.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_comparability.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_control_chars_refused.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_conversation_paging.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_count_for.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_docs_links.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_doctor.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_doctor_all_permissions.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_doctor_next_step.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_duplicate_front_matter_keys.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_editorial_audit.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_editorial_n3_n4.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_engagements.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_external_acceptance.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_facebook_auth.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_facebook_stage1.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_fake_api.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_form_spec.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_form_spec_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_forms.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_fresh_install.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_front_matter_injection.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_healthcheck_notifications.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_hypotheses.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_hypothesis_boundaries.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_hypothesis_units.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_impact_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_inbox_granted_scopes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_incident_notifications.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_independent_thread_review.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_independent_topic_review.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_independent_topic_review_r2.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_inflight.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_inflight_tag_body_hash.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_jst.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_limits_policy.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_limits_stage4.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_lint.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_list_projections.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_llm_trial.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_llm_trial_engage.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_lock.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_m2_independent.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_maintain.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_mastodon_adapter.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_mastodon_visibility.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_max_per_run.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_mcp.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_mcp_robustness.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_measured.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_media_accounts.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_media_next_steps.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_media_roundtrip.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_media_traits.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_meta_stage0.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_mismatch_diagnostics.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_n5_reply_null_element.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_n6_replies_incomplete_ledger.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_n7_doctor_error_body.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_no_limits.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_observation_provenance.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_operations_handoff.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_packaging.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_preview.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_production_mode.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_pull_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_pulse.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_queue.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_quiet_hours.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_r2_r4_r5.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_read_cli_bare_runtimeerror.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_reason_adoption.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_redact.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_redirect_token_leak.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_refresh.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_refresh_destination.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_rejudge_new.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_rejudge_r2_r3.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_replies.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_replies_refresh.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_repo_lock.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_repo_sync.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_report_checkout_import.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_report_http.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_report_isolation.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_report_service.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_retract_already_gone.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_reverse_audit.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_review_case_id_cluster_m2.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_review_case_id_cluster_r2.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_review_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_review_evidence_account.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_review_form_spec_and_case_id.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_review_provenance.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_review_records.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_revoke.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_roundtrip.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_run_missing_env.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_run_record_failclosed.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_runs_collected.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_runs_read_rows.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_schedule_multiple.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_schedule_view.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_scopes_source_requested.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_search_engage_targets.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_search_media_routes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_secret_value_redact.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_secrets_grep.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_security_small_fixes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_select.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_selfupdate.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_send.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_send_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_send_control_chars.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_send_guard_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_send_media.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_send_visibility.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_sent_integrity.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_server_json.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_site.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_skill_doc.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_study_report.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_systemd.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_thread_publish.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_thread_read.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_threadrun.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_threads_read_permissions.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_threadshape.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_thth_root.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_token_exists.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_token_scopes_record.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_token_set.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_topic.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_topic_advice.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_topic_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_topic_models.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_topic_review_fixes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_topic_shelf_observers.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_topic_store.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_topics_record_concurrent.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_topics_tool.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_trial_frictions.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v1015_path_semantics.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v1015_take_what_we_can.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v210_admin_transaction.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v210_approve_account.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v210_length.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v210_lock_wait.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v210_mastodon_scopes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v210_mentions.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v210_post_urls.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v210_repo_paths.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v210_reposts.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v210_study_add.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v210_tool_version.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v210_unanswered.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v210_unanswered_scope.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v210_where_arguments.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v210_where_filters.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v210_who_arguments.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v211_auth_integration.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v211_authflow.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v211_bluesky_stdin.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v211_doctor_binding.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v211_mastodon_auth.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v211_x_auth.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v212_ask_coordination.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v212_budget.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v212_budget_auth.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v212_budget_mcp.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v212_deletion.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v212_leave.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v212_leave_gate.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v212_leave_providers.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v212_leave_token_safety.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v212_mastodon_guide.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v212_mcp_compat.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v212_missing_token.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v212_read_coordination.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v212_relay.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v212_server_writes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v212_token_parent.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v212_write_storage.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v2131_send_dry_run.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v2131_threads_publish_wait.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v2132_send_inflight_hint.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v2132_threads_create_timeout.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v2132_threads_create_unknown.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_acceptance_fixes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_adts_asf.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_attachment_kinds.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_bluesky_external.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_bluesky_media.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_bluesky_metadata.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_bluesky_metadata_uri.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_bluesky_metadata_video.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_bluesky_record.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_bluesky_record_video.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_bluesky_video.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_bluesky_webm_named.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_bmff_typed_metadata.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_budget_lock.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_capabilities.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_carryover_timeout.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_graphemes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_mastodon_auth_media.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_mastodon_bmff_audio.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_mastodon_flac.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_mastodon_gif.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_mastodon_link.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_mastodon_media.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_mastodon_mp3.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_mastodon_ogg_opus.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_mastodon_ogg_vorbis.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_mastodon_poll.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_mastodon_primary_size_boundary.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_mastodon_quote.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_mastodon_thumbnail.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_mastodon_wav.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_mastodon_webm_audio.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_mastodon_webm_video.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_media_cleanup.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_media_formats.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_media_foundation.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_media_prepared.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_media_relay.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_media_relay_refusals.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_media_upload.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_review_followups.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_stage810_audit.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_static_diagnostics.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_stop_observation.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_systemd_worker.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_threads_ghost.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_threads_gif.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_threads_link.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_threads_media.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_threads_media_spoiler.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_threads_poll.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_threads_quote.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_threads_quote_media.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_threads_replies.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_threads_text.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_threads_text_spoiler.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_threads_video.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_transport_review.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_video_typed_metadata.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_vorbis_comment_boundary.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v213_webm_schema_boundary.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v2141_draft_lint_reason.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v2141_managed_repo_umask.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v214_release_signing.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v214_x_adapter.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v214_x_auth.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v214_x_media.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v214_x_posts_budget.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v21b_approved_writes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v28_tags.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3100_docs.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3100_invite_admin_approval.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3100_invite_create.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3100_invite_credential.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3100_invite_limits.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3100_invite_worker.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v310_morning.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v310_search_timeout.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v310_watch_words.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3111_observe_counts_only.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3111_observe_no_world.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v311_leave_same_user.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v311_mastodon_retract.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v311_morning_overdue.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v311_morning_own_exclusion.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v311_morning_unanswered_window.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v311_notifications_guidance.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v311_replies_owned.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3120_activity.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3120_admin_write_reasons.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3120_guard.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3120_worker_version.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v312_leave_shared_token.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v312_own_handles_stopped.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v312_report_admin.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v312_report_channel.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v312_report_inbox.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v312_report_mcp_user.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3140_api_relay.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3140_invite_key.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3140_remote_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3140_server_reads.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3142_browser_login.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3143_activity_push.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3143_cli_umask_leave.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3143_inflight_remote.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3143_managed_repo_recover.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v315_reactions.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v317_run_lock_wait.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3180_json_names.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3180_map_timer.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3180_where_filters.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3180_where_keep.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3192_publish_hold.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v31_analysis.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v31_collection.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3200_x_weighted_length.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v320_reply_to_file_display.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v320_reply_to_file_lint.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v320_reply_to_file_resolve.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v320_report_fixes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3220_account_scheduled.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3220_bluesky_reply_control.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3220_bluesky_retract.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3220_invite_mastodon.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3220_mentions_inbox.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v3250_burst_reply_queue.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v330_fingerprint_version.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v330_held.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v330_held_names.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v330_last_refusals.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v330_notification_route.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v330_observe.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v330_report_friction.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v330_report_words.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v330_reports_effect.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v331_inflight_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v331_listing_resolve.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v331_outbox_retention.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v331_publish_status.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v331_self_resolve.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v340_plaza_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v340_plaza_docs.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v340_plaza_fields.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v340_plaza_mcp.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v340_plaza_morning.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v340_plaza_observe.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v340_plaza_open.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v340_plaza_open_confirm.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v340_plaza_reply.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v340_plaza_store.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v350_map_docs.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v350_map_nodes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v350_map_observe.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v350_map_plaza.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v350_map_retention.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v350_map_self.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v350_map_show.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v350_map_world.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v351_leave_timers.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v351_plaza_open_holes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v351_who_owned.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v360_goal_analytics.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v360_goal_docs.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v360_goal_observe_map.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v360_goal_plaza.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v360_goal_record.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v360_goal_send.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v360_report_timeline.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v370_account_self_healing.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v370_approve_pending.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v370_click_attribution.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v370_collection_stale_basis.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v370_docs.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v370_follow_comparison.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v370_local_path.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v370_weekly_goals.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v370_where_aggregate.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v370_where_also.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v370_where_zero.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v380_docs.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v380_plaza_digest.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v380_plaza_from.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v380_plaza_mcp.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v380_plaza_moments.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v380_plaza_owner.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v380_plaza_received.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v380_plaza_triggers.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v381_plaza_visibility_default.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v382_confirm_file.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v382_first_stage_not_refusal.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v382_reader_lock_and_push_pending.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v382_sync_without_fetch_head.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v390_docs.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v390_per_post_clicks.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v390_where_rate.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v390_where_suggest.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v391_plaza_text_numbers.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_jikki_1017.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_jikki_1017_bookmark.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s1_approve.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s1_deliveries.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s1_events.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s1_fingerprints.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s1_guard.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s1_locks.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s1_principals.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s1_publish.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s1_remote.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s2_adapter.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s2_audit.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s2_audit_fixes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s2_commit.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s2_convert.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s2_held.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s2_oauth1.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s2_principal_auth.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s2_syntax_readback.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s3_adapter.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s3_convert.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s3_flow.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s4_announce.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s4_audit_fixes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s4_bookmark.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s4_ledger.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s5_audit_fixes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s5_conflict.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s5_detect.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s5_guard_remote.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s5_jikki.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s6_audit_fixes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s6_bundle.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v400_s6_collect.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v401_board_hatena_token.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v401_bookmark_burst.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v40_contract_json.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v410_audit_night.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v410_bookmark_batch.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v411_batch_cleanup.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v420_bookmark_edit.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v420_bookmark_tag_bytes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v421_audit_fixes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v422_bookmark_rejections.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v422_sparse_checkout.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v430_reply_batch.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v431_stopped_timer.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v440_reply_follow.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v441_approval_ledger.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v442_sync_lookup.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v450_x_full_archive.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v452_schedule_stock.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v453_approve_redo.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v453_bookmark_gate.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v454_schedule_thin.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v455_media_inflight_published.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v455_threads_publish_timeout.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v456_not_after.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v500_scenario.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v50_audit_fixes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v50_dashboard.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_v50_joined.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_value_domains_shown.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_version.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_where_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_where_threads_tag_author.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_who_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_writeback_rebase.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_writeback_validate.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_x_community.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_x_list.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_x_metrics.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_x_owned_metrics.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_x_search_thread.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_x_token_autorefresh.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/tests/test_x_trends_counts.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/__init__.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/__main__.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/_grapheme_data.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/account_report.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/account_settings.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/activity.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/adapters/_x_text_data.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/adapters/auth_mastodon.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/adapters/auth_threads.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/adapters/auth_x.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/adapters/bluesky.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/adapters/bluesky_media.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/adapters/bluesky_video.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/adapters/fotolife.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/adapters/hatena_common.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/adapters/hatenablog.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/adapters/hatenabookmark.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/adapters/hatenastar.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/adapters/mastodon.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/adapters/mastodon_media.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/adapters/threads.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/adapters/threads_media.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/adapters/x.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/adapters/x_media.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/adapters/x_text.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/admin_diagnose.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/admin_notifications.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/admin_report.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/advise.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/after_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/analytics_clicks.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/analytics_comparison.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/analytics_goals.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/analytics_report.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/analytics_shapes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/analytics_threads.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/analytics_weekly.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/announce.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/api_diagnostic.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/api_requests.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/appconfig.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/appenv.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/approval.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/approval_ledger.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/approve_pending.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/archive_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/article_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/article_reactions.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/ask.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/ask_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/assess.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/audioformats.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/auth_log.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/authclients.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/authpassword.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/bluesky_metadata.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/bookmark_batch.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/bookmark_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/budget_x.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/budget_x_posts.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/bundle.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/burst_queue.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/click_attribution.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/collection_context.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/collection_status.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/community_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/conflict_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/deletion.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/deliveries.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/deliveries_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/doctor.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/ebmlaudio.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/ebmlvideo.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/engagements.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/fingerprint_golden.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/flacformats.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/forms.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/fotolife_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/goals.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/graphemes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/guard.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/handoff_cursor.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/hatena_bookmark.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/hatena_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/hatena_conflict.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/hatena_convert.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/hatena_entry.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/hatena_fotolife.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/hatena_publish.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/hatena_reactions.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/healthcheck.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/httpsafe.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/incident.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/inflight.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/inflight_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/inflight_resolve.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/invites.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/jst.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/limits_view.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/list_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/lock.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/managed_repo.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/map_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/map_store.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/map_view.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/map_world.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/media_cleanup.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/media_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/media_observations.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/media_relay.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/media_traits/bluesky.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/media_traits/facebook.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/media_traits/fotolife.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/media_traits/hatenablog.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/media_traits/hatenabookmark.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/media_traits/mastodon.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/media_traits/misskey.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/media_traits/threads.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/media_traits/x.json +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/media_uploads.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/mediaformats.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/mpeg_audio.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/notification_route.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/oauth1.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/oggformats.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/operations_handoff.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/plaza.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/plaza_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/plaza_from.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/plaza_moments.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/plaza_observe.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/plaza_reads.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/plaza_redact.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/postid.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/principal_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/principals.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/private_store.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/publish_hold.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/pulse.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/reaction_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/reactions.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/read_coordination.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/read_window.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/redact.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/refusals.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/remote.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/replies.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/reply_follow.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/report.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/report_details.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/report_http.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/report_inbox.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/report_isolation.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/report_service.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/report_timeline.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/retract_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/runs.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/scenario_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/scopes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/secrets_fs.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/select.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/selfupdate.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/sent.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/server_files.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/server_reads.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/server_writes.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/stop_observation.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/study_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/study_report.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/summary_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/systemd_gen.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/tags.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/threadrun.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/threads_read_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/threadshape.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/threadthrow.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/timer_cleanup.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/tool_version.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/topic_advice.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/topic_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/topic_models.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/topic_store.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/topics.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/trends_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/unanswered.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/vorbisformats.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/watch_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/where_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/where_keep.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/where_suggest.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/who_cli.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/worker_version.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/writeback.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/x_archive.py +0 -0
- {thth-5.2.0 → thth-5.4.0}/thth/x_metrics.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: thth
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.4.0
|
|
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
|
|
@@ -124,7 +124,7 @@ MCP の道具は CLI の写しで、同じ `thth` コマンドを呼ぶだけで
|
|
|
124
124
|
|
|
125
125
|
`thth --help` で各コマンドの説明が出ます。
|
|
126
126
|
|
|
127
|
-
動くもの(`thth --help` の全サブコマンド): `lint`・`preview`・`approve`・`approvals`・`account`・`revoke`・`posts`・`replies`・`measured`・`threads`・`after`・`analytics-report`・`study-report`・`study`・`unanswered`・`handoff-report`・`observe`・`morning`・`events`・`summary`・`scenario`・`dashboard`・`deliveries`・`media`・`article`・`conflict`・`hatena`・`bookmark`・`serve-reports`・`worker`・`topics`・`forms`・`queue`・`schedule`・`throw`・`run`・`systemd`・`board`・`collect`・`pull`・`auth`・`refresh`・`maintain`・`send`・`doctor`・`app`・`token`・`ask`・`mentions`・`profile`・`thread`・`where`・`where-log`・`who`・`retract`・`edit`・`reply`・`repost`・`unrepost`・`like`・`unlike`・`list`・`community`・`trends`・`counts`・`archive`・`principal`・`fotolife`・`inflight`・`location`・`notifications`・`report`・`plaza`・`map`・`admin`・`login`・`logout`。
|
|
127
|
+
動くもの(`thth --help` の全サブコマンド): `lint`・`preview`・`approve`・`approvals`・`account`・`revoke`・`posts`・`replies`・`measured`・`threads`・`after`・`analytics-report`・`study-report`・`study`・`unanswered`・`handoff-report`・`observe`・`morning`・`events`・`summary`・`scenario`・`dashboard`・`deliveries`・`media`・`article`・`conflict`・`hatena`・`bookmark`・`serve-reports`・`worker`・`topics`・`forms`・`queue`・`schedule`・`throw`・`run`・`systemd`・`board`・`collect`・`pull`・`auth`・`refresh`・`maintain`・`send`・`doctor`・`app`・`token`・`ask`・`mentions`・`profile`・`thread`・`where`・`where-log`・`who`・`retract`・`edit`・`reply`・`comments`・`quota`・`repost`・`unrepost`・`like`・`unlike`・`list`・`community`・`trends`・`counts`・`archive`・`principal`・`ads`・`webhook`・`fotolife`・`inflight`・`location`・`notifications`・`report`・`plaza`・`map`・`admin`・`login`・`logout`。
|
|
128
128
|
|
|
129
129
|
## 版と配布
|
|
130
130
|
|
|
@@ -100,7 +100,7 @@ MCP の道具は CLI の写しで、同じ `thth` コマンドを呼ぶだけで
|
|
|
100
100
|
|
|
101
101
|
`thth --help` で各コマンドの説明が出ます。
|
|
102
102
|
|
|
103
|
-
動くもの(`thth --help` の全サブコマンド): `lint`・`preview`・`approve`・`approvals`・`account`・`revoke`・`posts`・`replies`・`measured`・`threads`・`after`・`analytics-report`・`study-report`・`study`・`unanswered`・`handoff-report`・`observe`・`morning`・`events`・`summary`・`scenario`・`dashboard`・`deliveries`・`media`・`article`・`conflict`・`hatena`・`bookmark`・`serve-reports`・`worker`・`topics`・`forms`・`queue`・`schedule`・`throw`・`run`・`systemd`・`board`・`collect`・`pull`・`auth`・`refresh`・`maintain`・`send`・`doctor`・`app`・`token`・`ask`・`mentions`・`profile`・`thread`・`where`・`where-log`・`who`・`retract`・`edit`・`reply`・`repost`・`unrepost`・`like`・`unlike`・`list`・`community`・`trends`・`counts`・`archive`・`principal`・`fotolife`・`inflight`・`location`・`notifications`・`report`・`plaza`・`map`・`admin`・`login`・`logout`。
|
|
103
|
+
動くもの(`thth --help` の全サブコマンド): `lint`・`preview`・`approve`・`approvals`・`account`・`revoke`・`posts`・`replies`・`measured`・`threads`・`after`・`analytics-report`・`study-report`・`study`・`unanswered`・`handoff-report`・`observe`・`morning`・`events`・`summary`・`scenario`・`dashboard`・`deliveries`・`media`・`article`・`conflict`・`hatena`・`bookmark`・`serve-reports`・`worker`・`topics`・`forms`・`queue`・`schedule`・`throw`・`run`・`systemd`・`board`・`collect`・`pull`・`auth`・`refresh`・`maintain`・`send`・`doctor`・`app`・`token`・`ask`・`mentions`・`profile`・`thread`・`where`・`where-log`・`who`・`retract`・`edit`・`reply`・`comments`・`quota`・`repost`・`unrepost`・`like`・`unlike`・`list`・`community`・`trends`・`counts`・`archive`・`principal`・`ads`・`webhook`・`fotolife`・`inflight`・`location`・`notifications`・`report`・`plaza`・`map`・`admin`・`login`・`logout`。
|
|
104
104
|
|
|
105
105
|
## 版と配布
|
|
106
106
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"account": "demo-instagram",
|
|
3
|
+
"project": "demo",
|
|
4
|
+
"media": "instagram",
|
|
5
|
+
"handle": "0",
|
|
6
|
+
"ig_user_id": "0",
|
|
7
|
+
"page_id": "0",
|
|
8
|
+
"user_id": "",
|
|
9
|
+
"repo_dir": "$THTH_ROOT/repos/demo",
|
|
10
|
+
"queue_dir": "docs/sns/queue",
|
|
11
|
+
"replies_dir": "data/sns/replies",
|
|
12
|
+
"quiet_hours": [
|
|
13
|
+
"22:00",
|
|
14
|
+
"07:00"
|
|
15
|
+
],
|
|
16
|
+
"min_interval_hours": 6,
|
|
17
|
+
"max_per_run": 1,
|
|
18
|
+
"tick_minutes": 10,
|
|
19
|
+
"collect_days": 14,
|
|
20
|
+
"hashtags": false,
|
|
21
|
+
"max_hashtags": 3,
|
|
22
|
+
"stale_days": 7,
|
|
23
|
+
"env": "~/.config/thth/demo-instagram.env",
|
|
24
|
+
"token": "~/.config/thth/demo-instagram.token",
|
|
25
|
+
"ping": "wrapper",
|
|
26
|
+
"timeout": 300,
|
|
27
|
+
"dry_run_env": "THTH_DRY_RUN",
|
|
28
|
+
"production": false,
|
|
29
|
+
"scheduled": false
|
|
30
|
+
}
|
|
@@ -57,7 +57,10 @@ FACEBOOK_NOTE = (
|
|
|
57
57
|
"の id ではない)。post_id は <ページID>_<数字>。画像は 1〜10 枚(2 枚以上は 1 本にまとまる)。"
|
|
58
58
|
"できないこと: 動画・字幕・投票・返信に画像・いいね・シェア・inbox。投稿の編集とコメントを隠す・消すは "
|
|
59
59
|
"CLI(thth edit・thth reply)だけ。文字数の上限 5,000 は THTH の線(台帳の char_limit で上げられる)。"
|
|
60
|
-
"facebook_data_access の行は Meta のデータに触れる期限(14 日を切ったら thth auth
|
|
60
|
+
"facebook_data_access の行は Meta のデータに触れる期限(14 日を切ったら thth auth のやり直し)。"
|
|
61
|
+
"instagram の口座(段 3)は 1 プロ口座 1 口座で、作るのは CLI(--media instagram --handle <ig_user_id> "
|
|
62
|
+
"--page-id <ページID>)と VM での thth auth。出せるのは JPEG の画像 1〜20 枚だけ(文だけ・PNG・動画は断る)。"
|
|
63
|
+
"post_id は数字。キャプションは 2,200 字。90 日ごとに thth auth のやり直し(instagram_data_access の行)")
|
|
61
64
|
|
|
62
65
|
TOOLS = [
|
|
63
66
|
{
|
|
@@ -106,6 +106,25 @@ THTH は CLI ツール。あなた(エージェント)が使う MCP の道
|
|
|
106
106
|
- **できないこと**(この版の口に無い・`tool.capabilities` の facebook の行): 動画・字幕・投票・返信の制御・返信に画像、いいね・シェア(`unsupported_on_platform`)、inbox と言及、ほかのページの観測。
|
|
107
107
|
- **文字数の上限 5,000 は THTH の線**(Facebook の公式の上限ではない)。超えると lint が断り、上げ方(口座の台帳の `char_limit`)を添える。
|
|
108
108
|
- **データに触れる期限**: ページの鍵そのものに期限は無いが、Meta の `data_access_expires_at`(通常 90 日)が 14 日を切ると `thth maintain` が `data_access_expiring`(過ぎたら `data_access_expired`)と言い、`thth events` に `token_data_access_expiring` が出る。対処は `thth auth <口座> --by <名前>` のやり直し(人が VM で打つ)。
|
|
109
|
+
- **量の制限**(段 2): `thth quota <口座> [--json]` が Meta の使用量のヘッダ(`X-App-Usage`・`X-Business-Use-Case-Usage`)と待ちを返す(読むだけ・MCP には無い)。Meta が量の制限で断ると(code 4・17・32・80001 など)断り文は `meta_rate_limited` で、**出ていない**。Meta が言う戻るまでの分(無ければ 60 分・THTH の線)だけ、その口座の timer は出さず(`thth throw` は `rate_limited`)、明けた次の回に同じ原稿が出る。待ちは `state/<口座>/meta_usage.json`。
|
|
110
|
+
|
|
111
|
+
## Instagram(Meta 計画 段 3・10/29)
|
|
112
|
+
|
|
113
|
+
- **口座の作り方**: 1 つのプロ口座を 1 口座で扱う。鍵はつながっている Facebook ページの鍵(Facebook ログインの道)で、口座ごとに別の `.token`。`thth account add <口座> --media instagram --project <p> --handle <ig_user_id> --page-id <ページID> --by <名前>` のあと `thth auth <口座> --by <名前>`(VM で人が打つ・MCP には無い)。`ig_user_id` はプロ口座の数字の id(`@` の名前ではない)で、ページの `instagram_business_account` から引ける。認可はページにつながっている Instagram が台帳の `ig_user_id` と同じときだけ保存する(違えば `instagram_account_mismatch`、つながっていなければ `instagram_account_not_linked`)。
|
|
114
|
+
- **post_id の形**: 数字(例 `17895695668004550`)。返事の宛先(`reply_to`)は**コメントの id**。
|
|
115
|
+
- **できること**: JPEG の画像 1〜20 枚(8MB・縦横比 4:5〜1.91:1・2 枚以上はカルーセル)・`alt`(1000 字まで)・`post_options: {is_ai_generated: true}`(AI で作った印・承認の指紋に入る)・コメントへの返事・取り下げ・最近の投稿・コメントと返事を読む・数(いいね・コメント・表示・リーチ・シェア・保存)・口座の日次(`thth collect`)・`thth quota`(1 日の公開の上限 `content_publishing_limit` と使用量)。公開は Meta が `https://thth.me/m/` の一時 URL から画像を取りに来る(Threads と同じ relay)。公開の前に毎回 1 日の上限を読み、届いていれば出さない。
|
|
116
|
+
- **コメントを隠す・戻す・消す**は `thth reply hide|unhide|delete`(Facebook と同じ)。**コメント欄の開け閉め** `thth comments close|open <口座> <post_id> --by <名前>`(1 段・戻せる・記録は moderation)。どれも台帳の `production: true` が要る。MCP には無い。
|
|
117
|
+
- **できないこと**: 文だけの投稿(Instagram に無い)・PNG・GIF・WebP(JPEG だけ)・動画とリール(資材が来てから)・キャプションの編集・いいね・ストーリー・DM・ハッシュタグ検索。コメントは webhook でなく採取で拾う(審査まで)。
|
|
118
|
+
- **文字数の上限 2,200**(キャプションの公式の上限)。ハッシュタグ 30・@ 20 は媒体が数える。
|
|
119
|
+
- **90 日ごとに `thth auth` をやり直す**: instagram の権限はデータに触れる期限(`data_access_expires_at`)に当たる見込み。14 日を切ると `thth maintain` が `data_access_expiring` と言う。
|
|
120
|
+
|
|
121
|
+
## 広告(Meta 計画 段 4・読むだけ・10/29)
|
|
122
|
+
|
|
123
|
+
- **運営者の CLI だけ**(MCP の道具には無い)。広告は投稿先の媒体ではないので `thth account` でなく `thth ads`。台帳は VM の `adaccounts/<名前>.json`(上限 `ceilings` は 0・`ads_enabled`/`production` は false が既定)、状態は `adaccount_state/<名前>/`。
|
|
124
|
+
- **Meta に書く命令は無い**(作る・配信・予算・`spend_cap`・止めるは段 5)。`spend_cap` と THTH の上限を上げる命令は段 5 になっても無い——`spend_cap` は masaru が広告マネージャで入れ、上限は VM の台帳を直接書く。
|
|
125
|
+
- 命令: `thth ads add <名前> --act-id <数字> --project <p> [--page <口座>] [--ig <口座>] --by <名前>` → `thth ads auth <名前> --by <名前>`(ユーザーの長い鍵・約 60 日)→ `thth ads show|insights|doctor|accounts <名前>`・`thth ads collect`(`thth collect <口座>` のたびにも結んだ広告の口座を読む)。`thth ads auth <名前> --exchange` は鍵の再交換で期限が延びるかを 1 回試す。
|
|
126
|
+
- 金額は**最小単位の整数**(JPY なら円)。通貨が JPY 以外の口座は台帳に `writes_refused: ads_currency_unverified` が付く(段 5 の書く操作を断る)。
|
|
127
|
+
- 見張り(`thth events`・dashboard の要対応・`thth morning` の予定の段): `ads_active_outside_thth`(THTH の外で誰かが配信を始めた・最優先)・`ads_no_end_time`・`ads_account_status`・`ads_spend_cap_unset`(`spend_cap` が入っていない)・`ads_spend_cap_near`・`ads_budget_low`・`ads_token_expiring`(鍵の残り 14 日・`thth maintain` も `ads_token_expiring`)・`ads_read_failed`。
|
|
109
128
|
|
|
110
129
|
## 何を拒むか
|
|
111
130
|
|
|
@@ -40,11 +40,11 @@
|
|
|
40
40
|
<script>
|
|
41
41
|
/* ---- 共通(4 つの型で同じ。直すなら 4 つとも同じに) ---- */
|
|
42
42
|
const THTH_SCHEMA="thth.dashboard/1";
|
|
43
|
-
const THTH_MEDIUM={threads:"Threads",x:"X",bluesky:"Bluesky",mastodon:"Mastodon",facebook:"Facebook",hatenablog:"はてなブログ",hatena_bookmark:"はてブ",site:"サイト"};
|
|
43
|
+
const THTH_MEDIUM={threads:"Threads",x:"X",bluesky:"Bluesky",mastodon:"Mastodon",facebook:"Facebook",instagram:"Instagram",hatenablog:"はてなブログ",hatena_bookmark:"はてブ",site:"サイト"};
|
|
44
44
|
const THTH_STAGE={collect:"リサーチ",diary:"仮説",article:"本記事",announce:"SNS 告知",warm:"エンゲージ"};
|
|
45
45
|
const THTH_EVENT={researched:"リサーチ済み",hypothesis:"仮説を書いた",article_published:"本記事を公開",closed:"終えた"};
|
|
46
|
-
const THTH_KIND={scenario_stalled:"停滞",series_low:"ストック不足",untied_drafts:"未分類の下書き",unanswered_replies:"未返信",schedule_low:"予約切れ間近",schedule_thin:"予約が薄い",not_after_passed:"期限切れ",publish_held:"公開を停止中",account_stopped:"口座が停止",inflight_open:"公開の結果待ち",delivery_held:"配信の保留",delivery_behind:"記事の更新待ち",principal_stopped:"はてな ID が停止",budget_exhausted:"予算切れ",token_data_access_expiring:"データの期限が近い(認可し直す)"};
|
|
47
|
-
const THTH_REASON={scenario_not_installed:"シナリオ(段 1)が未導入",no_declarations:"宣言が読めない",scenario_schema_unknown:"シナリオの版が違う",blog_pv_not_collected:"ブログ PV は取っていない",article_clicks_not_connected:"記事側の計測とつないでいない",needs_scenario_show:"詳細が読めない",posts_unlisted:"投稿の一覧が無い",deliveries_unlisted:"配信の一覧が無い",scenario_show_unavailable:"詳細が読めない",accounts_not_summed:"口座をまたいで足さない(口座ごとに見る)",not_measured_yet:"実測がまだ無い",not_published_yet:"まだ公開していない",no_deliveries:"配信がまだ無い",measured_unreadable:"実測の記録が読めない",reactions_unreadable:"反応の記録が読めない",account_unreadable:"口座の台帳が読めない",repo_unreadable:"原稿の置き場が読めない",scenarios_unreadable:"キャンペーン・シリーズの宣言が読めない",queue_unreadable:"原稿の置き場が読めない",sent_unreadable:"送った記録が読めない",deliveries_unreadable:"配信の記録が読めない",replies_unreadable:"返信の記録が読めない",inbox_unreadable:"通知の記録が読めない",source_unreadable:"記事の正本が読めない",inflight_unreadable:"公開の途中の記録が読めない",budget_unreadable:"X の予算の記録が読めない",hatena_account_missing:"はてなの口座がつながっていない",series_account_unknown:"シリーズの口座に知らない名前がある",series_account_out_of_scope:"この鍵では見えない口座がある(その分は数えない)",scenario_unreadable:"キャンペーン・シリーズが読めない",events_unreadable:"出来事が読めない",summary_unreadable:"直近 7 日の集計が読めない",summary_previous_unreadable:"前週の集計が読めない",schedule_unreadable:"予定が読めない",approve_pending_unreadable:"承認待ちが読めない",published_unreadable:"公開の数が読めない",followers_unreadable:"フォロワーの数が読めない",stopped_unreadable:"止まりの印が読めない",unanswered_unreadable:"未返信が読めない",full_trimmed:"詳細は大きすぎて省いた",target_unknown:"対象が見つからない"};
|
|
46
|
+
const THTH_KIND={scenario_stalled:"停滞",series_low:"ストック不足",untied_drafts:"未分類の下書き",unanswered_replies:"未返信",schedule_low:"予約切れ間近",schedule_thin:"予約が薄い",not_after_passed:"期限切れ",publish_held:"公開を停止中",account_stopped:"口座が停止",inflight_open:"公開の結果待ち",delivery_held:"配信の保留",delivery_behind:"記事の更新待ち",principal_stopped:"はてな ID が停止",budget_exhausted:"予算切れ",token_data_access_expiring:"データの期限が近い(認可し直す)",ads_active_outside_thth:"THTH の外で広告が配信中",ads_no_end_time:"終了日の無い広告が配信中",ads_account_status:"広告アカウントの状態",ads_spend_over_estimate:"広告の支出が見積もり超え",ads_spend_cap_near:"広告の支出が上限に近い",ads_budget_low:"広告の月の上限の残りが少ない",ads_spend_cap_unset:"広告アカウントに支出の上限が無い",ads_token_expiring:"広告の鍵の期限が近い",ads_read_failed:"広告の口座を読めない",webhook_down:"Webhook の取り込みが止まっている"};
|
|
47
|
+
const THTH_REASON={scenario_not_installed:"シナリオ(段 1)が未導入",no_declarations:"宣言が読めない",scenario_schema_unknown:"シナリオの版が違う",blog_pv_not_collected:"ブログ PV は取っていない",article_clicks_not_connected:"記事側の計測とつないでいない",needs_scenario_show:"詳細が読めない",posts_unlisted:"投稿の一覧が無い",deliveries_unlisted:"配信の一覧が無い",scenario_show_unavailable:"詳細が読めない",accounts_not_summed:"口座をまたいで足さない(口座ごとに見る)",not_measured_yet:"実測がまだ無い",not_published_yet:"まだ公開していない",no_deliveries:"配信がまだ無い",measured_unreadable:"実測の記録が読めない",reactions_unreadable:"反応の記録が読めない",account_unreadable:"口座の台帳が読めない",repo_unreadable:"原稿の置き場が読めない",scenarios_unreadable:"キャンペーン・シリーズの宣言が読めない",queue_unreadable:"原稿の置き場が読めない",sent_unreadable:"送った記録が読めない",deliveries_unreadable:"配信の記録が読めない",replies_unreadable:"返信の記録が読めない",inbox_unreadable:"通知の記録が読めない",source_unreadable:"記事の正本が読めない",inflight_unreadable:"公開の途中の記録が読めない",budget_unreadable:"X の予算の記録が読めない",hatena_account_missing:"はてなの口座がつながっていない",series_account_unknown:"シリーズの口座に知らない名前がある",series_account_out_of_scope:"この鍵では見えない口座がある(その分は数えない)",scenario_unreadable:"キャンペーン・シリーズが読めない",events_unreadable:"出来事が読めない",summary_unreadable:"直近 7 日の集計が読めない",summary_previous_unreadable:"前週の集計が読めない",schedule_unreadable:"予定が読めない",approve_pending_unreadable:"承認待ちが読めない",published_unreadable:"公開の数が読めない",followers_unreadable:"フォロワーの数が読めない",stopped_unreadable:"止まりの印が読めない",unanswered_unreadable:"未返信が読めない",full_trimmed:"詳細は大きすぎて省いた",target_unknown:"対象が見つからない",ads_unreadable:"広告の口座を読めない",webhook_unreadable:"Webhook の記録を読めない"};
|
|
48
48
|
function ththEsc(s){return String(s==null?"":s).replace(/[&<>"']/g,c=>({"&":"&","<":"<",">":">",'"':""","'":"'"}[c]));}
|
|
49
49
|
function ththNum(v){return v==null?"—":(typeof v==="number"?v.toLocaleString("ja-JP"):ththEsc(v));}
|
|
50
50
|
function ththPct(v){return v==null?"—":v+"%";}
|
|
@@ -44,11 +44,11 @@
|
|
|
44
44
|
<script>
|
|
45
45
|
/* ---- 共通(4 つの型で同じ。直すなら 4 つとも同じに) ---- */
|
|
46
46
|
const THTH_SCHEMA="thth.dashboard/1";
|
|
47
|
-
const THTH_MEDIUM={threads:"Threads",x:"X",bluesky:"Bluesky",mastodon:"Mastodon",facebook:"Facebook",hatenablog:"はてなブログ",hatena_bookmark:"はてブ",site:"サイト"};
|
|
47
|
+
const THTH_MEDIUM={threads:"Threads",x:"X",bluesky:"Bluesky",mastodon:"Mastodon",facebook:"Facebook",instagram:"Instagram",hatenablog:"はてなブログ",hatena_bookmark:"はてブ",site:"サイト"};
|
|
48
48
|
const THTH_STAGE={collect:"リサーチ",diary:"仮説",article:"本記事",announce:"SNS 告知",warm:"エンゲージ"};
|
|
49
49
|
const THTH_EVENT={researched:"リサーチ済み",hypothesis:"仮説を書いた",article_published:"本記事を公開",closed:"終えた"};
|
|
50
|
-
const THTH_KIND={scenario_stalled:"停滞",series_low:"ストック不足",untied_drafts:"未分類の下書き",unanswered_replies:"未返信",schedule_low:"予約切れ間近",schedule_thin:"予約が薄い",not_after_passed:"期限切れ",publish_held:"公開を停止中",account_stopped:"口座が停止",inflight_open:"公開の結果待ち",delivery_held:"配信の保留",delivery_behind:"記事の更新待ち",principal_stopped:"はてな ID が停止",budget_exhausted:"予算切れ",token_data_access_expiring:"データの期限が近い(認可し直す)"};
|
|
51
|
-
const THTH_REASON={scenario_not_installed:"シナリオ(段 1)が未導入",no_declarations:"宣言が読めない",scenario_schema_unknown:"シナリオの版が違う",blog_pv_not_collected:"ブログ PV は取っていない",article_clicks_not_connected:"記事側の計測とつないでいない",needs_scenario_show:"詳細が読めない",posts_unlisted:"投稿の一覧が無い",deliveries_unlisted:"配信の一覧が無い",scenario_show_unavailable:"詳細が読めない",accounts_not_summed:"口座をまたいで足さない(口座ごとに見る)",not_measured_yet:"実測がまだ無い",not_published_yet:"まだ公開していない",no_deliveries:"配信がまだ無い",measured_unreadable:"実測の記録が読めない",reactions_unreadable:"反応の記録が読めない",account_unreadable:"口座の台帳が読めない",repo_unreadable:"原稿の置き場が読めない",scenarios_unreadable:"キャンペーン・シリーズの宣言が読めない",queue_unreadable:"原稿の置き場が読めない",sent_unreadable:"送った記録が読めない",deliveries_unreadable:"配信の記録が読めない",replies_unreadable:"返信の記録が読めない",inbox_unreadable:"通知の記録が読めない",source_unreadable:"記事の正本が読めない",inflight_unreadable:"公開の途中の記録が読めない",budget_unreadable:"X の予算の記録が読めない",hatena_account_missing:"はてなの口座がつながっていない",series_account_unknown:"シリーズの口座に知らない名前がある",series_account_out_of_scope:"この鍵では見えない口座がある(その分は数えない)",scenario_unreadable:"キャンペーン・シリーズが読めない",events_unreadable:"出来事が読めない",summary_unreadable:"直近 7 日の集計が読めない",summary_previous_unreadable:"前週の集計が読めない",schedule_unreadable:"予定が読めない",approve_pending_unreadable:"承認待ちが読めない",published_unreadable:"公開の数が読めない",followers_unreadable:"フォロワーの数が読めない",stopped_unreadable:"止まりの印が読めない",unanswered_unreadable:"未返信が読めない",full_trimmed:"詳細は大きすぎて省いた",target_unknown:"対象が見つからない"};
|
|
50
|
+
const THTH_KIND={scenario_stalled:"停滞",series_low:"ストック不足",untied_drafts:"未分類の下書き",unanswered_replies:"未返信",schedule_low:"予約切れ間近",schedule_thin:"予約が薄い",not_after_passed:"期限切れ",publish_held:"公開を停止中",account_stopped:"口座が停止",inflight_open:"公開の結果待ち",delivery_held:"配信の保留",delivery_behind:"記事の更新待ち",principal_stopped:"はてな ID が停止",budget_exhausted:"予算切れ",token_data_access_expiring:"データの期限が近い(認可し直す)",ads_active_outside_thth:"THTH の外で広告が配信中",ads_no_end_time:"終了日の無い広告が配信中",ads_account_status:"広告アカウントの状態",ads_spend_over_estimate:"広告の支出が見積もり超え",ads_spend_cap_near:"広告の支出が上限に近い",ads_budget_low:"広告の月の上限の残りが少ない",ads_spend_cap_unset:"広告アカウントに支出の上限が無い",ads_token_expiring:"広告の鍵の期限が近い",ads_read_failed:"広告の口座を読めない",webhook_down:"Webhook の取り込みが止まっている"};
|
|
51
|
+
const THTH_REASON={scenario_not_installed:"シナリオ(段 1)が未導入",no_declarations:"宣言が読めない",scenario_schema_unknown:"シナリオの版が違う",blog_pv_not_collected:"ブログ PV は取っていない",article_clicks_not_connected:"記事側の計測とつないでいない",needs_scenario_show:"詳細が読めない",posts_unlisted:"投稿の一覧が無い",deliveries_unlisted:"配信の一覧が無い",scenario_show_unavailable:"詳細が読めない",accounts_not_summed:"口座をまたいで足さない(口座ごとに見る)",not_measured_yet:"実測がまだ無い",not_published_yet:"まだ公開していない",no_deliveries:"配信がまだ無い",measured_unreadable:"実測の記録が読めない",reactions_unreadable:"反応の記録が読めない",account_unreadable:"口座の台帳が読めない",repo_unreadable:"原稿の置き場が読めない",scenarios_unreadable:"キャンペーン・シリーズの宣言が読めない",queue_unreadable:"原稿の置き場が読めない",sent_unreadable:"送った記録が読めない",deliveries_unreadable:"配信の記録が読めない",replies_unreadable:"返信の記録が読めない",inbox_unreadable:"通知の記録が読めない",source_unreadable:"記事の正本が読めない",inflight_unreadable:"公開の途中の記録が読めない",budget_unreadable:"X の予算の記録が読めない",hatena_account_missing:"はてなの口座がつながっていない",series_account_unknown:"シリーズの口座に知らない名前がある",series_account_out_of_scope:"この鍵では見えない口座がある(その分は数えない)",scenario_unreadable:"キャンペーン・シリーズが読めない",events_unreadable:"出来事が読めない",summary_unreadable:"直近 7 日の集計が読めない",summary_previous_unreadable:"前週の集計が読めない",schedule_unreadable:"予定が読めない",approve_pending_unreadable:"承認待ちが読めない",published_unreadable:"公開の数が読めない",followers_unreadable:"フォロワーの数が読めない",stopped_unreadable:"止まりの印が読めない",unanswered_unreadable:"未返信が読めない",full_trimmed:"詳細は大きすぎて省いた",target_unknown:"対象が見つからない",ads_unreadable:"広告の口座を読めない",webhook_unreadable:"Webhook の記録を読めない"};
|
|
52
52
|
function ththEsc(s){return String(s==null?"":s).replace(/[&<>"']/g,c=>({"&":"&","<":"<",">":">",'"':""","'":"'"}[c]));}
|
|
53
53
|
function ththNum(v){return v==null?"—":(typeof v==="number"?v.toLocaleString("ja-JP"):ththEsc(v));}
|
|
54
54
|
function ththPct(v){return v==null?"—":v+"%";}
|
|
@@ -44,11 +44,11 @@ table.pl{width:100%;border-collapse:collapse;font-size:11px;table-layout:fixed}.
|
|
|
44
44
|
<script>
|
|
45
45
|
/* ---- 共通(4 つの型で同じ。直すなら 4 つとも同じに) ---- */
|
|
46
46
|
const THTH_SCHEMA="thth.dashboard/1";
|
|
47
|
-
const THTH_MEDIUM={threads:"Threads",x:"X",bluesky:"Bluesky",mastodon:"Mastodon",facebook:"Facebook",hatenablog:"はてなブログ",hatena_bookmark:"はてブ",site:"サイト"};
|
|
47
|
+
const THTH_MEDIUM={threads:"Threads",x:"X",bluesky:"Bluesky",mastodon:"Mastodon",facebook:"Facebook",instagram:"Instagram",hatenablog:"はてなブログ",hatena_bookmark:"はてブ",site:"サイト"};
|
|
48
48
|
const THTH_STAGE={collect:"リサーチ",diary:"仮説",article:"本記事",announce:"SNS 告知",warm:"エンゲージ"};
|
|
49
49
|
const THTH_EVENT={researched:"リサーチ済み",hypothesis:"仮説を書いた",article_published:"本記事を公開",closed:"終えた"};
|
|
50
|
-
const THTH_KIND={scenario_stalled:"停滞",series_low:"ストック不足",untied_drafts:"未分類の下書き",unanswered_replies:"未返信",schedule_low:"予約切れ間近",schedule_thin:"予約が薄い",not_after_passed:"期限切れ",publish_held:"公開を停止中",account_stopped:"口座が停止",inflight_open:"公開の結果待ち",delivery_held:"配信の保留",delivery_behind:"記事の更新待ち",principal_stopped:"はてな ID が停止",budget_exhausted:"予算切れ",token_data_access_expiring:"データの期限が近い(認可し直す)"};
|
|
51
|
-
const THTH_REASON={scenario_not_installed:"シナリオ(段 1)が未導入",no_declarations:"宣言が読めない",scenario_schema_unknown:"シナリオの版が違う",blog_pv_not_collected:"ブログ PV は取っていない",article_clicks_not_connected:"記事側の計測とつないでいない",needs_scenario_show:"詳細が読めない",posts_unlisted:"投稿の一覧が無い",deliveries_unlisted:"配信の一覧が無い",scenario_show_unavailable:"詳細が読めない",accounts_not_summed:"口座をまたいで足さない(口座ごとに見る)",not_measured_yet:"実測がまだ無い",not_published_yet:"まだ公開していない",no_deliveries:"配信がまだ無い",measured_unreadable:"実測の記録が読めない",reactions_unreadable:"反応の記録が読めない",account_unreadable:"口座の台帳が読めない",repo_unreadable:"原稿の置き場が読めない",scenarios_unreadable:"キャンペーン・シリーズの宣言が読めない",queue_unreadable:"原稿の置き場が読めない",sent_unreadable:"送った記録が読めない",deliveries_unreadable:"配信の記録が読めない",replies_unreadable:"返信の記録が読めない",inbox_unreadable:"通知の記録が読めない",source_unreadable:"記事の正本が読めない",inflight_unreadable:"公開の途中の記録が読めない",budget_unreadable:"X の予算の記録が読めない",hatena_account_missing:"はてなの口座がつながっていない",series_account_unknown:"シリーズの口座に知らない名前がある",series_account_out_of_scope:"この鍵では見えない口座がある(その分は数えない)",scenario_unreadable:"キャンペーン・シリーズが読めない",events_unreadable:"出来事が読めない",summary_unreadable:"直近 7 日の集計が読めない",summary_previous_unreadable:"前週の集計が読めない",schedule_unreadable:"予定が読めない",approve_pending_unreadable:"承認待ちが読めない",published_unreadable:"公開の数が読めない",followers_unreadable:"フォロワーの数が読めない",stopped_unreadable:"止まりの印が読めない",unanswered_unreadable:"未返信が読めない",full_trimmed:"詳細は大きすぎて省いた",target_unknown:"対象が見つからない"};
|
|
50
|
+
const THTH_KIND={scenario_stalled:"停滞",series_low:"ストック不足",untied_drafts:"未分類の下書き",unanswered_replies:"未返信",schedule_low:"予約切れ間近",schedule_thin:"予約が薄い",not_after_passed:"期限切れ",publish_held:"公開を停止中",account_stopped:"口座が停止",inflight_open:"公開の結果待ち",delivery_held:"配信の保留",delivery_behind:"記事の更新待ち",principal_stopped:"はてな ID が停止",budget_exhausted:"予算切れ",token_data_access_expiring:"データの期限が近い(認可し直す)",ads_active_outside_thth:"THTH の外で広告が配信中",ads_no_end_time:"終了日の無い広告が配信中",ads_account_status:"広告アカウントの状態",ads_spend_over_estimate:"広告の支出が見積もり超え",ads_spend_cap_near:"広告の支出が上限に近い",ads_budget_low:"広告の月の上限の残りが少ない",ads_spend_cap_unset:"広告アカウントに支出の上限が無い",ads_token_expiring:"広告の鍵の期限が近い",ads_read_failed:"広告の口座を読めない",webhook_down:"Webhook の取り込みが止まっている"};
|
|
51
|
+
const THTH_REASON={scenario_not_installed:"シナリオ(段 1)が未導入",no_declarations:"宣言が読めない",scenario_schema_unknown:"シナリオの版が違う",blog_pv_not_collected:"ブログ PV は取っていない",article_clicks_not_connected:"記事側の計測とつないでいない",needs_scenario_show:"詳細が読めない",posts_unlisted:"投稿の一覧が無い",deliveries_unlisted:"配信の一覧が無い",scenario_show_unavailable:"詳細が読めない",accounts_not_summed:"口座をまたいで足さない(口座ごとに見る)",not_measured_yet:"実測がまだ無い",not_published_yet:"まだ公開していない",no_deliveries:"配信がまだ無い",measured_unreadable:"実測の記録が読めない",reactions_unreadable:"反応の記録が読めない",account_unreadable:"口座の台帳が読めない",repo_unreadable:"原稿の置き場が読めない",scenarios_unreadable:"キャンペーン・シリーズの宣言が読めない",queue_unreadable:"原稿の置き場が読めない",sent_unreadable:"送った記録が読めない",deliveries_unreadable:"配信の記録が読めない",replies_unreadable:"返信の記録が読めない",inbox_unreadable:"通知の記録が読めない",source_unreadable:"記事の正本が読めない",inflight_unreadable:"公開の途中の記録が読めない",budget_unreadable:"X の予算の記録が読めない",hatena_account_missing:"はてなの口座がつながっていない",series_account_unknown:"シリーズの口座に知らない名前がある",series_account_out_of_scope:"この鍵では見えない口座がある(その分は数えない)",scenario_unreadable:"キャンペーン・シリーズが読めない",events_unreadable:"出来事が読めない",summary_unreadable:"直近 7 日の集計が読めない",summary_previous_unreadable:"前週の集計が読めない",schedule_unreadable:"予定が読めない",approve_pending_unreadable:"承認待ちが読めない",published_unreadable:"公開の数が読めない",followers_unreadable:"フォロワーの数が読めない",stopped_unreadable:"止まりの印が読めない",unanswered_unreadable:"未返信が読めない",full_trimmed:"詳細は大きすぎて省いた",target_unknown:"対象が見つからない",ads_unreadable:"広告の口座を読めない",webhook_unreadable:"Webhook の記録を読めない"};
|
|
52
52
|
function ththEsc(s){return String(s==null?"":s).replace(/[&<>"']/g,c=>({"&":"&","<":"<",">":">",'"':""","'":"'"}[c]));}
|
|
53
53
|
function ththNum(v){return v==null?"—":(typeof v==="number"?v.toLocaleString("ja-JP"):ththEsc(v));}
|
|
54
54
|
function ththPct(v){return v==null?"—":v+"%";}
|
|
@@ -39,11 +39,11 @@
|
|
|
39
39
|
<script>
|
|
40
40
|
/* ---- 共通(4 つの型で同じ。直すなら 4 つとも同じに) ---- */
|
|
41
41
|
const THTH_SCHEMA="thth.dashboard/1";
|
|
42
|
-
const THTH_MEDIUM={threads:"Threads",x:"X",bluesky:"Bluesky",mastodon:"Mastodon",facebook:"Facebook",hatenablog:"はてなブログ",hatena_bookmark:"はてブ",site:"サイト"};
|
|
42
|
+
const THTH_MEDIUM={threads:"Threads",x:"X",bluesky:"Bluesky",mastodon:"Mastodon",facebook:"Facebook",instagram:"Instagram",hatenablog:"はてなブログ",hatena_bookmark:"はてブ",site:"サイト"};
|
|
43
43
|
const THTH_STAGE={collect:"リサーチ",diary:"仮説",article:"本記事",announce:"SNS 告知",warm:"エンゲージ"};
|
|
44
44
|
const THTH_EVENT={researched:"リサーチ済み",hypothesis:"仮説を書いた",article_published:"本記事を公開",closed:"終えた"};
|
|
45
|
-
const THTH_KIND={scenario_stalled:"停滞",series_low:"ストック不足",untied_drafts:"未分類の下書き",unanswered_replies:"未返信",schedule_low:"予約切れ間近",schedule_thin:"予約が薄い",not_after_passed:"期限切れ",publish_held:"公開を停止中",account_stopped:"口座が停止",inflight_open:"公開の結果待ち",delivery_held:"配信の保留",delivery_behind:"記事の更新待ち",principal_stopped:"はてな ID が停止",budget_exhausted:"予算切れ",token_data_access_expiring:"データの期限が近い(認可し直す)"};
|
|
46
|
-
const THTH_REASON={scenario_not_installed:"シナリオ(段 1)が未導入",no_declarations:"宣言が読めない",scenario_schema_unknown:"シナリオの版が違う",blog_pv_not_collected:"ブログ PV は取っていない",article_clicks_not_connected:"記事側の計測とつないでいない",needs_scenario_show:"詳細が読めない",posts_unlisted:"投稿の一覧が無い",deliveries_unlisted:"配信の一覧が無い",scenario_show_unavailable:"詳細が読めない",accounts_not_summed:"口座をまたいで足さない(口座ごとに見る)",not_measured_yet:"実測がまだ無い",not_published_yet:"まだ公開していない",no_deliveries:"配信がまだ無い",measured_unreadable:"実測の記録が読めない",reactions_unreadable:"反応の記録が読めない",account_unreadable:"口座の台帳が読めない",repo_unreadable:"原稿の置き場が読めない",scenarios_unreadable:"キャンペーン・シリーズの宣言が読めない",queue_unreadable:"原稿の置き場が読めない",sent_unreadable:"送った記録が読めない",deliveries_unreadable:"配信の記録が読めない",replies_unreadable:"返信の記録が読めない",inbox_unreadable:"通知の記録が読めない",source_unreadable:"記事の正本が読めない",inflight_unreadable:"公開の途中の記録が読めない",budget_unreadable:"X の予算の記録が読めない",hatena_account_missing:"はてなの口座がつながっていない",series_account_unknown:"シリーズの口座に知らない名前がある",series_account_out_of_scope:"この鍵では見えない口座がある(その分は数えない)",scenario_unreadable:"キャンペーン・シリーズが読めない",events_unreadable:"出来事が読めない",summary_unreadable:"直近 7 日の集計が読めない",summary_previous_unreadable:"前週の集計が読めない",schedule_unreadable:"予定が読めない",approve_pending_unreadable:"承認待ちが読めない",published_unreadable:"公開の数が読めない",followers_unreadable:"フォロワーの数が読めない",stopped_unreadable:"止まりの印が読めない",unanswered_unreadable:"未返信が読めない",full_trimmed:"詳細は大きすぎて省いた",target_unknown:"対象が見つからない"};
|
|
45
|
+
const THTH_KIND={scenario_stalled:"停滞",series_low:"ストック不足",untied_drafts:"未分類の下書き",unanswered_replies:"未返信",schedule_low:"予約切れ間近",schedule_thin:"予約が薄い",not_after_passed:"期限切れ",publish_held:"公開を停止中",account_stopped:"口座が停止",inflight_open:"公開の結果待ち",delivery_held:"配信の保留",delivery_behind:"記事の更新待ち",principal_stopped:"はてな ID が停止",budget_exhausted:"予算切れ",token_data_access_expiring:"データの期限が近い(認可し直す)",ads_active_outside_thth:"THTH の外で広告が配信中",ads_no_end_time:"終了日の無い広告が配信中",ads_account_status:"広告アカウントの状態",ads_spend_over_estimate:"広告の支出が見積もり超え",ads_spend_cap_near:"広告の支出が上限に近い",ads_budget_low:"広告の月の上限の残りが少ない",ads_spend_cap_unset:"広告アカウントに支出の上限が無い",ads_token_expiring:"広告の鍵の期限が近い",ads_read_failed:"広告の口座を読めない",webhook_down:"Webhook の取り込みが止まっている"};
|
|
46
|
+
const THTH_REASON={scenario_not_installed:"シナリオ(段 1)が未導入",no_declarations:"宣言が読めない",scenario_schema_unknown:"シナリオの版が違う",blog_pv_not_collected:"ブログ PV は取っていない",article_clicks_not_connected:"記事側の計測とつないでいない",needs_scenario_show:"詳細が読めない",posts_unlisted:"投稿の一覧が無い",deliveries_unlisted:"配信の一覧が無い",scenario_show_unavailable:"詳細が読めない",accounts_not_summed:"口座をまたいで足さない(口座ごとに見る)",not_measured_yet:"実測がまだ無い",not_published_yet:"まだ公開していない",no_deliveries:"配信がまだ無い",measured_unreadable:"実測の記録が読めない",reactions_unreadable:"反応の記録が読めない",account_unreadable:"口座の台帳が読めない",repo_unreadable:"原稿の置き場が読めない",scenarios_unreadable:"キャンペーン・シリーズの宣言が読めない",queue_unreadable:"原稿の置き場が読めない",sent_unreadable:"送った記録が読めない",deliveries_unreadable:"配信の記録が読めない",replies_unreadable:"返信の記録が読めない",inbox_unreadable:"通知の記録が読めない",source_unreadable:"記事の正本が読めない",inflight_unreadable:"公開の途中の記録が読めない",budget_unreadable:"X の予算の記録が読めない",hatena_account_missing:"はてなの口座がつながっていない",series_account_unknown:"シリーズの口座に知らない名前がある",series_account_out_of_scope:"この鍵では見えない口座がある(その分は数えない)",scenario_unreadable:"キャンペーン・シリーズが読めない",events_unreadable:"出来事が読めない",summary_unreadable:"直近 7 日の集計が読めない",summary_previous_unreadable:"前週の集計が読めない",schedule_unreadable:"予定が読めない",approve_pending_unreadable:"承認待ちが読めない",published_unreadable:"公開の数が読めない",followers_unreadable:"フォロワーの数が読めない",stopped_unreadable:"止まりの印が読めない",unanswered_unreadable:"未返信が読めない",full_trimmed:"詳細は大きすぎて省いた",target_unknown:"対象が見つからない",ads_unreadable:"広告の口座を読めない",webhook_unreadable:"Webhook の記録を読めない"};
|
|
47
47
|
function ththEsc(s){return String(s==null?"":s).replace(/[&<>"']/g,c=>({"&":"&","<":"<",">":">",'"':""","'":"'"}[c]));}
|
|
48
48
|
function ththNum(v){return v==null?"—":(typeof v==="number"?v.toLocaleString("ja-JP"):ththEsc(v));}
|
|
49
49
|
function ththPct(v){return v==null?"—":v+"%";}
|
|
@@ -125,6 +125,23 @@ def no_real_hatena_adapters(monkeypatch):
|
|
|
125
125
|
monkeypatch.setattr(hatena_reactions, "SLEEP", lambda seconds: None)
|
|
126
126
|
|
|
127
127
|
|
|
128
|
+
@pytest.fixture(autouse=True)
|
|
129
|
+
def no_real_meta_app_secret(monkeypatch):
|
|
130
|
+
"""Meta の共通層(`thth/meta/graph.py`)が `appsecret_proof` のために読む app secret を、
|
|
131
|
+
**試験が `THTH_APP_ENV_PATH` で隔離した app.env を置いたときだけ**読ませる(段 2)。
|
|
132
|
+
|
|
133
|
+
`FacebookAdapter.from_account` は `META_APP_SECRET` を読む。HOME を隔離していない試験が
|
|
134
|
+
打った人の実物の `~/.config/thth/app.env` を読まないようにする(値は出ないが、読まない)。
|
|
135
|
+
"""
|
|
136
|
+
from thth.meta import graph as meta_graph
|
|
137
|
+
original = meta_graph.load_app_secret
|
|
138
|
+
|
|
139
|
+
def isolated():
|
|
140
|
+
import os
|
|
141
|
+
return original() if os.environ.get("THTH_APP_ENV_PATH") else None
|
|
142
|
+
monkeypatch.setattr(meta_graph, "load_app_secret", isolated)
|
|
143
|
+
|
|
144
|
+
|
|
128
145
|
@pytest.fixture(autouse=True)
|
|
129
146
|
def no_threads_status_poll_wait(monkeypatch):
|
|
130
147
|
"""公開の結果が分からないときの container の問い合わせ(設計 3.3.1 §2)を
|
|
@@ -720,9 +720,11 @@ def test_T3_REGISTRYに5媒体が載っている():
|
|
|
720
720
|
from thth.adapters import mastodon as mastodon_mod
|
|
721
721
|
from thth.adapters import x as x_mod
|
|
722
722
|
from thth.adapters import facebook as facebook_mod
|
|
723
|
-
|
|
724
|
-
|
|
723
|
+
from thth.adapters import instagram as instagram_mod
|
|
724
|
+
# 10/29: Facebook ページ(`thth/adapters/facebook.py`)を足した。段 3: Instagram(`instagram.py`)。
|
|
725
|
+
assert adapters_mod.known_media() == ["bluesky", "facebook", "instagram", "mastodon", "threads", "x"]
|
|
725
726
|
assert adapters_mod.REGISTRY["facebook"] is facebook_mod.FacebookAdapter
|
|
727
|
+
assert adapters_mod.REGISTRY["instagram"] is instagram_mod.InstagramAdapter
|
|
726
728
|
assert adapters_mod.REGISTRY["bluesky"] is bluesky_mod.BlueskyAdapter
|
|
727
729
|
assert adapters_mod.REGISTRY["mastodon"] is mastodon_mod.MastodonAdapter
|
|
728
730
|
assert adapters_mod.REGISTRY["x"] is x_mod.XAdapter
|
|
@@ -92,8 +92,10 @@ def test_REGISTRYにfacebookが載り境界の語彙に収まる():
|
|
|
92
92
|
cls = adapters_mod.REGISTRY["facebook"]
|
|
93
93
|
assert cls is fb.FacebookAdapter
|
|
94
94
|
assert set(cls.CAPABILITIES) <= base.KNOWN_CAPABILITIES
|
|
95
|
+
# 段 6(10/29): inbox・mentions(Webhook の記録から読む・`tests/test_meta_stage6.py`)。
|
|
95
96
|
assert cls.capabilities() == {"recent_posts", "thread_read", "views", "link_preview",
|
|
96
|
-
"account_insights", "carousel", "edit_post", "hide_reply"
|
|
97
|
+
"account_insights", "carousel", "edit_post", "hide_reply", "quota",
|
|
98
|
+
"inbox", "mentions"}
|
|
97
99
|
assert cls.TOKEN_KEYS == ("access_token",) and cls.has_token({"access_token": "x"})
|
|
98
100
|
assert cls.TOKEN_NO_EXPIRY is True and cls.AUTH_NEEDS_APP_ENV is True
|
|
99
101
|
assert cls.DELETE_PERMISSION == "pages_manage_posts"
|
|
@@ -87,12 +87,12 @@ def test_段0にだけあった5つのidの行き先():
|
|
|
87
87
|
|
|
88
88
|
def test_SNSの4媒体の行は表の1行に集まり根拠は媒体ごと():
|
|
89
89
|
row = limits_policy.rule("post.daily")
|
|
90
|
-
# facebook は 10/29 段 0 で媒体の性質の台帳を持った(5 媒体)。
|
|
91
|
-
assert set(row["ledger"]) == {"threads", "x", "bluesky", "mastodon", "facebook"}
|
|
90
|
+
# facebook は 10/29 段 0 で媒体の性質の台帳を持った(5 媒体)。instagram は段 3(6 媒体)。
|
|
91
|
+
assert set(row["ledger"]) == {"threads", "x", "bluesky", "mastodon", "facebook", "instagram"}
|
|
92
92
|
traits = {m: limits_policy.resolve(row, cfg={"media": m})["trait"] for m in row["ledger"]}
|
|
93
93
|
assert traits == {"threads": "threads.api_posts_24h", "x": "x.account_post_limit",
|
|
94
94
|
"bluesky": "bluesky.pds_points", "mastodon": "mastodon.api_rate",
|
|
95
|
-
"facebook": "facebook.api_rate"}
|
|
95
|
+
"facebook": "facebook.api_rate", "instagram": "instagram.publish_limit"}
|
|
96
96
|
# Threads の反応は台帳に根拠が無い → thth の線
|
|
97
97
|
assert limits_policy.resolve(limits_policy.rule("reaction.daily"), cfg={"media": "threads"})["trait"] \
|
|
98
98
|
== "thth:reaction.daily"
|
|
@@ -456,7 +456,7 @@ def test_既定の数は柵の表から引く(ledger):
|
|
|
456
456
|
for rule_id, row in (trait.get("defaults") or {}).items():
|
|
457
457
|
if rule_id == "post.daily":
|
|
458
458
|
row["count"] = 9
|
|
459
|
-
for media in ("threads", "x", "bluesky", "mastodon", "facebook"):
|
|
459
|
+
for media in ("threads", "x", "bluesky", "mastodon", "facebook", "instagram"):
|
|
460
460
|
edit_ledger(ledger, media, bump)
|
|
461
461
|
assert accounts.GUARD_DEFAULTS["daily_max_posts"] == 9
|
|
462
462
|
assert accounts.guard_limits({"media": "threads"})["daily_max_posts"] == 9
|
|
@@ -18,7 +18,7 @@ import pytest
|
|
|
18
18
|
|
|
19
19
|
from thth import (account_cli, accounts, adapters, dashboard_cli, leave_gate, limits_config,
|
|
20
20
|
limits_policy, media, media_capabilities, media_delivery, media_registry,
|
|
21
|
-
media_traits, queuefile, scenario, thread_read)
|
|
21
|
+
media_traits, queuefile, scenario, thread_read, webhook)
|
|
22
22
|
|
|
23
23
|
REGISTRY = media_registry.names()
|
|
24
24
|
NON_ADAPTER = media_registry.NON_ADAPTER_NAMES
|
|
@@ -69,6 +69,8 @@ TABLES = {
|
|
|
69
69
|
"dashboard_cli.MEDIUM_JA": lambda: set(dashboard_cli.MEDIUM_JA),
|
|
70
70
|
"thread_read.SOURCE_BY_MEDIUM": lambda: set(thread_read.SOURCE_BY_MEDIUM),
|
|
71
71
|
"thread_read.PERMISSION_BY_MEDIUM": lambda: set(thread_read.PERMISSION_BY_MEDIUM),
|
|
72
|
+
# Meta 計画 段 6: Webhook を購読する欄(Meta の Graph の媒体だけ・ほかは registry に理由)。
|
|
73
|
+
"webhook.SUBSCRIBE_FIELDS": lambda: set(webhook.SUBSCRIBE_FIELDS),
|
|
72
74
|
**{f"dashboard/{level}.html THTH_MEDIUM": (lambda level=level: _template_medium(level))
|
|
73
75
|
for level in ("all", "project", "campaign", "series")},
|
|
74
76
|
}
|
|
@@ -126,9 +128,19 @@ def test_雛形のhandleは雛形の台帳とダミーの印に一致する():
|
|
|
126
128
|
|
|
127
129
|
|
|
128
130
|
def test_添付を媒体が取りに来るのはrelayを渡す媒体だけ():
|
|
131
|
+
"""段 3(10/29): relay を渡すかは registry の `media_fetch: pull` だけで決める(`meta.media.relay_for`)。
|
|
132
|
+
|
|
133
|
+
`media_delivery` は媒体名で relay を分けない(`relay_for` を呼ぶだけ)。段 2 までは
|
|
134
|
+
`MediaRelay(...) if cfg['media']=='threads'` の 1 行だったのを、段 3 で Instagram を足すときに置き換えた。
|
|
135
|
+
"""
|
|
136
|
+
from thth.meta import media as meta_media
|
|
129
137
|
source = inspect.getsource(media_delivery)
|
|
130
|
-
|
|
131
|
-
assert
|
|
138
|
+
assert "meta_media.relay_for(cfg,has_items=bool(items))" in source
|
|
139
|
+
assert not re.search(r"MediaRelay\([^)]*\) if cfg\['media'\]", source), "媒体名で relay を分ける行が戻っている"
|
|
132
140
|
pulled = {name for name, medium in media_registry.MEDIA.items() if medium.media_fetch == "pull"}
|
|
133
|
-
assert pulled ==
|
|
141
|
+
assert pulled == {"threads", "instagram"}
|
|
142
|
+
for name in media_registry.MEDIA:
|
|
143
|
+
relay = meta_media.relay_for({"media": name, "account": "demo-" + name}, has_items=True)
|
|
144
|
+
assert (relay is not None) == (name in pulled), name
|
|
145
|
+
assert meta_media.relay_for({"media": name, "account": "demo-" + name}, has_items=False) is None
|
|
134
146
|
assert {m.media_fetch for m in media_registry.MEDIA.values()} <= {"push", "pull"}
|