jobctrl 0.4.0__tar.gz → 0.4.1__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 (1083) hide show
  1. {jobctrl-0.4.0 → jobctrl-0.4.1}/PKG-INFO +2 -2
  2. {jobctrl-0.4.0 → jobctrl-0.4.1}/pyproject.toml +2 -2
  3. {jobctrl-0.4.0 → jobctrl-0.4.1}/scripts/search_unit_concurrency_assessment.py +1 -1
  4. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/__init__.py +1 -1
  5. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/actions.py +17 -0
  6. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/launcher.py +1 -1
  7. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/cli.py +27 -6
  8. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/config.py +70 -11
  9. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/discovery/jobspy.py +75 -14
  10. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/discovery/smartextract.py +3 -0
  11. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/discovery/workflow.py +33 -1
  12. jobctrl-0.4.1/src/jobctrl/domain/discovery/remote_search.py +56 -0
  13. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/discovery/search_units.py +10 -2
  14. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/profile/search_targets.py +49 -0
  15. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/enrichment/detail.py +11 -6
  16. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/jobstreaming_gateway.py +77 -4
  17. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/live_browser.py +30 -0
  18. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/enrichment/sqlite_repository.py +57 -26
  19. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/gmail/feedback.py +70 -21
  20. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/profile/sqlite_repository.py +61 -7
  21. jobctrl-0.4.1/src/jobctrl/infrastructure/rpc/enrichment_retry.py +90 -0
  22. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/rpc/handlers.py +15 -46
  23. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/rpc/server.py +8 -4
  24. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/native_credentials.py +100 -4
  25. jobctrl-0.4.1/src/jobctrl/pipeline/retry.py +285 -0
  26. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/pipeline/runner.py +25 -5
  27. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/scoring/cover_letter.py +4 -2
  28. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/scoring/tailor.py +2 -1
  29. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/state.py +37 -57
  30. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/wizard/init.py +331 -49
  31. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/workflow_specs.py +17 -1
  32. jobctrl-0.4.1/tests/fixtures/rpc_boundary_python.json +1 -0
  33. jobctrl-0.4.1/tests/gmail_feedback_progress_rpc.py +66 -0
  34. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_dashboard_execution_policy.py +13 -3
  35. jobctrl-0.4.1/tests/test_discover_preview.py +149 -0
  36. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discover_reliability.py +3 -3
  37. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_url_safety.py +9 -0
  38. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gmail_feedback.py +261 -0
  39. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gmail_feedback_scan_handler.py +51 -2
  40. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_jobstreaming_gateway.py +4 -1
  41. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_jobstreaming_resumable_discovery.py +4 -1
  42. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_live_browser_discovery.py +1 -1
  43. jobctrl-0.4.1/tests/test_location_free_remote_discovery.py +990 -0
  44. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_native_credentials.py +380 -1
  45. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_optional_extension.py +10 -7
  46. jobctrl-0.4.1/tests/test_remote_country_snapshot.py +235 -0
  47. jobctrl-0.4.1/tests/test_remote_search_scope.py +520 -0
  48. jobctrl-0.4.1/tests/test_retry_material_predecessor.py +98 -0
  49. jobctrl-0.4.1/tests/test_retry_posting_lifecycle.py +86 -0
  50. jobctrl-0.4.1/tests/test_stage_retry_consistency.py +664 -0
  51. jobctrl-0.4.1/tests/test_wizard_files_preservation.py +510 -0
  52. jobctrl-0.4.1/tests/test_wizard_profile_preservation.py +264 -0
  53. {jobctrl-0.4.0 → jobctrl-0.4.1}/uv.lock +192 -127
  54. jobctrl-0.4.0/src/jobctrl/infrastructure/rpc/enrichment_retry.py +0 -46
  55. jobctrl-0.4.0/src/jobctrl/pipeline/retry.py +0 -129
  56. jobctrl-0.4.0/tests/fixtures/rpc_boundary_python.json +0 -1
  57. {jobctrl-0.4.0 → jobctrl-0.4.1}/.gitignore +0 -0
  58. {jobctrl-0.4.0 → jobctrl-0.4.1}/LICENSE +0 -0
  59. {jobctrl-0.4.0 → jobctrl-0.4.1}/NOTICE +0 -0
  60. {jobctrl-0.4.0 → jobctrl-0.4.1}/README.md +0 -0
  61. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/__main__.py +0 -0
  62. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/__init__.py +0 -0
  63. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/activities.py +0 -0
  64. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/auto_apply.py +0 -0
  65. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/batch_outcome.py +0 -0
  66. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/chrome.py +0 -0
  67. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/cover_letter_binding.py +0 -0
  68. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/dashboard.py +0 -0
  69. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/dispatch.py +0 -0
  70. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/execution.py +0 -0
  71. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/native_custody.py +0 -0
  72. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/origins.py +0 -0
  73. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/ownership.py +0 -0
  74. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/process_birth.py +0 -0
  75. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/prompt.py +0 -0
  76. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/telemetry.py +0 -0
  77. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/workflow.py +0 -0
  78. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/assets/determinations/taxonomy.v1.json +0 -0
  79. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/assets/fonts/GEIST-LICENSE.txt +0 -0
  80. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/assets/fonts/geist-latin-ext-wght-normal.woff2 +0 -0
  81. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/assets/fonts/geist-latin-wght-normal.woff2 +0 -0
  82. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/assets/interview/catalog.v1.json +0 -0
  83. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/browser_capabilities.py +0 -0
  84. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/company_briefing_cli.py +0 -0
  85. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/config/employers.yaml +0 -0
  86. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/config/sites.yaml +0 -0
  87. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/contact/__init__.py +0 -0
  88. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/contact/activities.py +0 -0
  89. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/contact/workflow.py +0 -0
  90. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/database.py +0 -0
  91. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/digest.py +0 -0
  92. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/discovery/__init__.py +0 -0
  93. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/discovery/activities.py +0 -0
  94. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/discovery/execution_reconciliation.py +0 -0
  95. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/discovery/job_url_import_workflow.py +0 -0
  96. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/discovery/manual_capture_import.py +0 -0
  97. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/discovery/manual_capture_workflow.py +0 -0
  98. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/discovery/target_queries.py +0 -0
  99. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/discovery/workday.py +0 -0
  100. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/__init__.py +0 -0
  101. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/__init__.py +0 -0
  102. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/aggregate.py +0 -0
  103. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/entities.py +0 -0
  104. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/event_privacy.py +0 -0
  105. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/form_mapping.py +0 -0
  106. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/process_manager.py +0 -0
  107. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/repeat_application.py +0 -0
  108. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/role_equivalence.py +0 -0
  109. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/screening_answers.py +0 -0
  110. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/services.py +0 -0
  111. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/terminal_report.py +0 -0
  112. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/use_cases.py +0 -0
  113. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/value_objects.py +0 -0
  114. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/compensation/__init__.py +0 -0
  115. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/compensation/benchmarks.py +0 -0
  116. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/compensation/classification.py +0 -0
  117. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/compensation/market.py +0 -0
  118. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/compensation/posted.py +0 -0
  119. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/contact/__init__.py +0 -0
  120. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/contact/aggregate.py +0 -0
  121. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/contact/outreach.py +0 -0
  122. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/contact/outreach_gates.py +0 -0
  123. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/contact/outreach_use_cases.py +0 -0
  124. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/contact/research.py +0 -0
  125. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/contact/research_services.py +0 -0
  126. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/contact/research_use_cases.py +0 -0
  127. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/contact/source_policy.py +0 -0
  128. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/contact/use_cases.py +0 -0
  129. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/contact/value_objects.py +0 -0
  130. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/determinations.py +0 -0
  131. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/discovery/__init__.py +0 -0
  132. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/discovery/aggregate.py +0 -0
  133. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/discovery/execution.py +0 -0
  134. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/discovery/identity.py +0 -0
  135. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/discovery/posting_qualification.py +0 -0
  136. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/discovery/scheduler.py +0 -0
  137. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/discovery/source_registry.py +0 -0
  138. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/discovery/use_cases.py +0 -0
  139. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/discovery/value_objects.py +0 -0
  140. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/__init__.py +0 -0
  141. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/aggregate.py +0 -0
  142. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/entities.py +0 -0
  143. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/filter_override.py +0 -0
  144. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/interpretation.py +0 -0
  145. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/page_interpretation.py +0 -0
  146. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/services.py +0 -0
  147. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/snapshot_services.py +0 -0
  148. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/snapshot_set.py +0 -0
  149. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/snapshot_use_case.py +0 -0
  150. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/snapshot_value_objects.py +0 -0
  151. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/use_cases.py +0 -0
  152. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/value_objects.py +0 -0
  153. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/errors.py +0 -0
  154. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/__init__.py +0 -0
  155. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/apply.py +0 -0
  156. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/base.py +0 -0
  157. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/contact.py +0 -0
  158. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/discovery.py +0 -0
  159. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/enrichment.py +0 -0
  160. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/interview.py +0 -0
  161. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/materials.py +0 -0
  162. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/operations.py +0 -0
  163. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/orchestration.py +0 -0
  164. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/profile.py +0 -0
  165. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/scoring.py +0 -0
  166. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/workflow.py +0 -0
  167. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/exact_values.py +0 -0
  168. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/extraction.py +0 -0
  169. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/feedback/__init__.py +0 -0
  170. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/feedback/message_interpretation.py +0 -0
  171. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/identifiers.py +0 -0
  172. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/interview/__init__.py +0 -0
  173. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/interview/catalog.py +0 -0
  174. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/interview/evidence.py +0 -0
  175. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/interview/preparation.py +0 -0
  176. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/interview/question_generation.py +0 -0
  177. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/interview/use_cases.py +0 -0
  178. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/interview/value_objects.py +0 -0
  179. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/job_content_identity.py +0 -0
  180. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/job_snapshot.py +0 -0
  181. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/__init__.py +0 -0
  182. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/adversarial.py +0 -0
  183. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/aggregate.py +0 -0
  184. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/analysis.py +0 -0
  185. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/analysis_agreement.py +0 -0
  186. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/analysis_grounding.py +0 -0
  187. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/analyze_use_case.py +0 -0
  188. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/artifact_quality.py +0 -0
  189. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/claim_grounding.py +0 -0
  190. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/claim_review_response.py +0 -0
  191. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/claim_verification.py +0 -0
  192. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/company_briefings.py +0 -0
  193. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/cover_letter_settings.py +0 -0
  194. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/coverage_audit.py +0 -0
  195. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/edit_intent.py +0 -0
  196. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/editable_export.py +0 -0
  197. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/entities.py +0 -0
  198. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/evidence_selection.py +0 -0
  199. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/generation.py +0 -0
  200. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/locale_variants.py +0 -0
  201. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/policy.py +0 -0
  202. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/provenance.py +0 -0
  203. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/provenance_builder.py +0 -0
  204. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/quality.py +0 -0
  205. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/requirement_coverage.py +0 -0
  206. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/resume_document.py +0 -0
  207. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/screening_answers.py +0 -0
  208. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/services.py +0 -0
  209. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/use_cases.py +0 -0
  210. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/value_objects.py +0 -0
  211. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/voice.py +0 -0
  212. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/operations/__init__.py +0 -0
  213. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/operations/career_learning.py +0 -0
  214. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/operations/evidence_map.py +0 -0
  215. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/operations/feedback.py +0 -0
  216. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/operations/learning.py +0 -0
  217. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/operations/projections.py +0 -0
  218. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/pipeline/__init__.py +0 -0
  219. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/pipeline/aggregate.py +0 -0
  220. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/pipeline/repository.py +0 -0
  221. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/pipeline/state_machine.py +0 -0
  222. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/pipeline/use_cases.py +0 -0
  223. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/pipeline_types.py +0 -0
  224. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/__init__.py +0 -0
  225. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/analysis_agreement.py +0 -0
  226. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/apply.py +0 -0
  227. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/artifact_generation.py +0 -0
  228. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/artifact_quality.py +0 -0
  229. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/artifact_review.py +0 -0
  230. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/claim_verification.py +0 -0
  231. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/contact.py +0 -0
  232. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/discovery.py +0 -0
  233. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/enrichment.py +0 -0
  234. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/events.py +0 -0
  235. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/feedback.py +0 -0
  236. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/job_interpretation.py +0 -0
  237. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/learning.py +0 -0
  238. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/letter_reviews.py +0 -0
  239. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/llm.py +0 -0
  240. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/materials.py +0 -0
  241. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/politeness.py +0 -0
  242. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/resume_adversarial.py +0 -0
  243. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/retrieval.py +0 -0
  244. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/scoring.py +0 -0
  245. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/watermark.py +0 -0
  246. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/preparation/__init__.py +0 -0
  247. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/preparation/work_items.py +0 -0
  248. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/profile/__init__.py +0 -0
  249. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/profile/aggregate.py +0 -0
  250. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/profile/canonical_sources.py +0 -0
  251. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/profile/interpretation.py +0 -0
  252. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/profile/ports.py +0 -0
  253. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/profile/required_bullet_coaching.py +0 -0
  254. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/profile/resume_extraction.py +0 -0
  255. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/profile/snapshot.py +0 -0
  256. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/profile/use_cases.py +0 -0
  257. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/profile/value_objects.py +0 -0
  258. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/rpc/__init__.py +0 -0
  259. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/rpc/messages.py +0 -0
  260. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/scoring/__init__.py +0 -0
  261. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/scoring/aggregate.py +0 -0
  262. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/scoring/determination.py +0 -0
  263. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/scoring/eligibility.py +0 -0
  264. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/scoring/policy.py +0 -0
  265. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/scoring/profile_impact.py +0 -0
  266. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/scoring/requirement_fit.py +0 -0
  267. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/scoring/retrieval.py +0 -0
  268. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/scoring/services.py +0 -0
  269. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/scoring/use_cases.py +0 -0
  270. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/scoring/value_objects.py +0 -0
  271. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/taxonomy.py +0 -0
  272. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/taxonomy_codes.py +0 -0
  273. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/tenant.py +0 -0
  274. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/enrichment/__init__.py +0 -0
  275. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/enrichment/activities.py +0 -0
  276. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/enrichment/availability.py +0 -0
  277. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/enrichment/availability_workflow.py +0 -0
  278. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/__init__.py +0 -0
  279. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/analysis/__init__.py +0 -0
  280. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/analysis/antigravity_analysis_adapter.py +0 -0
  281. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/analysis/claude_analysis_adapter.py +0 -0
  282. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/analysis/codex_analysis_adapter.py +0 -0
  283. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/analysis/ensemble.py +0 -0
  284. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/analysis/gemini_schema.py +0 -0
  285. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/analysis/llm_analysis_synthesizer.py +0 -0
  286. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/analysis/prompts.py +0 -0
  287. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/analysis/strict_schema.py +0 -0
  288. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/apply/__init__.py +0 -0
  289. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/apply/claude_code_cli.py +0 -0
  290. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/apply/email_sender.py +0 -0
  291. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/apply/form_mapping.py +0 -0
  292. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/apply/local_chrome.py +0 -0
  293. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/apply_controls.py +0 -0
  294. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/apply_tools/__init__.py +0 -0
  295. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/apply_tools/mcp_server.py +0 -0
  296. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/captcha/__init__.py +0 -0
  297. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/captcha/capsolver.py +0 -0
  298. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/career_learning.py +0 -0
  299. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/commit_notifications.py +0 -0
  300. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/__init__.py +0 -0
  301. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/automatic_refresh.py +0 -0
  302. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/benchmark_ingestion.py +0 -0
  303. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/benchmark_lineage.py +0 -0
  304. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/benchmark_materialization.py +0 -0
  305. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/classification_batch.py +0 -0
  306. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/interpretation.py +0 -0
  307. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/levels_fyi_public.py +0 -0
  308. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/official_data.py +0 -0
  309. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/refresh.py +0 -0
  310. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/refresh_control.py +0 -0
  311. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/refresh_state.py +0 -0
  312. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/sqlite_benchmark_repository.py +0 -0
  313. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/sqlite_market_repository.py +0 -0
  314. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/sqlite_repository.py +0 -0
  315. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/workflow.py +0 -0
  316. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/contact/__init__.py +0 -0
  317. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/contact/offer_sources.py +0 -0
  318. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/contact/outreach_repository.py +0 -0
  319. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/contact/research_fetcher.py +0 -0
  320. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/contact/research_repository.py +0 -0
  321. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/contact/sqlite_repository.py +0 -0
  322. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/determinations.py +0 -0
  323. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/__init__.py +0 -0
  324. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/archived_smart_posting.py +0 -0
  325. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/ats_adapters.py +0 -0
  326. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/capture_recovery.py +0 -0
  327. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/execution_result_plan.py +0 -0
  328. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/listing_display.py +0 -0
  329. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/posting_source_proposals.py +0 -0
  330. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/production_wiring.py +0 -0
  331. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/recovery_manifest.py +0 -0
  332. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/result_budget.py +0 -0
  333. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/smart_postings.py +0 -0
  334. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/sqlite_execution_repository.py +0 -0
  335. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/sqlite_identity_resolver.py +0 -0
  336. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/sqlite_repository.py +0 -0
  337. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/sqlite_run_repository.py +0 -0
  338. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/sqlite_search_unit_repository.py +0 -0
  339. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/enrichment/__init__.py +0 -0
  340. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/enrichment/execution_lease.py +0 -0
  341. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/enrichment/interpretation.py +0 -0
  342. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/enrichment/linkedin_apply_resolver.py +0 -0
  343. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/enrichment/page_interpretation.py +0 -0
  344. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/enrichment/playwright_fetcher.py +0 -0
  345. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/enrichment/posting_sources.py +0 -0
  346. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/events/__init__.py +0 -0
  347. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/events/in_process_bus.py +0 -0
  348. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/events/watermark.py +0 -0
  349. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/gmail/__init__.py +0 -0
  350. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/gmail/auth.py +0 -0
  351. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/gmail/client.py +0 -0
  352. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/gmail/mcp_server.py +0 -0
  353. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/gmail/privacy.py +0 -0
  354. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/gmail/windows_private_file.py +0 -0
  355. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/interview/__init__.py +0 -0
  356. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/interview/sqlite_repository.py +0 -0
  357. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/job_locators.py +0 -0
  358. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/learning/__init__.py +0 -0
  359. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/learning/sqlite_repository.py +0 -0
  360. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/__init__.py +0 -0
  361. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/agent_runtime_antigravity.py +0 -0
  362. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/agent_runtime_claude.py +0 -0
  363. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/agent_runtime_codex.py +0 -0
  364. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/agent_runtime_pool.py +0 -0
  365. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/attempt_admission.py +0 -0
  366. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/codex_runtime_storage.py +0 -0
  367. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/codex_turn.py +0 -0
  368. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/codex_workspace.py +0 -0
  369. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/llm_client.py +0 -0
  370. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/model_catalog.py +0 -0
  371. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/provider_availability.py +0 -0
  372. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/provider_errors.py +0 -0
  373. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/task_instructions.py +0 -0
  374. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/__init__.py +0 -0
  375. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/accepted_export.py +0 -0
  376. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/accepted_export_api.py +0 -0
  377. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/artifact_writer.py +0 -0
  378. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/bullet_provenance_repository.py +0 -0
  379. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/company_briefing_fetcher.py +0 -0
  380. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/company_briefings.py +0 -0
  381. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/cover_letter_files.py +0 -0
  382. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/cover_letter_policy.py +0 -0
  383. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/docx_export.py +0 -0
  384. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/employer_analysis_repository.py +0 -0
  385. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/html_resume_pdf.py +0 -0
  386. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/letter_reviews.py +0 -0
  387. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/locale_variants.py +0 -0
  388. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/manual_decline.py +0 -0
  389. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/playwright_html_pdf.py +0 -0
  390. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/resume_html_migration.py +0 -0
  391. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/resume_style.py +0 -0
  392. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/screening_answers.py +0 -0
  393. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/sqlite_repository.py +0 -0
  394. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/unit_of_work.py +0 -0
  395. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/user_edit_review.py +0 -0
  396. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/voice_adapter.py +0 -0
  397. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/voice_prompts.py +0 -0
  398. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/__init__.py +0 -0
  399. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/compensation_role_family_seed.py +0 -0
  400. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/identity_upcast.py +0 -0
  401. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/legacy_to_v10_execute.py +0 -0
  402. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/legacy_to_v11_execute.py +0 -0
  403. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/legacy_to_v12_execute.py +0 -0
  404. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/legacy_to_v13_execute.py +0 -0
  405. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/legacy_to_v14_execute.py +0 -0
  406. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/legacy_to_v15_execute.py +0 -0
  407. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/legacy_to_v9_execute.py +0 -0
  408. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/resume_template_seed.py +0 -0
  409. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_manifest.py +0 -0
  410. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v10.py +0 -0
  411. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v10.sql +0 -0
  412. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v11.py +0 -0
  413. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v11.sql +0 -0
  414. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v12.py +0 -0
  415. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v12.sql +0 -0
  416. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v13.py +0 -0
  417. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v13.sql +0 -0
  418. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v14.py +0 -0
  419. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v14.sql +0 -0
  420. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v15.py +0 -0
  421. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v15.sql +0 -0
  422. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v7.py +0 -0
  423. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v7.sql +0 -0
  424. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v8.py +0 -0
  425. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v8.sql +0 -0
  426. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v9.py +0 -0
  427. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v9.sql +0 -0
  428. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v10_to_v11_execute.py +0 -0
  429. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v11_to_v12_execute.py +0 -0
  430. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v12_activation.py +0 -0
  431. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v12_to_v13_execute.py +0 -0
  432. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v13_activation.py +0 -0
  433. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v13_to_v14_execute.py +0 -0
  434. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v14_activation.py +0 -0
  435. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v14_to_v15_execute.py +0 -0
  436. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v14_to_v15_inplace.py +0 -0
  437. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v15_activation.py +0 -0
  438. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_apply_run_projections.py +0 -0
  439. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_artifact_list_projections.py +0 -0
  440. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_candidate.py +0 -0
  441. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_contact_projections.py +0 -0
  442. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_copy.py +0 -0
  443. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_dashboard_projections.py +0 -0
  444. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_duplicate_links.py +0 -0
  445. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_events.py +0 -0
  446. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_evidence_usage_projections.py +0 -0
  447. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_execute.py +0 -0
  448. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_job_detail_projections.py +0 -0
  449. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_job_list_projections.py +0 -0
  450. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_pipeline_step_projections.py +0 -0
  451. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_plan.py +0 -0
  452. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_population_steps.py +0 -0
  453. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_preflight.py +0 -0
  454. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_quiescence.py +0 -0
  455. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_root.py +0 -0
  456. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_score_keywords.py +0 -0
  457. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_verify.py +0 -0
  458. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_work_items.py +0 -0
  459. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_workflow_run_projections.py +0 -0
  460. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v8_execute.py +0 -0
  461. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v7_dashboard_outcome_conversion.py +0 -0
  462. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v7_dashboard_projection_rows.py +0 -0
  463. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v7_evidence_usage_projection_rows.py +0 -0
  464. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v7_job_list_projection_rows.py +0 -0
  465. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v7_to_v8_execute.py +0 -0
  466. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v8_to_v9_execute.py +0 -0
  467. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v9_to_v10_execute.py +0 -0
  468. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/network/__init__.py +0 -0
  469. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/network/fetch_failures.py +0 -0
  470. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/network/http_client.py +0 -0
  471. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/network/politeness.py +0 -0
  472. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/network/proxy.py +0 -0
  473. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/network/public_http.py +0 -0
  474. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/network/rate_limiter.py +0 -0
  475. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/network/robots.py +0 -0
  476. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/network/url_safety.py +0 -0
  477. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/observability/__init__.py +0 -0
  478. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/observability/adapter_spans.py +0 -0
  479. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/observability/enrichment_spans.py +0 -0
  480. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/observability/llm_spans.py +0 -0
  481. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/observability/otel.py +0 -0
  482. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/observability/source_spans.py +0 -0
  483. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/pipeline/__init__.py +0 -0
  484. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/pipeline/sqlite_repository.py +0 -0
  485. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/preflight.py +0 -0
  486. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/preparation/__init__.py +0 -0
  487. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/preparation/sqlite_repository.py +0 -0
  488. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/preparation_recovery.py +0 -0
  489. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/process_ownership.py +0 -0
  490. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/profile/__init__.py +0 -0
  491. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/profile/factory.py +0 -0
  492. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/profile/interpretation.py +0 -0
  493. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/profile/legacy_evidence.py +0 -0
  494. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/profile/legacy_evidence_recovery.py +0 -0
  495. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/profile/pdf_parser.py +0 -0
  496. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/projections/__init__.py +0 -0
  497. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/projections/fetch_failure.py +0 -0
  498. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/projections/location_normalization.py +0 -0
  499. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/projections/projection_builder.py +0 -0
  500. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/projections/source_quality.py +0 -0
  501. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/projections/sqlite_feedback_signals.py +0 -0
  502. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/projections/sqlite_projection_store.py +0 -0
  503. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/rpc/__init__.py +0 -0
  504. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/rpc/job_url_import_status.py +0 -0
  505. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/rpc/workflow_starter.py +0 -0
  506. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/runtime_identity.py +0 -0
  507. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/scoring/__init__.py +0 -0
  508. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/scoring/criteria_provider.py +0 -0
  509. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/scoring/keyword_normalization.py +0 -0
  510. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/scoring/sqlite_repository.py +0 -0
  511. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/setup_probes.py +0 -0
  512. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/__init__.py +0 -0
  513. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/activity_runtime_telemetry.py +0 -0
  514. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/cancellation_audit.py +0 -0
  515. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/client.py +0 -0
  516. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/concurrency.py +0 -0
  517. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/control.py +0 -0
  518. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/durability_probe.py +0 -0
  519. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/finalize.py +0 -0
  520. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/pipeline_step_lifecycle.py +0 -0
  521. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/preparation_outcome_audit.py +0 -0
  522. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/registry.py +0 -0
  523. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/run_in_activity.py +0 -0
  524. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/runtime_guard.py +0 -0
  525. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/task_queue_observation.py +0 -0
  526. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/task_queues.py +0 -0
  527. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/worker.py +0 -0
  528. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/workflow_run_context.py +0 -0
  529. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/interview/__init__.py +0 -0
  530. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/interview/activities.py +0 -0
  531. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/interview/workflow.py +0 -0
  532. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/legacy_evidence_cli.py +0 -0
  533. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/llm.py +0 -0
  534. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/llm_lanes.py +0 -0
  535. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/llm_request_context.py +0 -0
  536. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/materials/__init__.py +0 -0
  537. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/materials/activities.py +0 -0
  538. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/materials/executor.py +0 -0
  539. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/model_defaults.py +0 -0
  540. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/operational_metrics.py +0 -0
  541. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/pipeline/__init__.py +0 -0
  542. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/pipeline/automatic_preparation.py +0 -0
  543. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/pipeline/current_policy_selectors.py +0 -0
  544. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/pipeline/preparation.py +0 -0
  545. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/pipeline/public_fetch_recovery.py +0 -0
  546. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/pipeline/workflow.py +0 -0
  547. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/preparation/__init__.py +0 -0
  548. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/preparation/workflow.py +0 -0
  549. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/profile/__init__.py +0 -0
  550. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/profile/activities.py +0 -0
  551. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/profile/importer.py +0 -0
  552. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/profile/workflow.py +0 -0
  553. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/profile_import.py +0 -0
  554. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/provider_packs.py +0 -0
  555. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/resume_profile.py +0 -0
  556. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/runtime.py +0 -0
  557. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/scoring/__init__.py +0 -0
  558. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/scoring/activities.py +0 -0
  559. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/scoring/eligibility_sql.py +0 -0
  560. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/scoring/employer_analysis.py +0 -0
  561. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/scoring/eval.py +0 -0
  562. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/scoring/material_lifecycle.py +0 -0
  563. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/scoring/scorer.py +0 -0
  564. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/source_proposals_cli.py +0 -0
  565. {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/wizard/__init__.py +0 -0
  566. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/__init__.py +0 -0
  567. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/activity_capacity_api_fixture.py +0 -0
  568. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/apply_execution_fixture.py +0 -0
  569. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/apply_late_settlement_probe.py +0 -0
  570. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/apply_receipt_privacy_fixture.py +0 -0
  571. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/apply_skip_restart_probe.py +0 -0
  572. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/apply_stopped_owner_probe.py +0 -0
  573. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/availability_fixture.py +0 -0
  574. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/availability_transports.py +0 -0
  575. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/career_learning_fixture.py +0 -0
  576. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/company_briefing_fixture.py +0 -0
  577. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/compensation_fakes.py +0 -0
  578. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/conftest.py +0 -0
  579. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/cover_letter_pdf_probe.py +0 -0
  580. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/determination_fakes.py +0 -0
  581. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/email_approval_api_probe.py +0 -0
  582. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/fixtures/discovery_barcelona_acceptance.json +0 -0
  583. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/fixtures/enrichment_retry.sql +0 -0
  584. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/fixtures/hybrid_search_topk.json +0 -0
  585. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/fixtures/required_bullet_rpc_probe.py +0 -0
  586. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/fixtures/rescore_advice_probe.py +0 -0
  587. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/fixtures/rpc_boundary.json +0 -0
  588. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/fixtures/scoring_eval_cases.json +0 -0
  589. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/fixtures/shipped_v6_schema.sql +0 -0
  590. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/gmail_feedback_rpc_fixture.py +0 -0
  591. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/helpers/apply_batch_outcome_native.py +0 -0
  592. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/helpers/apply_custody_native.py +0 -0
  593. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/helpers/apply_execution_native.py +0 -0
  594. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/helpers/apply_execution_ports.py +0 -0
  595. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/helpers/apply_execution_retry_native.py +0 -0
  596. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/helpers/apply_execution_temporal.py +0 -0
  597. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/helpers/apply_session_fence_native.py +0 -0
  598. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/legacy_evidence_fixture.py +0 -0
  599. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/live_browser_helpers.py +0 -0
  600. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/outreach_rpc_harness.py +0 -0
  601. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/page_fakes.py +0 -0
  602. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/politeness_helpers.py +0 -0
  603. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/projection_cross_runtime_fixture.py +0 -0
  604. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/rpc_contract_probe.py +0 -0
  605. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/smart_posting_fakes.py +0 -0
  606. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/source_apply_scope_probe.py +0 -0
  607. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/source_email_scope_probe.py +0 -0
  608. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/source_scope_child_evidence.py +0 -0
  609. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/temporal_env.py +0 -0
  610. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_accepted_docx_export.py +0 -0
  611. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_accepted_export_api.py +0 -0
  612. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_actions.py +0 -0
  613. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_activity_apply.py +0 -0
  614. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_activity_connection_lifetime.py +0 -0
  615. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_activity_control_executor_capacity.py +0 -0
  616. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_activity_cover.py +0 -0
  617. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_activity_enrich.py +0 -0
  618. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_activity_executor_generation_capacity.py +0 -0
  619. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_activity_profile_import.py +0 -0
  620. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_activity_runtime_telemetry.py +0 -0
  621. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_activity_score.py +0 -0
  622. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_activity_tailor.py +0 -0
  623. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_agent_runtime_cleanup_privacy.py +0 -0
  624. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_agent_runtime_codex.py +0 -0
  625. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_agent_runtime_pool.py +0 -0
  626. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_analysis_determinations.py +0 -0
  627. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_analysis_retry_boundaries.py +0 -0
  628. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_analyze_job_use_case.py +0 -0
  629. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_antigravity_adapter.py +0 -0
  630. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_application_url_authority.py +0 -0
  631. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_approval_vocabulary.py +0 -0
  632. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_batch_crashes.py +0 -0
  633. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_batch_limits.py +0 -0
  634. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_browser_ownership.py +0 -0
  635. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_chrome_dry_run_guard.py +0 -0
  636. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_chrome_endpoint_ownership.py +0 -0
  637. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_crash_custody.py +0 -0
  638. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_dashboard_isolation.py +0 -0
  639. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_eligibility_checker.py +0 -0
  640. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_endpoint_consumers.py +0 -0
  641. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_execution.py +0 -0
  642. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_launcher_ownership.py +0 -0
  643. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_log_artifact_registration.py +0 -0
  644. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_native_custody.py +0 -0
  645. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_origin_policy.py +0 -0
  646. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_prompt_builder.py +0 -0
  647. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_queue_selectors.py +0 -0
  648. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_regressions.py +0 -0
  649. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_run_aggregate.py +0 -0
  650. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_runs_projection_from_events.py +0 -0
  651. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_runs_table_dropped.py +0 -0
  652. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_saga.py +0 -0
  653. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_source_census_scope.py +0 -0
  654. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_source_lifetime.py +0 -0
  655. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_stopped_owner_recovery.py +0 -0
  656. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_tools_mcp_server.py +0 -0
  657. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_use_cases.py +0 -0
  658. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_approved_material_recovery_ownership.py +0 -0
  659. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_archived_smart_posting_temporal.py +0 -0
  660. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_artifact_determinations.py +0 -0
  661. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_ats_adapters.py +0 -0
  662. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_audit_projection_parity.py +0 -0
  663. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_auto_apply_reconciler.py +0 -0
  664. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_automatic_compensation_refresh.py +0 -0
  665. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_automatic_material_decline.py +0 -0
  666. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_automatic_preparation.py +0 -0
  667. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_automatic_preparation_overlap.py +0 -0
  668. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_automatic_preparation_temporal_qa.py +0 -0
  669. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_autonomous_agent_port.py +0 -0
  670. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_availability_model_budget.py +0 -0
  671. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_baseline_accomplishment_retention.py +0 -0
  672. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_binding_repair_feedback.py +0 -0
  673. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_browser_capabilities.py +0 -0
  674. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_browser_capabilities_rpc.py +0 -0
  675. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_browser_capability_cli.py +0 -0
  676. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_browser_port.py +0 -0
  677. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_browser_rate_limit_recovery.py +0 -0
  678. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_browser_request_headers.py +0 -0
  679. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_browser_ua_propagation.py +0 -0
  680. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_bullet_provenance.py +0 -0
  681. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_bundled_runtime.py +0 -0
  682. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_cancellation_audit.py +0 -0
  683. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_capsolver_client.py +0 -0
  684. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_captured_posting_recovery.py +0 -0
  685. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_career_learning.py +0 -0
  686. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_claim_grounding.py +0 -0
  687. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_claim_review_response.py +0 -0
  688. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_claude_code_cli_adapter.py +0 -0
  689. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_claude_terminal_failure.py +0 -0
  690. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_codex_adapter_status.py +0 -0
  691. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_codex_home_isolation.py +0 -0
  692. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_codex_runtime_cleanup_privacy.py +0 -0
  693. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_codex_runtime_storage.py +0 -0
  694. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_codex_turn.py +0 -0
  695. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_codex_workspace.py +0 -0
  696. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_company_briefings.py +0 -0
  697. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_audit_contract.py +0 -0
  698. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_benchmark_materialization.py +0 -0
  699. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_benchmark_repository.py +0 -0
  700. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_benchmarks.py +0 -0
  701. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_classification_parallelism.py +0 -0
  702. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_gateway_routing.py +0 -0
  703. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_official_data.py +0 -0
  704. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_refresh_cli.py +0 -0
  705. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_refresh_state.py +0 -0
  706. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_refresh_temporal.py +0 -0
  707. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_source_outcomes.py +0 -0
  708. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_v7_job_id.py +0 -0
  709. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_config_file_transactions.py +0 -0
  710. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_contact_aggregate.py +0 -0
  711. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_contact_projection_parity.py +0 -0
  712. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_contact_provenance.py +0 -0
  713. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_contact_repository.py +0 -0
  714. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_contact_research_activity_heartbeat.py +0 -0
  715. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_contact_research_e2e_fixture.py +0 -0
  716. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_contact_research_inference.py +0 -0
  717. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_contact_research_inference_temporal.py +0 -0
  718. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_contact_research_projection_parity.py +0 -0
  719. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_contact_research_source_policy.py +0 -0
  720. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_contact_research_workflow.py +0 -0
  721. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_content_validator.py +0 -0
  722. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_cover_generation_repair.py +0 -0
  723. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_cover_letter_opt_in.py +0 -0
  724. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_cover_letter_review.py +0 -0
  725. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_cover_requirements.py +0 -0
  726. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_cover_reviewed_anchors.py +0 -0
  727. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_coverage_audit.py +0 -0
  728. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_crawl_politeness_config.py +0 -0
  729. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_criteria_provider.py +0 -0
  730. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_dashboard_projection.py +0 -0
  731. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_database_backup.py +0 -0
  732. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_database_initialization_race.py +0 -0
  733. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_default_resume_fit.py +0 -0
  734. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_dependabot_policy.py +0 -0
  735. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_detail_page_fetcher.py +0 -0
  736. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_detail_page_frames.py +0 -0
  737. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_detail_projection_job_id_contract.py +0 -0
  738. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_digest_canonical_cli.py +0 -0
  739. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_digest_cli.py +0 -0
  740. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_digest_parity.py +0 -0
  741. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_direct_material_attempt_fencing.py +0 -0
  742. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_enrichment_handoff.py +0 -0
  743. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_execution_identity.py +0 -0
  744. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_execution_lineage.py +0 -0
  745. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_execution_reconciliation.py +0 -0
  746. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_execution_result_plan.py +0 -0
  747. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_family_result_budget.py +0 -0
  748. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_identity.py +0 -0
  749. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_limits.py +0 -0
  750. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_preparation_orchestration.py +0 -0
  751. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_production_wiring.py +0 -0
  752. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_result_budget.py +0 -0
  753. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_scheduler_pr4.py +0 -0
  754. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_search_unit_identity.py +0 -0
  755. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_search_units.py +0 -0
  756. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_transaction_lifecycle.py +0 -0
  757. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_distribution_smoke_model.py +0 -0
  758. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_doctor_diagnostics.py +0 -0
  759. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_doctor_gmail_mcp.py +0 -0
  760. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_doctor_langfuse.py +0 -0
  761. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_doctor_llm_budget.py +0 -0
  762. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_doctor_playwright.py +0 -0
  763. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_doctor_temporal.py +0 -0
  764. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_domain_event_parity.py +0 -0
  765. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_domain_events.py +0 -0
  766. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_domain_types.py +0 -0
  767. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_due_follow_up_projection_parity.py +0 -0
  768. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_employer_analysis_ensemble.py +0 -0
  769. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_employer_analysis_leg_config.py +0 -0
  770. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_employer_analysis_model.py +0 -0
  771. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_employer_analysis_repository.py +0 -0
  772. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_aggregate.py +0 -0
  773. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_detail_staleness.py +0 -0
  774. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_events_pr3.py +0 -0
  775. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_extractors.py +0 -0
  776. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_lease_concurrency.py +0 -0
  777. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_politeness_gate.py +0 -0
  778. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_quarantine_gating.py +0 -0
  779. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_queue_selectors.py +0 -0
  780. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_repository.py +0 -0
  781. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_retry.py +0 -0
  782. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_snapshot_pr3.py +0 -0
  783. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_use_cases.py +0 -0
  784. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_visible_capture.py +0 -0
  785. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_event_publication.py +0 -0
  786. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_event_type_migration.py +0 -0
  787. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_event_watermark.py +0 -0
  788. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_evidence_interview_value_objects.py +0 -0
  789. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_exact_v10_schema.py +0 -0
  790. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_exact_v11_schema.py +0 -0
  791. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_exact_v12_schema.py +0 -0
  792. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_exact_v14_schema.py +0 -0
  793. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_exact_v7_apply_acquire_job_identity.py +0 -0
  794. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_exact_v7_schema.py +0 -0
  795. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_exact_v7_selector_job_identity.py +0 -0
  796. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_exact_v7_state_reset.py +0 -0
  797. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_exact_v8_schema.py +0 -0
  798. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_exact_v9_schema.py +0 -0
  799. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_feedback_signal_reader.py +0 -0
  800. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_fetch_failure_projection.py +0 -0
  801. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_fetch_surface_enforcement.py +0 -0
  802. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gateway_http_client.py +0 -0
  803. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gemini_schema.py +0 -0
  804. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gmail_connector.py +0 -0
  805. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gmail_feedback_client_contract.py +0 -0
  806. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gmail_feedback_privacy.py +0 -0
  807. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gmail_feedback_v10_anchors.py +0 -0
  808. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gmail_mcp_config.py +0 -0
  809. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gmail_token_atomic.py +0 -0
  810. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gmail_token_windows_acl.py +0 -0
  811. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gmail_windows_acl_contract.py +0 -0
  812. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_in_process_bus.py +0 -0
  813. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_interpretation_citable_fields.py +0 -0
  814. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_interview_catalog.py +0 -0
  815. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_interview_catalog_packaging.py +0 -0
  816. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_interview_determinations.py +0 -0
  817. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_interview_persistence_v12.py +0 -0
  818. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_interview_prep_generation.py +0 -0
  819. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_job_aggregate.py +0 -0
  820. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_job_application_locators.py +0 -0
  821. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_job_detail_authority.py +0 -0
  822. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_job_list_projection.py +0 -0
  823. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_job_repository.py +0 -0
  824. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_job_url_import_status.py +0 -0
  825. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_job_url_import_workflow.py +0 -0
  826. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_jobspy_gateway_boundary.py +0 -0
  827. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_jobstreaming_source_result_budget.py +0 -0
  828. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_jsonrpc_handlers.py +0 -0
  829. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_jsonrpc_server.py +0 -0
  830. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_keychain_credentials.py +0 -0
  831. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_learning_recommendations.py +0 -0
  832. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_legacy_evidence_preservation.py +0 -0
  833. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_legacy_evidence_recovery.py +0 -0
  834. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_legacy_to_v10_execute.py +0 -0
  835. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_legacy_to_v11_execute.py +0 -0
  836. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_legacy_to_v12_execute.py +0 -0
  837. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_legacy_to_v9_execute.py +0 -0
  838. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_levels_fyi_public.py +0 -0
  839. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_linkedin_apply_resolver.py +0 -0
  840. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_linkedin_authenticated_enrichment_retry.py +0 -0
  841. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_linkedin_guest_dialog.py +0 -0
  842. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_live_worker_smoke_provider.py +0 -0
  843. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_llm_analysis_synthesizer.py +0 -0
  844. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_llm_client.py +0 -0
  845. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_llm_defaults.py +0 -0
  846. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_llm_no_credential_leakage.py +0 -0
  847. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_llm_port.py +0 -0
  848. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_llm_provider_routing.py +0 -0
  849. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_llm_spans.py +0 -0
  850. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_llm_spend_budget.py +0 -0
  851. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_locale_variants.py +0 -0
  852. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_locale_variants_integration.py +0 -0
  853. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_location_normalization.py +0 -0
  854. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_manual_capture_workflow.py +0 -0
  855. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_market_compensation_estimator.py +0 -0
  856. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_market_compensation_repository.py +0 -0
  857. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_material_activity_recovery.py +0 -0
  858. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_material_batch_attempt_fencing.py +0 -0
  859. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_material_candidate_identity.py +0 -0
  860. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_material_context_requirements.py +0 -0
  861. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_material_evidence_selection.py +0 -0
  862. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_material_executor_prerequisites.py +0 -0
  863. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_material_override_retention.py +0 -0
  864. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_material_render_publication.py +0 -0
  865. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_material_review_history.py +0 -0
  866. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_materials_adversarial.py +0 -0
  867. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_materials_aggregate.py +0 -0
  868. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_materials_quality.py +0 -0
  869. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_materials_queue_selectors.py +0 -0
  870. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_materials_repository.py +0 -0
  871. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_materials_repository_v7.py +0 -0
  872. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_materials_review_constraints.py +0 -0
  873. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_materials_unit_of_work.py +0 -0
  874. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_materials_use_cases.py +0 -0
  875. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_model_catalog.py +0 -0
  876. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_native_apply_readiness.py +0 -0
  877. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_numeric_literal_formats.py +0 -0
  878. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_offer_outreach.py +0 -0
  879. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_operational_metrics.py +0 -0
  880. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_otel_init.py +0 -0
  881. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_outreach_draft_gates.py +0 -0
  882. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_outreach_follow_up_derivation.py +0 -0
  883. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_outreach_no_auto_send.py +0 -0
  884. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_outreach_no_send_transport.py +0 -0
  885. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_outreach_projection_parity.py +0 -0
  886. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_outreach_repository_v7.py +0 -0
  887. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_outreach_thread_aggregate.py +0 -0
  888. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_p1b_error_inversion.py +0 -0
  889. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_packaged_browser_contract.py +0 -0
  890. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_parallel_letter_reviews.py +0 -0
  891. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_parallel_resume_reviews.py +0 -0
  892. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_pdf_renderer_ports.py +0 -0
  893. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_pipeline_observability.py +0 -0
  894. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_pipeline_repository.py +0 -0
  895. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_pipeline_status_cli.py +0 -0
  896. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_pipeline_step_events.py +0 -0
  897. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_pipeline_step_lifecycle_emission.py +0 -0
  898. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_pipeline_step_projection.py +0 -0
  899. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_pipeline_use_cases.py +0 -0
  900. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_politeness_gateway.py +0 -0
  901. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_politeness_ports.py +0 -0
  902. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_posted_compensation_repository.py +0 -0
  903. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_posted_compensation_source_fence.py +0 -0
  904. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_posting_availability_rereview.py +0 -0
  905. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_posting_availability_review.py +0 -0
  906. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_posting_source_proposals.py +0 -0
  907. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_posting_source_selection.py +0 -0
  908. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_posting_sources.py +0 -0
  909. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_preflight.py +0 -0
  910. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_preparation_availability_cache.py +0 -0
  911. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_preparation_capture_reuse.py +0 -0
  912. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_preparation_job_reader.py +0 -0
  913. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_preparation_manual_decline.py +0 -0
  914. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_preparation_outcome_audit.py +0 -0
  915. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_preparation_score_cancellation.py +0 -0
  916. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_preparation_score_material_block.py +0 -0
  917. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_process_ownership_census.py +0 -0
  918. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_process_ownership_graceful.py +0 -0
  919. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_process_ownership_scope_fence.py +0 -0
  920. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_process_ownership_temporal.py +0 -0
  921. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_profile_aggregate.py +0 -0
  922. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_profile_determinations.py +0 -0
  923. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_profile_import.py +0 -0
  924. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_profile_snapshot.py +0 -0
  925. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_profile_use_cases.py +0 -0
  926. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_projection_builder.py +0 -0
  927. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_provider_availability_recovery.py +0 -0
  928. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_provider_packs.py +0 -0
  929. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_provider_transient_recovery.py +0 -0
  930. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_public_destination_http.py +0 -0
  931. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_public_fetch_recovery.py +0 -0
  932. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_python_package_attribution.py +0 -0
  933. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_release_check.py +0 -0
  934. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_release_workflow_topology.py +0 -0
  935. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_remaining_determinations.py +0 -0
  936. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_render_resume_pdf_handler.py +0 -0
  937. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_repeat_application_prevention.py +0 -0
  938. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_repository_construction.py +0 -0
  939. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_required_bullet_coaching.py +0 -0
  940. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_required_skill_categories.py +0 -0
  941. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_requirement_fit_resolution.py +0 -0
  942. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_requirement_led_tailoring.py +0 -0
  943. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_resume_assembler.py +0 -0
  944. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_resume_html_migration.py +0 -0
  945. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_resume_polish_policy.py +0 -0
  946. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_resume_review_response_bounds.py +0 -0
  947. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_rpc_cancel_run.py +0 -0
  948. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_rpc_contract_boundary.py +0 -0
  949. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_rpc_handlers_apply_workflow.py +0 -0
  950. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_rpc_learning_recommendations.py +0 -0
  951. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_rpc_otel.py +0 -0
  952. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_rpc_server_workflow_mode.py +0 -0
  953. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_runtime_identity.py +0 -0
  954. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_saved_default_model.py +0 -0
  955. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_saved_edit_determinations.py +0 -0
  956. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_saved_posting_availability.py +0 -0
  957. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_saved_posting_availability_runtime.py +0 -0
  958. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_saved_search_read_failure.py +0 -0
  959. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_schema_v7_packaging.py +0 -0
  960. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_activity_recovery.py +0 -0
  961. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_aggregate.py +0 -0
  962. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_atomic_publication.py +0 -0
  963. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_batch_ownership.py +0 -0
  964. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_eligibility_stage_state.py +0 -0
  965. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_interview_binding.py +0 -0
  966. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_profile_impact.py +0 -0
  967. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_queue_selectors.py +0 -0
  968. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_repository.py +0 -0
  969. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_saved_search_preflight.py +0 -0
  970. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_source_fence.py +0 -0
  971. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_staleness_publication.py +0 -0
  972. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_use_cases.py +0 -0
  973. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_scorer.py +0 -0
  974. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_scoring_determinations.py +0 -0
  975. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_scoring_eval.py +0 -0
  976. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_scoring_eval_feedback.py +0 -0
  977. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_scoring_policy.py +0 -0
  978. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_screening_answers.py +0 -0
  979. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_screening_answers_integration.py +0 -0
  980. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_search_unit_concurrency_assessment.py +0 -0
  981. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_selected_apply_url_refresh.py +0 -0
  982. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_selected_board_wiring.py +0 -0
  983. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_semantic_determinations.py +0 -0
  984. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_semantic_storage.py +0 -0
  985. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_setup_probes.py +0 -0
  986. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_setup_synthesis_auth.py +0 -0
  987. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_single_provider_analysis.py +0 -0
  988. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_smart_posting_intake.py +0 -0
  989. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_smartextract_discovery.py +0 -0
  990. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_smartextract_resilience.py +0 -0
  991. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_source_quality_projection_pr4.py +0 -0
  992. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_source_registry.py +0 -0
  993. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_source_spans.py +0 -0
  994. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_sqlite_learning_recommendations.py +0 -0
  995. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_sqlite_profile_repository.py +0 -0
  996. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_stage_runner_thread_safety.py +0 -0
  997. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_stage_state_machine.py +0 -0
  998. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_state_dashboard.py +0 -0
  999. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_state_legacy_parity.py +0 -0
  1000. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_state_machine_parity.py +0 -0
  1001. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_strict_schema.py +0 -0
  1002. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_tailor_judge_selection.py +0 -0
  1003. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_tailor_provenance_integration.py +0 -0
  1004. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_tailor_retailor.py +0 -0
  1005. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_tailor_voice_audit_integration.py +0 -0
  1006. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_tailoring_artifact_boundary.py +0 -0
  1007. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_tailoring_ownership_race.py +0 -0
  1008. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_tailoring_policy_revisions.py +0 -0
  1009. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_tailoring_prompt_projection.py +0 -0
  1010. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_target_search_preferences.py +0 -0
  1011. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_task_queue_observation.py +0 -0
  1012. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_temporal_client.py +0 -0
  1013. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_temporal_concurrency.py +0 -0
  1014. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_temporal_env.py +0 -0
  1015. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_temporal_registry.py +0 -0
  1016. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_temporal_worker.py +0 -0
  1017. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_terminal_material_rejection.py +0 -0
  1018. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v10_to_v11_execute.py +0 -0
  1019. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v12_activation.py +0 -0
  1020. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v14_v15_inplace.py +0 -0
  1021. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v15_candidate_execution.py +0 -0
  1022. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v15_lifecycle_revisions.py +0 -0
  1023. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_apply_run_projections.py +0 -0
  1024. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_artifact_list_projections.py +0 -0
  1025. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_candidate.py +0 -0
  1026. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_contact_projections_copy.py +0 -0
  1027. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_copy.py +0 -0
  1028. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_dashboard_projections.py +0 -0
  1029. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_duplicate_links.py +0 -0
  1030. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_event_copy.py +0 -0
  1031. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_evidence_usage_projections.py +0 -0
  1032. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_execute.py +0 -0
  1033. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_feedback_copy.py +0 -0
  1034. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_job_detail_projections.py +0 -0
  1035. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_job_list_projections.py +0 -0
  1036. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_pipeline_step_projections_copy.py +0 -0
  1037. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_plan.py +0 -0
  1038. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_population_steps.py +0 -0
  1039. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_preflight.py +0 -0
  1040. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_quiescence.py +0 -0
  1041. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_root_copy.py +0 -0
  1042. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_score_keywords.py +0 -0
  1043. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_verify.py +0 -0
  1044. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_work_items_copy.py +0 -0
  1045. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_workflow_run_projections_copy.py +0 -0
  1046. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v8_execute.py +0 -0
  1047. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v7_cover_runtime.py +0 -0
  1048. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v7_dashboard_outcome_conversion.py +0 -0
  1049. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v7_dashboard_projection_rows.py +0 -0
  1050. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v7_evidence_usage_projection_rows.py +0 -0
  1051. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v7_job_list_projection_rows.py +0 -0
  1052. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v7_materials_selectors.py +0 -0
  1053. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v7_projection_builder_event_identity.py +0 -0
  1054. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v7_score_runtime.py +0 -0
  1055. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v7_tailor_runtime.py +0 -0
  1056. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v7_to_v8_execute.py +0 -0
  1057. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v8_to_v9_execute.py +0 -0
  1058. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v9_to_v10_execute.py +0 -0
  1059. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_voice_adapter.py +0 -0
  1060. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_voice_payload.py +0 -0
  1061. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workday_discovery.py +0 -0
  1062. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workday_gateway_routing.py +0 -0
  1063. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_worker_cooperative_shutdown.py +0 -0
  1064. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_worker_heartbeat_loop.py +0 -0
  1065. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_worker_reconciler.py +0 -0
  1066. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_worker_trace_context.py +0 -0
  1067. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_apply.py +0 -0
  1068. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_control_capacity.py +0 -0
  1069. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_discovery.py +0 -0
  1070. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_durability_probe.py +0 -0
  1071. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_finalize.py +0 -0
  1072. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_heavy_rpc_conversions.py +0 -0
  1073. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_id_overlap.py +0 -0
  1074. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_job_pipeline.py +0 -0
  1075. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_job_preparation.py +0 -0
  1076. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_run_context.py +0 -0
  1077. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_runs_projection_from_events.py +0 -0
  1078. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_start_metadata.py +0 -0
  1079. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_starter_cache.py +0 -0
  1080. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workspace_migration.py +0 -0
  1081. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/v6_feedback_fixture.py +0 -0
  1082. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/v6_migration_fixture.py +0 -0
  1083. {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/workflow_determination_fakes.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: jobctrl
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Summary: AI-powered end-to-end job application pipeline
5
5
  Project-URL: Homepage, https://github.com/ebarti/JobCtrl
6
6
  Project-URL: Repository, https://github.com/ebarti/JobCtrl
@@ -49,7 +49,7 @@ Requires-Dist: pytest-timeout<3,>=2.4; extra == 'dev'
49
49
  Requires-Dist: pytest-xdist<4,>=3.8; extra == 'dev'
50
50
  Requires-Dist: pytest>=7.0; extra == 'dev'
51
51
  Requires-Dist: python-docx<2,>=1.2; extra == 'dev'
52
- Requires-Dist: ruff==0.17.1; extra == 'dev'
52
+ Requires-Dist: ruff==0.17.3; extra == 'dev'
53
53
  Provides-Extra: providers
54
54
  Requires-Dist: claude-agent-sdk==0.2.121; extra == 'providers'
55
55
  Requires-Dist: google-antigravity==0.1.2; extra == 'providers'
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "jobctrl"
3
- version = "0.4.0"
3
+ version = "0.4.1"
4
4
  description = "AI-powered end-to-end job application pipeline"
5
5
  readme = "README.md"
6
6
  license = "AGPL-3.0-only"
@@ -65,7 +65,7 @@ dev = [
65
65
  "pytest-timeout>=2.4,<3",
66
66
  "pytest-xdist>=3.8,<4",
67
67
  "python-docx>=1.2,<2",
68
- "ruff==0.17.1",
68
+ "ruff==0.17.3",
69
69
  ]
70
70
  providers = [
71
71
  "claude-agent-sdk==0.2.121",
@@ -188,7 +188,7 @@ def _config(
188
188
  "locations": [{"label": "remote", "location": FIXED_LOCATION, "remote": True}],
189
189
  "defaults": {
190
190
  "results_per_site": results_per_site,
191
- "hours_old": 72,
191
+ "hours_old": None,
192
192
  "country_indeed": "usa",
193
193
  },
194
194
  "location": {
@@ -1,3 +1,3 @@
1
1
  """JobCtrl — AI-powered end-to-end job application pipeline."""
2
2
 
3
- __version__ = "0.4.0"
3
+ __version__ = "0.4.1"
@@ -24,6 +24,7 @@ from jobctrl.workflow_specs import (
24
24
  build_apply_workflow_spec,
25
25
  build_profile_import_workflow_spec,
26
26
  build_run_stage_workflow_spec,
27
+ reject_discover_preview,
27
28
  start_workflow_spec_and_wait_sync,
28
29
  workflow_result_to_dict,
29
30
  )
@@ -97,6 +98,22 @@ def run_local_action(request: LocalActionRequest) -> LocalActionResult:
97
98
  error=f"Unknown action stage: {request.stage}",
98
99
  )
99
100
 
101
+ try:
102
+ reject_discover_preview([request.stage], dry_run=request.dry_run)
103
+ except ValueError as exc:
104
+ return LocalActionResult(
105
+ ok=False,
106
+ action_id=action_id,
107
+ stage=request.stage,
108
+ status="failed",
109
+ started_at=started_at,
110
+ finished_at=utc_now(),
111
+ duration_ms=int((perf_counter() - start) * 1000),
112
+ job_url=request.job_url,
113
+ dry_run=request.dry_run,
114
+ error=str(exc),
115
+ )
116
+
100
117
  apply_job_id: str | None = None
101
118
  try:
102
119
  _bootstrap_runtime()
@@ -2772,7 +2772,7 @@ def reset_failed() -> int:
2772
2772
  try:
2773
2773
  reset_retry_stages(
2774
2774
  conn, [(str(job_id), "apply")], tenant_id=tenant_id,
2775
- reset_attempts=True, only_failed=True, _allow_apply_only=True,
2775
+ reset_attempts=True, only_failed=True,
2776
2776
  )
2777
2777
  count += 1
2778
2778
  except ValueError as exc:
@@ -29,6 +29,7 @@ from jobctrl.workflow_specs import (
29
29
  build_apply_workflow_spec,
30
30
  build_compensation_refresh_workflow_spec,
31
31
  build_run_stage_workflow_spec,
32
+ reject_discover_preview,
32
33
  start_workflow_spec_and_wait_sync,
33
34
  workflow_result_to_dict,
34
35
  )
@@ -286,9 +287,12 @@ def _write_env_updates(path: Path, updates: dict[str, str], *, dry_run: bool, qu
286
287
  if not quiet:
287
288
  console.print(f"[yellow]Would update {path}:[/yellow] {', '.join(sorted(updates))}")
288
289
  return
289
- path.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
290
- path.write_text(_env_file_updates(path, updates), encoding="utf-8")
291
- path.chmod(0o600)
290
+ from jobctrl.config import config_file_lock
291
+
292
+ # Coordinate the read/merge/write with the init wizard's file updates.
293
+ with config_file_lock(path=path):
294
+ path.write_text(_env_file_updates(path, updates), encoding="utf-8")
295
+ path.chmod(0o600)
292
296
  for key, value in updates.items():
293
297
  import os
294
298
 
@@ -730,6 +734,14 @@ def _render_run_timeline(run: dict, limit: int = 8) -> Panel | None:
730
734
  )
731
735
 
732
736
 
737
+ def _check_discover_preview(stages: list[str], *, dry_run: bool) -> None:
738
+ try:
739
+ reject_discover_preview(stages, dry_run=dry_run)
740
+ except ValueError as exc:
741
+ console.print(f"[red]Error:[/red] {exc}")
742
+ raise typer.Exit(code=2) from exc
743
+
744
+
733
745
  def _run_stage_command(
734
746
  stage: str,
735
747
  *,
@@ -744,6 +756,7 @@ def _run_stage_command(
744
756
  tailor_judge_model: str | None = None,
745
757
  ) -> None:
746
758
  """Run a single pipeline stage through the shared orchestrator."""
759
+ _check_discover_preview([stage], dry_run=dry_run)
747
760
  _bootstrap()
748
761
 
749
762
  _check_tier2_stage(stage)
@@ -991,8 +1004,13 @@ def action(
991
1004
  def init() -> None:
992
1005
  """Run the first-time setup wizard (profile, resume, search config)."""
993
1006
  from jobctrl.wizard.init import run_wizard
1007
+ from jobctrl.domain.errors import ConfigurationError
994
1008
 
995
- run_wizard()
1009
+ try:
1010
+ run_wizard()
1011
+ except ConfigurationError as exc:
1012
+ console.print(f"[red]Setup stopped:[/red] {exc}")
1013
+ raise typer.Exit(code=1) from exc
996
1014
 
997
1015
 
998
1016
  @app.command()
@@ -1355,9 +1373,9 @@ def run(
1355
1373
  ),
1356
1374
  ) -> None:
1357
1375
  """Run one or more pipeline stages in order."""
1358
- _bootstrap()
1359
-
1360
1376
  stage_list = stages if stages else ["all"]
1377
+ _check_discover_preview(stage_list, dry_run=dry_run)
1378
+ _bootstrap()
1361
1379
 
1362
1380
  # Validate stage names
1363
1381
  for s in stage_list:
@@ -2131,6 +2149,9 @@ def retry(
2131
2149
  raise typer.Exit(code=1)
2132
2150
 
2133
2151
  console.print(f"[green]Reset {stage} for retry:[/green] {job_url}")
2152
+ if job_url.retailor_required:
2153
+ console.print("Approved materials remain available. Use explicit re-tailor to create a replacement.")
2154
+ return
2134
2155
  if run_after:
2135
2156
  if stage == "apply":
2136
2157
  identity = SqliteJobIdentityResolver(get_connection()).resolve_current_by_posting_url(
@@ -469,11 +469,14 @@ def load_discovery_control_settings() -> dict:
469
469
  if search_cfg is None:
470
470
  search_cfg = _default_discovery_search_config()
471
471
  effective = effective_discovery_search_config(search_cfg)
472
- # Legacy JSON may contain numeric tier strings. Comparisons in provider
473
- # planning use integers; normalize the execution copy, not the saved row.
472
+ # Legacy JSON may contain numeric strings. Normalize only the execution
473
+ # copy so planning and adapter capability checks keep the stored bytes.
474
474
  for query in effective.get("queries", []):
475
475
  if "tier" in query:
476
476
  query["tier"] = int(query["tier"])
477
+ for key in ("results_per_site", "hours_old", "distance"):
478
+ if key in effective.get("defaults", {}):
479
+ effective["defaults"][key] = int(effective["defaults"][key])
477
480
  return effective
478
481
 
479
482
 
@@ -542,18 +545,31 @@ def load_discovery_automation_settings() -> dict[str, object]:
542
545
  def save_discovery_automation_settings(
543
546
  *,
544
547
  auto_apply: bool,
545
- apply_approval_required: bool,
548
+ apply_approval_required: bool | None,
549
+ expected_automation: Mapping[str, object] | None = None,
550
+ initialize_approval_default: bool = False,
546
551
  ) -> None:
547
552
  """Persist Apply automation choices with the SQLite-owned Discovery settings."""
548
553
  def update(search_cfg: dict) -> dict:
549
554
  raw_automation = search_cfg.get("automation")
550
555
  automation = dict(raw_automation) if isinstance(raw_automation, dict) else {}
551
- automation.update(
552
- {
553
- "auto_apply": bool(auto_apply),
554
- "apply_approval_required": bool(apply_approval_required),
555
- }
556
- )
556
+ updates = {"auto_apply": bool(auto_apply)}
557
+ if apply_approval_required is not None:
558
+ updates["apply_approval_required"] = bool(apply_approval_required)
559
+ if expected_automation is not None and any(
560
+ (key in automation, automation.get(key))
561
+ != (key in expected_automation, expected_automation.get(key))
562
+ for key in updates
563
+ ):
564
+ from jobctrl.domain.errors import ConfigurationError
565
+
566
+ raise ConfigurationError(
567
+ "Apply automation changed while setup was awaiting your choice. "
568
+ "Your Apply settings were not changed; retry jobctrl init."
569
+ )
570
+ if initialize_approval_default:
571
+ automation.setdefault("apply_approval_required", True)
572
+ automation.update(updates)
557
573
  search_cfg["automation"] = automation
558
574
  return search_cfg
559
575
 
@@ -657,7 +673,9 @@ def _read_discovery_search_config(
657
673
  return loaded
658
674
 
659
675
 
660
- def _update_discovery_search_config(update: Callable[[dict], dict]) -> None:
676
+ def _update_discovery_search_config(
677
+ update: Callable[[dict], dict], *, first_use_update: Callable[[dict], dict] | None = None,
678
+ ) -> None:
661
679
  """Validate and update under the same write lock, preserving invalid rows."""
662
680
  try:
663
681
  DB_PATH.lstat()
@@ -674,7 +692,48 @@ def _update_discovery_search_config(update: Callable[[dict], dict]) -> None:
674
692
  conn.row_factory = sqlite3.Row
675
693
  conn.execute("BEGIN IMMEDIATE")
676
694
  current = _read_discovery_search_config(conn)
677
- next_config = update(current or _default_discovery_search_config())
695
+ current_config = current or _default_discovery_search_config()
696
+ previous_config = json.loads(json.dumps(current_config))
697
+ current_boards = resolve_jobspy_boards(current_config, warn=False)
698
+ current_hours = current_config.get("defaults", {}).get("hours_old", 72)
699
+ current_hours = int(current_hours) if current_hours is not None else None
700
+ updater = first_use_update if current is None and first_use_update is not None else update
701
+ next_config = updater(current_config)
702
+ next_boards = resolve_jobspy_boards(next_config, warn=False)
703
+ next_hours = next_config.get("defaults", {}).get("hours_old", 72)
704
+ next_hours = int(next_hours) if next_hours is not None else None
705
+ selection_changed = previous_config.get("location_labels") != next_config.get("location_labels")
706
+ changed_boards = next_boards if next_hours != current_hours or selection_changed else [
707
+ board for board in next_boards if board not in current_boards
708
+ ]
709
+ from jobctrl.domain.profile.search_targets import legacy_remote_target_rows
710
+
711
+ old_legacy = legacy_remote_target_rows(previous_config.get("locations"))
712
+ new_legacy = legacy_remote_target_rows(next_config.get("locations"))
713
+ if changed_boards or old_legacy != new_legacy:
714
+ row = conn.execute(
715
+ "SELECT experience_target_locations, experience_target_work_models FROM candidate_profiles "
716
+ "WHERE tenant_id = ? AND profile_id = ?",
717
+ (str(LOCAL_TENANT), "default"),
718
+ ).fetchone()
719
+ from jobctrl.domain.discovery.remote_search import validate_target_row
720
+ from jobctrl.domain.profile.search_targets import active_target_rows, guarded_target_rows, has_profile_target_rows
721
+
722
+ rows = new_legacy
723
+ profile_overrides = False
724
+ if row is not None:
725
+ locations, models = row["experience_target_locations"], row["experience_target_work_models"]
726
+ if not isinstance(locations, str) or not isinstance(models, str):
727
+ raise InvalidSavedSearchError("Saved Candidate Profile targets")
728
+ profile_overrides = has_profile_target_rows(locations, models)
729
+ if profile_overrides:
730
+ rows = guarded_target_rows(locations, models)
731
+ for location, choices, label in active_target_rows(rows, next_config):
732
+ boards = next_boards if not profile_overrides and (location, choices, label) not in old_legacy else changed_boards
733
+ if boards:
734
+ validate_target_row(
735
+ location=location, choices=choices, sites=tuple(boards), hours_old=next_hours
736
+ )
678
737
  _ensure_discovery_settings_table(conn)
679
738
  now = datetime_utc_now()
680
739
  conn.execute(
@@ -20,6 +20,7 @@ from jobctrl import config
20
20
  from jobctrl.database import get_connection, init_db
21
21
  from jobctrl.domain.discovery import Employer, JobMetadata, PostingUrl, SearchStrategy, Source
22
22
  from jobctrl.domain.discovery.execution import DiscoveryExecutionRef
23
+ from jobctrl.domain.discovery.remote_search import RemoteSearchConfigurationError, validate_remote_search_scope
23
24
  from jobctrl.domain.discovery.search_units import (
24
25
  DiscoverySearchSpec,
25
26
  DiscoverySearchUnit,
@@ -1093,7 +1094,7 @@ def _run_one_search(
1093
1094
  label = f'''"{s["query"]}" in {s["location"]} {("(remote)" if s.get("remote") else "")}'''
1094
1095
  if "tier" in s:
1095
1096
  label += f" [tier {s['tier']}]"
1096
- gd_location = glassdoor_map.get(s["location"], s["location"].split(",")[0])
1097
+ gd_location = glassdoor_map.get(s["location"], s["location"].split(",")[0]) if s["location"] else ""
1097
1098
  has_glassdoor = "glassdoor" in sites
1098
1099
  other_sites = [si for si in sites if si != "glassdoor"]
1099
1100
  all_dfs = []
@@ -1322,6 +1323,19 @@ def _configured_searches(
1322
1323
  ]
1323
1324
 
1324
1325
 
1326
+ def validate_remote_search_config(search_cfg: dict, sites: list[str]) -> None:
1327
+ """Preflight the exact selected rows and boards before starting a crawl."""
1328
+ defaults = search_cfg.get("defaults") or {}
1329
+ searches = _configured_searches(
1330
+ search_cfg, tiers=search_cfg.get("tiers"), locations=search_cfg.get("location_labels"),
1331
+ )
1332
+ for search in searches:
1333
+ validate_remote_search_scope(
1334
+ sites, location=str(search["location"]), remote_only=bool(search.get("remote")),
1335
+ hours_old=defaults.get("hours_old", 72),
1336
+ )
1337
+
1338
+
1325
1339
  def _durable_search_specs(
1326
1340
  search_cfg: dict,
1327
1341
  *,
@@ -1339,6 +1353,11 @@ def _durable_search_specs(
1339
1353
  glassdoor_map = search_cfg.get("glassdoor_location_map", {})
1340
1354
  specs: list[DiscoverySearchSpec] = []
1341
1355
  for search in searches:
1356
+ # A location-free non-Remote row cannot form a search unit at all.
1357
+ # Board-specific limitations are handled per unit below.
1358
+ validate_remote_search_scope(
1359
+ (), location=str(search["location"]), remote_only=bool(search.get("remote")), hours_old=hours_old,
1360
+ )
1342
1361
  common = {
1343
1362
  "query": str(search["query"]),
1344
1363
  "target_location": str(search["location"]),
@@ -1350,7 +1369,7 @@ def _durable_search_specs(
1350
1369
  for site in sites:
1351
1370
  target_location = str(search["location"])
1352
1371
  provider_location = target_location
1353
- if site == "glassdoor":
1372
+ if site == "glassdoor" and target_location:
1354
1373
  provider_location = str(glassdoor_map.get(target_location, target_location.split(",")[0]))
1355
1374
  specs.append(
1356
1375
  DiscoverySearchSpec(
@@ -1729,19 +1748,20 @@ def _durable_full_crawl(
1729
1748
  persisted_linkedin_detail = any(
1730
1749
  unit.spec.sites == ("linkedin",) and unit.spec.linkedin_fetch_description for unit in existing_units
1731
1750
  )
1732
- specs = _durable_search_specs(
1733
- search_cfg,
1734
- tiers=tiers,
1735
- locations=locations,
1736
- sites=sites,
1737
- results_per_site=results_per_site,
1738
- hours_old=hours_old,
1739
- linkedin_fetch_description=persisted_linkedin_detail,
1740
- )
1741
1751
  if result_budget is not None and existing_units:
1742
1752
  # Live disable/quarantine controls reduce the frozen source allowance;
1743
1753
  # they must not rewrite provider request/checkpoint identities on retry.
1744
1754
  specs = [unit.spec for unit in existing_units]
1755
+ else:
1756
+ specs = _durable_search_specs(
1757
+ search_cfg,
1758
+ tiers=tiers,
1759
+ locations=locations,
1760
+ sites=sites,
1761
+ results_per_site=results_per_site,
1762
+ hours_old=hours_old,
1763
+ linkedin_fetch_description=persisted_linkedin_detail,
1764
+ )
1745
1765
  repository.plan_units(discovery_execution, specs)
1746
1766
  proxy_config = parse_proxy(proxy) if proxy else None
1747
1767
  proxies = [proxy_config.jobspy] if proxy_config else None
@@ -1810,10 +1830,23 @@ def _durable_full_crawl(
1810
1830
  emit_progress(unit, "JobStreaming discovery canceled")
1811
1831
  raise DiscoveryCancelled("JobStreaming discovery canceled")
1812
1832
 
1833
+ try:
1834
+ validate_remote_search_scope(
1835
+ unit.spec.sites, location=unit.spec.target_location,
1836
+ remote_only=unit.spec.remote_only, hours_old=unit.spec.hours_old,
1837
+ )
1838
+ except RemoteSearchConfigurationError:
1839
+ repository.record_failure(
1840
+ lease, error_code=f"{unit.spec.sites[0]}:unsupported_remote_search",
1841
+ error_type="RemoteSearchConfigurationError", retryable=False, reset_checkpoint=False,
1842
+ )
1843
+ emit_progress(repository.get_unit(discovery_execution, lease.unit_id), "Board search rejected")
1844
+ continue
1845
+
1813
1846
  invocations = sum(
1814
1847
  (1 + candidate.recovery_count)
1815
1848
  for candidate in repository.list_units(discovery_execution)
1816
- if candidate.lease_attempt > 0
1849
+ if candidate.lease_attempt > 0 and candidate.last_error_type != "RemoteSearchConfigurationError"
1817
1850
  )
1818
1851
  if invocations > BROAD_BOARD_LEAD_POLICY.max_requests_per_run:
1819
1852
  repository.mark_skipped(lease)
@@ -2077,21 +2110,44 @@ def _durable_full_crawl(
2077
2110
  failed_units = [unit for unit in units if unit.state == "failed"]
2078
2111
  completed_units = [unit for unit in units if unit.state == "completed"]
2079
2112
  canceled_units = [unit for unit in units if unit.state == "canceled"]
2113
+ unsupported_reasons: list[str] = []
2114
+ unsupported_source_ids: set[str] = set()
2115
+ for unit in units:
2116
+ if unit.last_error_type == "UnsupportedRemoteSearch":
2117
+ reason = (
2118
+ f"{', '.join(unit.spec.sites)} cannot apply the selected Remote search filters. "
2119
+ "Remove the board from this search or adjust the target and lookback."
2120
+ )
2121
+ if reason not in unsupported_reasons:
2122
+ unsupported_reasons.append(reason)
2123
+ unsupported_source_ids.update(_jobspy_source_id(site) for site in unit.spec.sites)
2124
+ try:
2125
+ validate_remote_search_scope(
2126
+ unit.spec.sites, location=unit.spec.target_location,
2127
+ remote_only=unit.spec.remote_only, hours_old=unit.spec.hours_old,
2128
+ )
2129
+ except RemoteSearchConfigurationError as exc:
2130
+ if str(exc) not in unsupported_reasons:
2131
+ unsupported_reasons.append(str(exc))
2132
+ unsupported_source_ids.update(_jobspy_source_id(site) for site in unit.spec.sites)
2080
2133
  if canceled_units:
2081
2134
  raise DiscoveryCancelled("JobStreaming discovery canceled")
2082
2135
  if failed_units and not completed_units and counts["accepted"] == 0:
2136
+ if unsupported_reasons:
2137
+ raise RemoteSearchConfigurationError(" ".join(unsupported_reasons))
2083
2138
  raise RuntimeError(f"JobStreaming failed for all {len(failed_units)} search unit(s)")
2084
2139
 
2085
2140
  db_total = int(conn.execute("SELECT COUNT(*) FROM jobs").fetchone()[0])
2086
2141
  admitted_new = sum(count for source, count in result_budget.counts().items() if source.startswith("jobspy:")) if result_budget is not None else counts["new"]
2142
+ failed_source_ids = sorted(set(_failed_jobstreaming_source_ids(units)) | unsupported_source_ids)
2087
2143
  result = {
2088
2144
  "total": counts["accepted"] + max(admitted_new - counts["new"], 0),
2089
2145
  "raw_total": repository.execution_provider_job_count(discovery_execution),
2090
2146
  "new": admitted_new,
2091
2147
  "existing": counts["existing"],
2092
- "errors": len(_failed_jobstreaming_source_ids(units)),
2148
+ "errors": len(failed_source_ids),
2093
2149
  "failed_queries": len(failed_units),
2094
- "failed_source_ids": _failed_jobstreaming_source_ids(units),
2150
+ "failed_source_ids": failed_source_ids,
2095
2151
  "filtered": repository.execution_filtered_count(discovery_execution),
2096
2152
  "db_total": db_total,
2097
2153
  "queries": sum(unit.state in {"completed", "skipped", "failed"} for unit in units),
@@ -2099,6 +2155,8 @@ def _durable_full_crawl(
2099
2155
  "recovered_units": sum(unit.recovered for unit in units),
2100
2156
  "skipped_units": sum(unit.state == "skipped" for unit in units),
2101
2157
  }
2158
+ if unsupported_reasons:
2159
+ result["unsupported_remote_error"] = " ".join(unsupported_reasons)
2102
2160
  emit_progress(None, "JobStreaming discovery complete")
2103
2161
  return result
2104
2162
 
@@ -2145,6 +2203,9 @@ def run_discovery(
2145
2203
  tiers = cfg.get("tiers")
2146
2204
  locations = cfg.get("location_labels")
2147
2205
 
2206
+ if discovery_execution is None:
2207
+ validate_remote_search_config(cfg, sites)
2208
+
2148
2209
  if discovery_execution is not None:
2149
2210
  if activity_attempt is None or activity_attempt < 1:
2150
2211
  raise ValueError("activity_attempt is required for resumable discovery")
@@ -50,6 +50,7 @@ from jobctrl.infrastructure.discovery.live_browser import (
50
50
  LiveBrowserResult,
51
51
  LiveChromeDiscoveryClient,
52
52
  PoliteLiveChromeHttpClient,
53
+ trusted_live_browser_url,
53
54
  prefer_live_browser,
54
55
  )
55
56
  from jobctrl.infrastructure.discovery.production_wiring import DurableJobEventPublisher
@@ -1556,6 +1557,8 @@ def _run_all(
1556
1557
  return target.get("source_id") or f"smart_extract:{slug or 'site'}"
1557
1558
 
1558
1559
  def _browser_client_for_target(target: dict) -> PoliteLiveChromeHttpClient | None:
1560
+ if not trusted_live_browser_url(str(target.get("url") or "")):
1561
+ return None
1559
1562
  if id(target) in selected_clients:
1560
1563
  return selected_clients[id(target)]
1561
1564
  if discovery_execution is None:
@@ -104,6 +104,7 @@ _AUTOMATIC_COMPENSATION_REFRESH_PATCH = "discover-automatic-compensation-refresh
104
104
  _COMPENSATION_MODEL_BUDGET_PATCH = "discover-compensation-model-budget-v1"
105
105
  _SOURCE_RESULT_BUDGET_PATCH = "discover-source-result-budget-v1"
106
106
  _TERMINAL_ENRICHMENT_HANDOFF_PATCH = "discover-terminal-enrichment-handoff-v1"
107
+ _UNSUPPORTED_REMOTE_FAILURE_PATCH = "discover-unsupported-remote-failure-v1"
107
108
 
108
109
 
109
110
  @workflow.defn(name="DiscoverWorkflow")
@@ -205,6 +206,7 @@ class DiscoverWorkflow:
205
206
  completed: list[str] = []
206
207
  failed: list[str] = []
207
208
  failures: list[str] = []
209
+ unsupported_remote_failures: list[str] = []
208
210
  # Score-as-you-discover uses the durable job commit as its handoff
209
211
  # boundary. One execution-scoped enrichment activity polls while source
210
212
  # activities are still producing jobs and hands each successful job to
@@ -249,6 +251,8 @@ class DiscoverWorkflow:
249
251
  failed.append(family)
250
252
  if failure is not None:
251
253
  failures.append(failure)
254
+ if status == "unsupported_remote":
255
+ unsupported_remote_failures.append(failure)
252
256
  if batch_completed:
253
257
  streaming_pass_ordinal += 1
254
258
  await self._stream_family_preparation(
@@ -329,6 +333,29 @@ class DiscoverWorkflow:
329
333
  raise CancelledError() from exc
330
334
  preparation_error = exc
331
335
 
336
+ # A pre-upgrade plan can reach a source activity without the new
337
+ # planning preflight. Finish healthy-family work before reporting the
338
+ # rejected board scope, rather than letting a peer's success hide it.
339
+ if unsupported_remote_failures:
340
+ failure = "; ".join(failures)
341
+ if enrichment_failure is not None:
342
+ failure += f"; enrichment also failed: {enrichment_failure}"
343
+ if preparation_error is not None:
344
+ prep_cause = str(preparation_error.cause) if preparation_error.cause else str(preparation_error)
345
+ failure += f"; preparation also failed: {prep_cause}"
346
+ return DiscoverWorkflowResult(
347
+ families_completed=completed,
348
+ families_failed=failed,
349
+ preparation_started=preparation_started,
350
+ enrichment_status=enrichment_status,
351
+ enrichment_site_errors=enrichment_site_errors,
352
+ compensation_refresh_status=compensation_refresh_status,
353
+ compensation_estimates_written=compensation_estimates_written,
354
+ compensation_refresh_warnings=compensation_refresh_warnings,
355
+ failure=failure,
356
+ error_code="unsupported_remote_search",
357
+ )
358
+
332
359
  all_families_failed = bool(failed) and not completed
333
360
  if all_families_failed:
334
361
  return DiscoverWorkflowResult(
@@ -384,7 +411,7 @@ class DiscoverWorkflow:
384
411
  """Run one family's source crawl; return ``(family, status, failure)``.
385
412
 
386
413
  Never raises: it folds every outcome into a status
387
- (``"ok"``/``"failed"``/``"canceled"``) so ``asyncio.gather`` over a
414
+ (``"ok"``/``"failed"``/``"unsupported_remote"``/``"canceled"``) so ``asyncio.gather`` over a
388
415
  parallel batch always completes and the caller folds results in a
389
416
  deterministic, submission-order pass. Cancellation is surfaced as
390
417
  ``"canceled"`` and re-raised by the caller so it fans out to the whole
@@ -416,6 +443,11 @@ class DiscoverWorkflow:
416
443
  except ActivityError as exc:
417
444
  if _activity_error_was_cancelled(exc):
418
445
  return (family, "canceled", None)
446
+ if (
447
+ _activity_error_code(exc) == "unsupported_remote_search"
448
+ and workflow.patched(_UNSUPPORTED_REMOTE_FAILURE_PATCH)
449
+ ):
450
+ return (family, "unsupported_remote", f"{family}: {exc.cause if exc.cause else exc}")
419
451
  return (family, "failed", f"{family}: {exc.cause if exc.cause else exc}")
420
452
  return (family, "ok", None)
421
453
 
@@ -0,0 +1,56 @@
1
+ """Literal capability checks for the pinned broad-board adapters."""
2
+
3
+ from jobctrl.domain.errors import ConfigurationError
4
+
5
+
6
+ class RemoteSearchConfigurationError(ConfigurationError):
7
+ """A requested board cannot preserve a selected Remote search scope."""
8
+
9
+ code = "unsupported_remote_search"
10
+
11
+
12
+ def validate_remote_search_scope(
13
+ sites: tuple[str, ...] | list[str], *, location: str, remote_only: bool, hours_old: int | None,
14
+ ) -> None:
15
+ """Reject combinations the pinned adapters cannot apply without broadening."""
16
+ if not remote_only and not location:
17
+ raise RemoteSearchConfigurationError(
18
+ "A Hybrid or On-site search needs a location. Add a location or choose only Remote for that row."
19
+ )
20
+ if not remote_only:
21
+ return
22
+ selected = set(sites)
23
+ if "indeed" in selected and hours_old:
24
+ raise RemoteSearchConfigurationError(
25
+ "Indeed cannot combine Remote with the selected lookback. "
26
+ "Remove Indeed from this search or choose a non-Remote target."
27
+ )
28
+ if "glassdoor" in selected and location:
29
+ raise RemoteSearchConfigurationError(
30
+ "Glassdoor cannot combine Remote with a selected location. "
31
+ "Remove Glassdoor from this search or use a location-free Remote target."
32
+ )
33
+ day_limited = sorted(selected & {"glassdoor", "zip_recruiter"})
34
+ if day_limited and hours_old and hours_old % 24:
35
+ raise RemoteSearchConfigurationError(
36
+ f"{', '.join(day_limited)} can apply a Remote lookback only in whole days. "
37
+ "Choose a lookback in multiples of 24 hours or remove the board from this search."
38
+ )
39
+ unsupported = sorted(selected & {"bayt", "bdjobs"})
40
+ if unsupported:
41
+ raise RemoteSearchConfigurationError(
42
+ f"{', '.join(unsupported)} cannot apply a Remote filter. Remove the board from this search."
43
+ )
44
+
45
+
46
+ def validate_target_row(
47
+ sites: tuple[str, ...] | list[str], *, location: str, choices: tuple[str, ...], hours_old: int | None,
48
+ ) -> None:
49
+ """Validate every requested work-model flag without dropping row counterparts."""
50
+ from jobctrl.domain.taxonomy import SEMANTIC_TAXONOMY
51
+
52
+ work_model = SEMANTIC_TAXONOMY["workModel"]
53
+ if not location and {"hybrid", work_model["hybrid"], "onsite", work_model["onsite"]}.intersection(choices):
54
+ validate_remote_search_scope(sites, location="", remote_only=False, hours_old=hours_old)
55
+ if {"remote", work_model["remote"]}.intersection(choices):
56
+ validate_remote_search_scope(sites, location=location, remote_only=True, hours_old=hours_old)
@@ -55,12 +55,20 @@ class DiscoverySearchSpec:
55
55
  def __post_init__(self) -> None:
56
56
  for field_name, value in (
57
57
  ("query", self.query),
58
- ("provider_location", self.provider_location),
59
- ("target_location", self.target_location),
60
58
  ("country_indeed", self.country_indeed),
61
59
  ):
62
60
  if not isinstance(value, str) or not value.strip():
63
61
  raise ValueError(f"{field_name} must be a non-empty string")
62
+ # An empty location is a literal location-free Remote request, not a
63
+ # default geography. Keep both sides empty so no mapping widens it.
64
+ for field_name, value in (
65
+ ("provider_location", self.provider_location),
66
+ ("target_location", self.target_location),
67
+ ):
68
+ if not isinstance(value, str) or (not value.strip() and not (value == "" and self.remote_only)):
69
+ raise ValueError(f"{field_name} must be a non-empty string unless remote-only")
70
+ if (self.provider_location == "") != (self.target_location == ""):
71
+ raise ValueError("location-free searches must not invent a provider or target location")
64
72
  if not self.sites:
65
73
  raise ValueError("sites must contain at least one board")
66
74
  if len(set(self.sites)) != len(self.sites):