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.
- {jobctrl-0.4.0 → jobctrl-0.4.1}/PKG-INFO +2 -2
- {jobctrl-0.4.0 → jobctrl-0.4.1}/pyproject.toml +2 -2
- {jobctrl-0.4.0 → jobctrl-0.4.1}/scripts/search_unit_concurrency_assessment.py +1 -1
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/__init__.py +1 -1
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/actions.py +17 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/launcher.py +1 -1
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/cli.py +27 -6
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/config.py +70 -11
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/discovery/jobspy.py +75 -14
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/discovery/smartextract.py +3 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/discovery/workflow.py +33 -1
- jobctrl-0.4.1/src/jobctrl/domain/discovery/remote_search.py +56 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/discovery/search_units.py +10 -2
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/profile/search_targets.py +49 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/enrichment/detail.py +11 -6
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/jobstreaming_gateway.py +77 -4
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/live_browser.py +30 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/enrichment/sqlite_repository.py +57 -26
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/gmail/feedback.py +70 -21
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/profile/sqlite_repository.py +61 -7
- jobctrl-0.4.1/src/jobctrl/infrastructure/rpc/enrichment_retry.py +90 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/rpc/handlers.py +15 -46
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/rpc/server.py +8 -4
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/native_credentials.py +100 -4
- jobctrl-0.4.1/src/jobctrl/pipeline/retry.py +285 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/pipeline/runner.py +25 -5
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/scoring/cover_letter.py +4 -2
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/scoring/tailor.py +2 -1
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/state.py +37 -57
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/wizard/init.py +331 -49
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/workflow_specs.py +17 -1
- jobctrl-0.4.1/tests/fixtures/rpc_boundary_python.json +1 -0
- jobctrl-0.4.1/tests/gmail_feedback_progress_rpc.py +66 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_dashboard_execution_policy.py +13 -3
- jobctrl-0.4.1/tests/test_discover_preview.py +149 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discover_reliability.py +3 -3
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_url_safety.py +9 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gmail_feedback.py +261 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gmail_feedback_scan_handler.py +51 -2
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_jobstreaming_gateway.py +4 -1
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_jobstreaming_resumable_discovery.py +4 -1
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_live_browser_discovery.py +1 -1
- jobctrl-0.4.1/tests/test_location_free_remote_discovery.py +990 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_native_credentials.py +380 -1
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_optional_extension.py +10 -7
- jobctrl-0.4.1/tests/test_remote_country_snapshot.py +235 -0
- jobctrl-0.4.1/tests/test_remote_search_scope.py +520 -0
- jobctrl-0.4.1/tests/test_retry_material_predecessor.py +98 -0
- jobctrl-0.4.1/tests/test_retry_posting_lifecycle.py +86 -0
- jobctrl-0.4.1/tests/test_stage_retry_consistency.py +664 -0
- jobctrl-0.4.1/tests/test_wizard_files_preservation.py +510 -0
- jobctrl-0.4.1/tests/test_wizard_profile_preservation.py +264 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/uv.lock +192 -127
- jobctrl-0.4.0/src/jobctrl/infrastructure/rpc/enrichment_retry.py +0 -46
- jobctrl-0.4.0/src/jobctrl/pipeline/retry.py +0 -129
- jobctrl-0.4.0/tests/fixtures/rpc_boundary_python.json +0 -1
- {jobctrl-0.4.0 → jobctrl-0.4.1}/.gitignore +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/LICENSE +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/NOTICE +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/README.md +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/__main__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/activities.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/auto_apply.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/batch_outcome.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/chrome.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/cover_letter_binding.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/dashboard.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/dispatch.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/execution.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/native_custody.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/origins.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/ownership.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/process_birth.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/prompt.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/telemetry.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/apply/workflow.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/assets/determinations/taxonomy.v1.json +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/assets/fonts/GEIST-LICENSE.txt +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/assets/fonts/geist-latin-ext-wght-normal.woff2 +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/assets/fonts/geist-latin-wght-normal.woff2 +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/assets/interview/catalog.v1.json +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/browser_capabilities.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/company_briefing_cli.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/config/employers.yaml +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/config/sites.yaml +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/contact/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/contact/activities.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/contact/workflow.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/database.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/digest.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/discovery/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/discovery/activities.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/discovery/execution_reconciliation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/discovery/job_url_import_workflow.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/discovery/manual_capture_import.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/discovery/manual_capture_workflow.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/discovery/target_queries.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/discovery/workday.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/aggregate.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/entities.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/event_privacy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/form_mapping.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/process_manager.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/repeat_application.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/role_equivalence.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/screening_answers.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/services.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/terminal_report.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/use_cases.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/apply/value_objects.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/compensation/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/compensation/benchmarks.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/compensation/classification.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/compensation/market.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/compensation/posted.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/contact/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/contact/aggregate.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/contact/outreach.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/contact/outreach_gates.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/contact/outreach_use_cases.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/contact/research.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/contact/research_services.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/contact/research_use_cases.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/contact/source_policy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/contact/use_cases.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/contact/value_objects.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/determinations.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/discovery/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/discovery/aggregate.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/discovery/execution.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/discovery/identity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/discovery/posting_qualification.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/discovery/scheduler.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/discovery/source_registry.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/discovery/use_cases.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/discovery/value_objects.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/aggregate.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/entities.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/filter_override.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/interpretation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/page_interpretation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/services.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/snapshot_services.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/snapshot_set.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/snapshot_use_case.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/snapshot_value_objects.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/use_cases.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/enrichment/value_objects.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/errors.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/apply.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/base.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/contact.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/discovery.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/enrichment.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/interview.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/materials.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/operations.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/orchestration.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/profile.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/scoring.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/events/workflow.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/exact_values.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/extraction.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/feedback/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/feedback/message_interpretation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/identifiers.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/interview/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/interview/catalog.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/interview/evidence.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/interview/preparation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/interview/question_generation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/interview/use_cases.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/interview/value_objects.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/job_content_identity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/job_snapshot.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/adversarial.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/aggregate.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/analysis.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/analysis_agreement.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/analysis_grounding.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/analyze_use_case.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/artifact_quality.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/claim_grounding.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/claim_review_response.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/claim_verification.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/company_briefings.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/cover_letter_settings.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/coverage_audit.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/edit_intent.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/editable_export.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/entities.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/evidence_selection.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/generation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/locale_variants.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/policy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/provenance.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/provenance_builder.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/quality.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/requirement_coverage.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/resume_document.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/screening_answers.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/services.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/use_cases.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/value_objects.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/materials/voice.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/operations/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/operations/career_learning.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/operations/evidence_map.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/operations/feedback.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/operations/learning.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/operations/projections.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/pipeline/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/pipeline/aggregate.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/pipeline/repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/pipeline/state_machine.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/pipeline/use_cases.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/pipeline_types.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/analysis_agreement.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/apply.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/artifact_generation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/artifact_quality.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/artifact_review.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/claim_verification.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/contact.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/discovery.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/enrichment.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/events.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/feedback.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/job_interpretation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/learning.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/letter_reviews.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/llm.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/materials.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/politeness.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/resume_adversarial.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/retrieval.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/scoring.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/ports/watermark.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/preparation/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/preparation/work_items.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/profile/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/profile/aggregate.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/profile/canonical_sources.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/profile/interpretation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/profile/ports.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/profile/required_bullet_coaching.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/profile/resume_extraction.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/profile/snapshot.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/profile/use_cases.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/profile/value_objects.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/rpc/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/rpc/messages.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/scoring/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/scoring/aggregate.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/scoring/determination.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/scoring/eligibility.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/scoring/policy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/scoring/profile_impact.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/scoring/requirement_fit.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/scoring/retrieval.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/scoring/services.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/scoring/use_cases.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/scoring/value_objects.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/taxonomy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/taxonomy_codes.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/domain/tenant.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/enrichment/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/enrichment/activities.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/enrichment/availability.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/enrichment/availability_workflow.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/analysis/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/analysis/antigravity_analysis_adapter.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/analysis/claude_analysis_adapter.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/analysis/codex_analysis_adapter.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/analysis/ensemble.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/analysis/gemini_schema.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/analysis/llm_analysis_synthesizer.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/analysis/prompts.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/analysis/strict_schema.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/apply/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/apply/claude_code_cli.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/apply/email_sender.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/apply/form_mapping.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/apply/local_chrome.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/apply_controls.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/apply_tools/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/apply_tools/mcp_server.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/captcha/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/captcha/capsolver.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/career_learning.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/commit_notifications.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/automatic_refresh.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/benchmark_ingestion.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/benchmark_lineage.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/benchmark_materialization.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/classification_batch.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/interpretation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/levels_fyi_public.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/official_data.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/refresh.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/refresh_control.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/refresh_state.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/sqlite_benchmark_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/sqlite_market_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/sqlite_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/compensation/workflow.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/contact/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/contact/offer_sources.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/contact/outreach_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/contact/research_fetcher.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/contact/research_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/contact/sqlite_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/determinations.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/archived_smart_posting.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/ats_adapters.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/capture_recovery.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/execution_result_plan.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/listing_display.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/posting_source_proposals.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/production_wiring.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/recovery_manifest.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/result_budget.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/smart_postings.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/sqlite_execution_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/sqlite_identity_resolver.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/sqlite_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/sqlite_run_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/discovery/sqlite_search_unit_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/enrichment/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/enrichment/execution_lease.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/enrichment/interpretation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/enrichment/linkedin_apply_resolver.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/enrichment/page_interpretation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/enrichment/playwright_fetcher.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/enrichment/posting_sources.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/events/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/events/in_process_bus.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/events/watermark.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/gmail/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/gmail/auth.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/gmail/client.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/gmail/mcp_server.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/gmail/privacy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/gmail/windows_private_file.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/interview/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/interview/sqlite_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/job_locators.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/learning/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/learning/sqlite_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/agent_runtime_antigravity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/agent_runtime_claude.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/agent_runtime_codex.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/agent_runtime_pool.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/attempt_admission.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/codex_runtime_storage.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/codex_turn.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/codex_workspace.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/llm_client.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/model_catalog.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/provider_availability.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/provider_errors.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/llm/task_instructions.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/accepted_export.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/accepted_export_api.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/artifact_writer.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/bullet_provenance_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/company_briefing_fetcher.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/company_briefings.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/cover_letter_files.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/cover_letter_policy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/docx_export.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/employer_analysis_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/html_resume_pdf.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/letter_reviews.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/locale_variants.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/manual_decline.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/playwright_html_pdf.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/resume_html_migration.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/resume_style.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/screening_answers.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/sqlite_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/unit_of_work.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/user_edit_review.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/voice_adapter.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/materials/voice_prompts.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/compensation_role_family_seed.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/identity_upcast.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/legacy_to_v10_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/legacy_to_v11_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/legacy_to_v12_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/legacy_to_v13_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/legacy_to_v14_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/legacy_to_v15_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/legacy_to_v9_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/resume_template_seed.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_manifest.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v10.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v10.sql +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v11.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v11.sql +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v12.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v12.sql +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v13.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v13.sql +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v14.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v14.sql +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v15.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v15.sql +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v7.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v7.sql +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v8.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v8.sql +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v9.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/schema_v9.sql +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v10_to_v11_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v11_to_v12_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v12_activation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v12_to_v13_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v13_activation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v13_to_v14_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v14_activation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v14_to_v15_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v14_to_v15_inplace.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v15_activation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_apply_run_projections.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_artifact_list_projections.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_candidate.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_contact_projections.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_copy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_dashboard_projections.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_duplicate_links.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_events.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_evidence_usage_projections.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_job_detail_projections.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_job_list_projections.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_pipeline_step_projections.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_plan.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_population_steps.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_preflight.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_quiescence.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_root.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_score_keywords.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_verify.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_work_items.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v7_workflow_run_projections.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v6_to_v8_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v7_dashboard_outcome_conversion.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v7_dashboard_projection_rows.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v7_evidence_usage_projection_rows.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v7_job_list_projection_rows.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v7_to_v8_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v8_to_v9_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/migrations/v9_to_v10_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/network/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/network/fetch_failures.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/network/http_client.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/network/politeness.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/network/proxy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/network/public_http.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/network/rate_limiter.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/network/robots.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/network/url_safety.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/observability/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/observability/adapter_spans.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/observability/enrichment_spans.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/observability/llm_spans.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/observability/otel.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/observability/source_spans.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/pipeline/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/pipeline/sqlite_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/preflight.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/preparation/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/preparation/sqlite_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/preparation_recovery.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/process_ownership.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/profile/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/profile/factory.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/profile/interpretation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/profile/legacy_evidence.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/profile/legacy_evidence_recovery.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/profile/pdf_parser.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/projections/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/projections/fetch_failure.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/projections/location_normalization.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/projections/projection_builder.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/projections/source_quality.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/projections/sqlite_feedback_signals.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/projections/sqlite_projection_store.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/rpc/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/rpc/job_url_import_status.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/rpc/workflow_starter.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/runtime_identity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/scoring/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/scoring/criteria_provider.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/scoring/keyword_normalization.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/scoring/sqlite_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/setup_probes.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/activity_runtime_telemetry.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/cancellation_audit.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/client.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/concurrency.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/control.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/durability_probe.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/finalize.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/pipeline_step_lifecycle.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/preparation_outcome_audit.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/registry.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/run_in_activity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/runtime_guard.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/task_queue_observation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/task_queues.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/temporal/worker.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/infrastructure/workflow_run_context.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/interview/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/interview/activities.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/interview/workflow.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/legacy_evidence_cli.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/llm.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/llm_lanes.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/llm_request_context.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/materials/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/materials/activities.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/materials/executor.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/model_defaults.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/operational_metrics.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/pipeline/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/pipeline/automatic_preparation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/pipeline/current_policy_selectors.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/pipeline/preparation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/pipeline/public_fetch_recovery.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/pipeline/workflow.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/preparation/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/preparation/workflow.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/profile/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/profile/activities.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/profile/importer.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/profile/workflow.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/profile_import.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/provider_packs.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/resume_profile.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/runtime.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/scoring/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/scoring/activities.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/scoring/eligibility_sql.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/scoring/employer_analysis.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/scoring/eval.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/scoring/material_lifecycle.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/scoring/scorer.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/source_proposals_cli.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/src/jobctrl/wizard/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/__init__.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/activity_capacity_api_fixture.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/apply_execution_fixture.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/apply_late_settlement_probe.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/apply_receipt_privacy_fixture.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/apply_skip_restart_probe.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/apply_stopped_owner_probe.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/availability_fixture.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/availability_transports.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/career_learning_fixture.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/company_briefing_fixture.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/compensation_fakes.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/conftest.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/cover_letter_pdf_probe.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/determination_fakes.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/email_approval_api_probe.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/fixtures/discovery_barcelona_acceptance.json +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/fixtures/enrichment_retry.sql +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/fixtures/hybrid_search_topk.json +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/fixtures/required_bullet_rpc_probe.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/fixtures/rescore_advice_probe.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/fixtures/rpc_boundary.json +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/fixtures/scoring_eval_cases.json +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/fixtures/shipped_v6_schema.sql +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/gmail_feedback_rpc_fixture.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/helpers/apply_batch_outcome_native.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/helpers/apply_custody_native.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/helpers/apply_execution_native.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/helpers/apply_execution_ports.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/helpers/apply_execution_retry_native.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/helpers/apply_execution_temporal.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/helpers/apply_session_fence_native.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/legacy_evidence_fixture.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/live_browser_helpers.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/outreach_rpc_harness.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/page_fakes.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/politeness_helpers.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/projection_cross_runtime_fixture.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/rpc_contract_probe.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/smart_posting_fakes.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/source_apply_scope_probe.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/source_email_scope_probe.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/source_scope_child_evidence.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/temporal_env.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_accepted_docx_export.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_accepted_export_api.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_actions.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_activity_apply.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_activity_connection_lifetime.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_activity_control_executor_capacity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_activity_cover.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_activity_enrich.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_activity_executor_generation_capacity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_activity_profile_import.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_activity_runtime_telemetry.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_activity_score.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_activity_tailor.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_agent_runtime_cleanup_privacy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_agent_runtime_codex.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_agent_runtime_pool.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_analysis_determinations.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_analysis_retry_boundaries.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_analyze_job_use_case.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_antigravity_adapter.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_application_url_authority.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_approval_vocabulary.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_batch_crashes.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_batch_limits.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_browser_ownership.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_chrome_dry_run_guard.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_chrome_endpoint_ownership.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_crash_custody.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_dashboard_isolation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_eligibility_checker.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_endpoint_consumers.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_execution.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_launcher_ownership.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_log_artifact_registration.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_native_custody.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_origin_policy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_prompt_builder.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_queue_selectors.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_regressions.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_run_aggregate.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_runs_projection_from_events.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_runs_table_dropped.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_saga.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_source_census_scope.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_source_lifetime.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_stopped_owner_recovery.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_tools_mcp_server.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_apply_use_cases.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_approved_material_recovery_ownership.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_archived_smart_posting_temporal.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_artifact_determinations.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_ats_adapters.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_audit_projection_parity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_auto_apply_reconciler.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_automatic_compensation_refresh.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_automatic_material_decline.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_automatic_preparation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_automatic_preparation_overlap.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_automatic_preparation_temporal_qa.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_autonomous_agent_port.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_availability_model_budget.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_baseline_accomplishment_retention.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_binding_repair_feedback.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_browser_capabilities.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_browser_capabilities_rpc.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_browser_capability_cli.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_browser_port.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_browser_rate_limit_recovery.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_browser_request_headers.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_browser_ua_propagation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_bullet_provenance.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_bundled_runtime.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_cancellation_audit.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_capsolver_client.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_captured_posting_recovery.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_career_learning.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_claim_grounding.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_claim_review_response.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_claude_code_cli_adapter.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_claude_terminal_failure.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_codex_adapter_status.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_codex_home_isolation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_codex_runtime_cleanup_privacy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_codex_runtime_storage.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_codex_turn.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_codex_workspace.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_company_briefings.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_audit_contract.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_benchmark_materialization.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_benchmark_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_benchmarks.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_classification_parallelism.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_gateway_routing.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_official_data.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_refresh_cli.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_refresh_state.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_refresh_temporal.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_source_outcomes.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_compensation_v7_job_id.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_config_file_transactions.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_contact_aggregate.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_contact_projection_parity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_contact_provenance.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_contact_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_contact_research_activity_heartbeat.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_contact_research_e2e_fixture.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_contact_research_inference.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_contact_research_inference_temporal.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_contact_research_projection_parity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_contact_research_source_policy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_contact_research_workflow.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_content_validator.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_cover_generation_repair.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_cover_letter_opt_in.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_cover_letter_review.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_cover_requirements.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_cover_reviewed_anchors.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_coverage_audit.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_crawl_politeness_config.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_criteria_provider.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_dashboard_projection.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_database_backup.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_database_initialization_race.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_default_resume_fit.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_dependabot_policy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_detail_page_fetcher.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_detail_page_frames.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_detail_projection_job_id_contract.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_digest_canonical_cli.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_digest_cli.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_digest_parity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_direct_material_attempt_fencing.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_enrichment_handoff.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_execution_identity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_execution_lineage.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_execution_reconciliation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_execution_result_plan.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_family_result_budget.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_identity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_limits.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_preparation_orchestration.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_production_wiring.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_result_budget.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_scheduler_pr4.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_search_unit_identity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_search_units.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_discovery_transaction_lifecycle.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_distribution_smoke_model.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_doctor_diagnostics.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_doctor_gmail_mcp.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_doctor_langfuse.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_doctor_llm_budget.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_doctor_playwright.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_doctor_temporal.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_domain_event_parity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_domain_events.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_domain_types.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_due_follow_up_projection_parity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_employer_analysis_ensemble.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_employer_analysis_leg_config.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_employer_analysis_model.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_employer_analysis_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_aggregate.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_detail_staleness.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_events_pr3.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_extractors.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_lease_concurrency.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_politeness_gate.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_quarantine_gating.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_queue_selectors.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_retry.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_snapshot_pr3.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_use_cases.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_enrichment_visible_capture.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_event_publication.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_event_type_migration.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_event_watermark.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_evidence_interview_value_objects.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_exact_v10_schema.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_exact_v11_schema.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_exact_v12_schema.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_exact_v14_schema.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_exact_v7_apply_acquire_job_identity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_exact_v7_schema.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_exact_v7_selector_job_identity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_exact_v7_state_reset.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_exact_v8_schema.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_exact_v9_schema.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_feedback_signal_reader.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_fetch_failure_projection.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_fetch_surface_enforcement.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gateway_http_client.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gemini_schema.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gmail_connector.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gmail_feedback_client_contract.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gmail_feedback_privacy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gmail_feedback_v10_anchors.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gmail_mcp_config.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gmail_token_atomic.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gmail_token_windows_acl.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_gmail_windows_acl_contract.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_in_process_bus.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_interpretation_citable_fields.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_interview_catalog.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_interview_catalog_packaging.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_interview_determinations.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_interview_persistence_v12.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_interview_prep_generation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_job_aggregate.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_job_application_locators.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_job_detail_authority.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_job_list_projection.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_job_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_job_url_import_status.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_job_url_import_workflow.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_jobspy_gateway_boundary.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_jobstreaming_source_result_budget.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_jsonrpc_handlers.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_jsonrpc_server.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_keychain_credentials.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_learning_recommendations.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_legacy_evidence_preservation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_legacy_evidence_recovery.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_legacy_to_v10_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_legacy_to_v11_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_legacy_to_v12_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_legacy_to_v9_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_levels_fyi_public.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_linkedin_apply_resolver.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_linkedin_authenticated_enrichment_retry.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_linkedin_guest_dialog.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_live_worker_smoke_provider.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_llm_analysis_synthesizer.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_llm_client.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_llm_defaults.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_llm_no_credential_leakage.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_llm_port.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_llm_provider_routing.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_llm_spans.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_llm_spend_budget.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_locale_variants.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_locale_variants_integration.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_location_normalization.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_manual_capture_workflow.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_market_compensation_estimator.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_market_compensation_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_material_activity_recovery.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_material_batch_attempt_fencing.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_material_candidate_identity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_material_context_requirements.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_material_evidence_selection.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_material_executor_prerequisites.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_material_override_retention.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_material_render_publication.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_material_review_history.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_materials_adversarial.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_materials_aggregate.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_materials_quality.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_materials_queue_selectors.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_materials_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_materials_repository_v7.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_materials_review_constraints.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_materials_unit_of_work.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_materials_use_cases.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_model_catalog.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_native_apply_readiness.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_numeric_literal_formats.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_offer_outreach.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_operational_metrics.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_otel_init.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_outreach_draft_gates.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_outreach_follow_up_derivation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_outreach_no_auto_send.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_outreach_no_send_transport.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_outreach_projection_parity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_outreach_repository_v7.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_outreach_thread_aggregate.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_p1b_error_inversion.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_packaged_browser_contract.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_parallel_letter_reviews.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_parallel_resume_reviews.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_pdf_renderer_ports.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_pipeline_observability.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_pipeline_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_pipeline_status_cli.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_pipeline_step_events.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_pipeline_step_lifecycle_emission.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_pipeline_step_projection.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_pipeline_use_cases.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_politeness_gateway.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_politeness_ports.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_posted_compensation_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_posted_compensation_source_fence.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_posting_availability_rereview.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_posting_availability_review.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_posting_source_proposals.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_posting_source_selection.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_posting_sources.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_preflight.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_preparation_availability_cache.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_preparation_capture_reuse.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_preparation_job_reader.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_preparation_manual_decline.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_preparation_outcome_audit.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_preparation_score_cancellation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_preparation_score_material_block.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_process_ownership_census.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_process_ownership_graceful.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_process_ownership_scope_fence.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_process_ownership_temporal.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_profile_aggregate.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_profile_determinations.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_profile_import.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_profile_snapshot.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_profile_use_cases.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_projection_builder.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_provider_availability_recovery.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_provider_packs.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_provider_transient_recovery.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_public_destination_http.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_public_fetch_recovery.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_python_package_attribution.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_release_check.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_release_workflow_topology.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_remaining_determinations.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_render_resume_pdf_handler.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_repeat_application_prevention.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_repository_construction.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_required_bullet_coaching.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_required_skill_categories.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_requirement_fit_resolution.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_requirement_led_tailoring.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_resume_assembler.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_resume_html_migration.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_resume_polish_policy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_resume_review_response_bounds.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_rpc_cancel_run.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_rpc_contract_boundary.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_rpc_handlers_apply_workflow.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_rpc_learning_recommendations.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_rpc_otel.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_rpc_server_workflow_mode.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_runtime_identity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_saved_default_model.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_saved_edit_determinations.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_saved_posting_availability.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_saved_posting_availability_runtime.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_saved_search_read_failure.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_schema_v7_packaging.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_activity_recovery.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_aggregate.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_atomic_publication.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_batch_ownership.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_eligibility_stage_state.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_interview_binding.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_profile_impact.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_queue_selectors.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_saved_search_preflight.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_source_fence.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_staleness_publication.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_score_use_cases.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_scorer.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_scoring_determinations.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_scoring_eval.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_scoring_eval_feedback.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_scoring_policy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_screening_answers.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_screening_answers_integration.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_search_unit_concurrency_assessment.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_selected_apply_url_refresh.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_selected_board_wiring.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_semantic_determinations.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_semantic_storage.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_setup_probes.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_setup_synthesis_auth.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_single_provider_analysis.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_smart_posting_intake.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_smartextract_discovery.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_smartextract_resilience.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_source_quality_projection_pr4.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_source_registry.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_source_spans.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_sqlite_learning_recommendations.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_sqlite_profile_repository.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_stage_runner_thread_safety.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_stage_state_machine.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_state_dashboard.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_state_legacy_parity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_state_machine_parity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_strict_schema.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_tailor_judge_selection.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_tailor_provenance_integration.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_tailor_retailor.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_tailor_voice_audit_integration.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_tailoring_artifact_boundary.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_tailoring_ownership_race.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_tailoring_policy_revisions.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_tailoring_prompt_projection.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_target_search_preferences.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_task_queue_observation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_temporal_client.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_temporal_concurrency.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_temporal_env.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_temporal_registry.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_temporal_worker.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_terminal_material_rejection.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v10_to_v11_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v12_activation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v14_v15_inplace.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v15_candidate_execution.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v15_lifecycle_revisions.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_apply_run_projections.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_artifact_list_projections.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_candidate.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_contact_projections_copy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_copy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_dashboard_projections.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_duplicate_links.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_event_copy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_evidence_usage_projections.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_feedback_copy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_job_detail_projections.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_job_list_projections.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_pipeline_step_projections_copy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_plan.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_population_steps.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_preflight.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_quiescence.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_root_copy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_score_keywords.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_verify.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_work_items_copy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v7_workflow_run_projections_copy.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v6_to_v8_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v7_cover_runtime.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v7_dashboard_outcome_conversion.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v7_dashboard_projection_rows.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v7_evidence_usage_projection_rows.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v7_job_list_projection_rows.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v7_materials_selectors.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v7_projection_builder_event_identity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v7_score_runtime.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v7_tailor_runtime.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v7_to_v8_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v8_to_v9_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_v9_to_v10_execute.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_voice_adapter.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_voice_payload.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workday_discovery.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workday_gateway_routing.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_worker_cooperative_shutdown.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_worker_heartbeat_loop.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_worker_reconciler.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_worker_trace_context.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_apply.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_control_capacity.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_discovery.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_durability_probe.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_finalize.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_heavy_rpc_conversions.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_id_overlap.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_job_pipeline.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_job_preparation.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_run_context.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_runs_projection_from_events.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_start_metadata.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workflow_starter_cache.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/test_workspace_migration.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/v6_feedback_fixture.py +0 -0
- {jobctrl-0.4.0 → jobctrl-0.4.1}/tests/v6_migration_fixture.py +0 -0
- {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.
|
|
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.
|
|
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.
|
|
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.
|
|
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":
|
|
191
|
+
"hours_old": None,
|
|
192
192
|
"country_indeed": "usa",
|
|
193
193
|
},
|
|
194
194
|
"location": {
|
|
@@ -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,
|
|
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
|
-
|
|
290
|
-
|
|
291
|
-
|
|
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
|
-
|
|
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
|
|
473
|
-
#
|
|
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
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
2148
|
+
"errors": len(failed_source_ids),
|
|
2093
2149
|
"failed_queries": len(failed_units),
|
|
2094
|
-
"failed_source_ids":
|
|
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):
|