lixiaowww commited on
Commit
2c859ea
·
verified ·
1 Parent(s): ce7686b

Sync from GitHub via hub-sync

Browse files
config.yaml CHANGED
@@ -60,6 +60,24 @@ job_radar:
60
  senior_retrain_cap_months: 24
61
  min_stratified_responses: 5
62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  # ---- job market calibration (BLS to KB displacement risk overlay) ----
64
  job_market:
65
  enabled: true
 
60
  senior_retrain_cap_months: 24
61
  min_stratified_responses: 5
62
 
63
+ # ---- job query calibration agent (Phase 9) ----
64
+ job_query_agent:
65
+ enabled: true
66
+ traces_path: data/query_agent_traces.jsonl
67
+ discover:
68
+ include_core: true
69
+ include_seed: true
70
+ seed_path: data/query_seed.json
71
+ include_feedback_titles: true
72
+ feedback_min_responses: 1
73
+ include_variants: false
74
+ max_queries_per_run: 200
75
+ evaluate:
76
+ fail_on_weak_core: true
77
+ review:
78
+ require_review: true
79
+ pending_dir: pending/job_calibration
80
+
81
  # ---- job market calibration (BLS to KB displacement risk overlay) ----
82
  job_market:
83
  enabled: true
data/jobs_kb.json CHANGED
@@ -381,6 +381,18 @@
381
  "id": "tech_software_eng",
382
  "title": "Software Engineer",
383
  "title_zh": "软件工程师",
 
 
 
 
 
 
 
 
 
 
 
 
384
  "industry": "Tech",
385
  "category": "transforming",
386
  "description": "Creates, tests, and maintains software applications. Transitioning from manual coding to leveraging AI agents for code generation, focusing on architecture and security.",
@@ -440,6 +452,213 @@
440
  }
441
  ]
442
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
443
  {
444
  "id": "tech_prompt_eng",
445
  "title": "Prompt Engineer & LLM Specialist",
 
381
  "id": "tech_software_eng",
382
  "title": "Software Engineer",
383
  "title_zh": "软件工程师",
384
+ "search_aliases": [
385
+ "software developer",
386
+ "software development",
387
+ "programmer",
388
+ "coder",
389
+ "full stack developer",
390
+ "backend developer",
391
+ "frontend developer",
392
+ "程序员",
393
+ "软件开发",
394
+ "开发工程师"
395
+ ],
396
  "industry": "Tech",
397
  "category": "transforming",
398
  "description": "Creates, tests, and maintains software applications. Transitioning from manual coding to leveraging AI agents for code generation, focusing on architecture and security.",
 
452
  }
453
  ]
454
  },
455
+ {
456
+ "id": "tech_product_manager",
457
+ "title": "Software Product Manager",
458
+ "title_zh": "软件产品经理",
459
+ "search_aliases": [
460
+ "product manager",
461
+ "产品经理",
462
+ "technical product manager",
463
+ "PM",
464
+ "product owner"
465
+ ],
466
+ "industry": "Tech",
467
+ "category": "transforming",
468
+ "description": "Owns product vision, roadmap, and prioritization; synthesizes user research, market signals, and engineering constraints. AI copilots accelerate specs, analytics, and prototyping, but accountability for trade-offs and cross-functional alignment remains human.",
469
+ "description_zh": "负责产品愿景、路线图与优先级;综合用户研究、市场信号与工程约束做决策。AI 可加速需求文档、数据分析与原型,但跨团队权衡与最终责任仍依赖人类产品经理。",
470
+ "sensitivity": {
471
+ "augmentation_ratio": 0.75,
472
+ "demand_elasticity": 0.7,
473
+ "oring_leverage": 0.55,
474
+ "skill_distance": 0.45,
475
+ "diffusion_years": -0.3,
476
+ "absorbing_sector": 0.4,
477
+ "productivity_capture": 0.65,
478
+ "task_frontier_open": 0.75
479
+ },
480
+ "base_demand_trend": 0.07,
481
+ "displacement_risk": 0.22,
482
+ "required_skills": [
483
+ "Product Roadmapping",
484
+ "User Research Synthesis",
485
+ "Stakeholder Alignment",
486
+ "AI-Assisted Product Analytics"
487
+ ],
488
+ "skill_vector": [
489
+ 0.75,
490
+ 0.55,
491
+ 0.7,
492
+ 0.6,
493
+ 0.5,
494
+ 0.8,
495
+ 0.6,
496
+ 0.55
497
+ ],
498
+ "emergence_year": null,
499
+ "sources": [
500
+ "BLS: Management Occupations — Computer and Information Systems Managers (product-adjacent)",
501
+ "O*NET 11-3021.00 - Computer and Information Systems Managers",
502
+ "McKinsey: The future of product management in the age of AI"
503
+ ],
504
+ "transition_targets": [
505
+ {
506
+ "target_id": "tech_prompt_eng",
507
+ "skill_bridge": "Develop proficiency in Prompt Design Patterns, RAG Pipeline Configuration to transition into the Prompt Engineer & LLM Specialist role.",
508
+ "retrain_months": 5,
509
+ "salary_delta": 0.12
510
+ },
511
+ {
512
+ "target_id": "edu_ai_learning_guide",
513
+ "skill_bridge": "Develop proficiency in Instructional System Design (ISD), Adaptive Learning Algorithms to transition into the AI Learning Experience Designer role.",
514
+ "retrain_months": 6,
515
+ "salary_delta": 0.1
516
+ },
517
+ {
518
+ "target_id": "tech_ai_infra_eng",
519
+ "skill_bridge": "Develop proficiency in Kubernetes (K8s) Orchestration, GPU Clustering (NCCL) to transition into the AI Infrastructure Architect role.",
520
+ "retrain_months": 9,
521
+ "salary_delta": 0.15
522
+ }
523
+ ]
524
+ },
525
+ {
526
+ "id": "tech_data_scientist",
527
+ "title": "Data Scientist",
528
+ "title_zh": "数据科学家",
529
+ "search_aliases": [
530
+ "data science",
531
+ "machine learning scientist",
532
+ "数据科学"
533
+ ],
534
+ "industry": "Tech",
535
+ "category": "transforming",
536
+ "description": "Builds statistical and machine-learning models to extract insight from data; increasingly augmented by AutoML and LLM-assisted feature engineering while human judgment remains critical for problem framing and causal interpretation.",
537
+ "description_zh": "构建统计与机器学习模型从数据中提取洞察;AutoML 与大模型辅助特征工程日益普及,但问题定义与因果解释仍依赖人类判断。",
538
+ "sensitivity": {
539
+ "augmentation_ratio": 0.8,
540
+ "demand_elasticity": 0.85,
541
+ "oring_leverage": 0.6,
542
+ "skill_distance": 0.55,
543
+ "diffusion_years": -0.4,
544
+ "absorbing_sector": 0.35,
545
+ "productivity_capture": 0.75,
546
+ "task_frontier_open": 0.85
547
+ },
548
+ "base_demand_trend": 0.1,
549
+ "displacement_risk": 0.18,
550
+ "required_skills": [
551
+ "Python & ML Frameworks",
552
+ "Experiment Design",
553
+ "Causal Inference",
554
+ "LLM Feature Pipelines"
555
+ ],
556
+ "skill_vector": [
557
+ 0.85,
558
+ 0.8,
559
+ 0.65,
560
+ 0.55,
561
+ 0.35,
562
+ 0.45,
563
+ 0.75,
564
+ 0.8
565
+ ],
566
+ "emergence_year": null,
567
+ "sources": [
568
+ "BLS: Data Scientists",
569
+ "O*NET 15-2051.00 - Data Scientists",
570
+ "LinkedIn Jobs on the Rise: Data Science roles"
571
+ ],
572
+ "transition_targets": [
573
+ {
574
+ "target_id": "tech_prompt_eng",
575
+ "skill_bridge": "Develop proficiency in Prompt Design Patterns, Vector Database Operations to transition into the Prompt Engineer & LLM Specialist role.",
576
+ "retrain_months": 4,
577
+ "salary_delta": 0.14
578
+ },
579
+ {
580
+ "target_id": "tech_ai_infra_eng",
581
+ "skill_bridge": "Develop proficiency in Kubernetes (K8s) Orchestration, Distributed Storage Systems to transition into the AI Infrastructure Architect role.",
582
+ "retrain_months": 7,
583
+ "salary_delta": 0.12
584
+ },
585
+ {
586
+ "target_id": "fin_risk_manager",
587
+ "skill_bridge": "Develop proficiency in VaR Modeling, Stress Testing Frameworks to transition into the Risk Management Specialist role.",
588
+ "retrain_months": 8,
589
+ "salary_delta": 0.1
590
+ }
591
+ ]
592
+ },
593
+ {
594
+ "id": "tech_project_manager",
595
+ "title": "Technical Project Manager",
596
+ "title_zh": "技术项目经理",
597
+ "search_aliases": [
598
+ "project manager",
599
+ "项目经理",
600
+ "TPM",
601
+ "program manager"
602
+ ],
603
+ "industry": "Tech",
604
+ "category": "transforming",
605
+ "description": "Coordinates cross-functional engineering delivery, timelines, and risk; AI scheduling and status summarization tools reduce admin load but stakeholder negotiation and ambiguity resolution stay human-centric.",
606
+ "description_zh": "协调跨职能研发交付、时间表与风险;AI 排期与状态摘要工具减轻事务性负担,但利益相关方博弈与模糊情境决策仍依赖人类。",
607
+ "sensitivity": {
608
+ "augmentation_ratio": 0.65,
609
+ "demand_elasticity": 0.6,
610
+ "oring_leverage": 0.5,
611
+ "skill_distance": 0.4,
612
+ "diffusion_years": -0.2,
613
+ "absorbing_sector": 0.45,
614
+ "productivity_capture": 0.55,
615
+ "task_frontier_open": 0.6
616
+ },
617
+ "base_demand_trend": 0.05,
618
+ "displacement_risk": 0.28,
619
+ "required_skills": [
620
+ "Agile Delivery",
621
+ "Risk & Dependency Management",
622
+ "Technical Communication",
623
+ "AI-Assisted Planning Tools"
624
+ ],
625
+ "skill_vector": [
626
+ 0.65,
627
+ 0.5,
628
+ 0.6,
629
+ 0.55,
630
+ 0.55,
631
+ 0.75,
632
+ 0.55,
633
+ 0.5
634
+ ],
635
+ "emergence_year": null,
636
+ "sources": [
637
+ "BLS: Project Management Specialists",
638
+ "O*NET 13-1082.00 - Project Management Specialists",
639
+ "PMI: Pulse of the Profession"
640
+ ],
641
+ "transition_targets": [
642
+ {
643
+ "target_id": "tech_product_manager",
644
+ "skill_bridge": "Develop proficiency in Product Roadmapping, User Research Synthesis to transition into the Software Product Manager role.",
645
+ "retrain_months": 6,
646
+ "salary_delta": 0.11
647
+ },
648
+ {
649
+ "target_id": "tech_software_eng",
650
+ "skill_bridge": "Develop proficiency in System Architecture, API Design to transition into the Software Engineer role.",
651
+ "retrain_months": 8,
652
+ "salary_delta": 0.13
653
+ },
654
+ {
655
+ "target_id": "log_supply_chain_analyst",
656
+ "skill_bridge": "Develop proficiency in Demand Forecasting, Inventory Optimization to transition into the Supply Chain Analyst role.",
657
+ "retrain_months": 7,
658
+ "salary_delta": 0.08
659
+ }
660
+ ]
661
+ },
662
  {
663
  "id": "tech_prompt_eng",
664
  "title": "Prompt Engineer & LLM Specialist",
data/predictions_live.jsonl CHANGED
@@ -1,16 +1,20 @@
1
- {"rationale":"The papers on AI-driven optimization, diffusion models, and neural networks suggest a growing need for professionals with expertise in AI and data analysis. According to the job-evolution prior, high augmentation ratios are associated with higher net job multipliers, which supports this prediction.","confidence":0.6,"resolution_date":"2028-06-30","sources":["https://www.bls.gov/","https://arxiv.org/abs/2606.23689v1"],"status":"open","judged_rationale":"","brier":null,"id":"2384fe381c30a311","statement":"By 2028-Q2, the number of jobs in the 'data scientist' category will increase by at least 15% compared to 2026-Q2, driven by the growing demand for AI-related skills.","category":"labor","horizon":"2028-Q2","resolution_criteria":"Comparison of the number of data scientist jobs in 2026-Q2 and 2028-Q2, using data from the Bureau of Labor Statistics (BLS) or equivalent sources.","created_at":"2026-06-23T19:36:24.629511","outcome":null,"resolved_at":null}
2
- {"rationale":"The papers on diffusion models, neural networks, and AI-driven optimization suggest a growing importance of digital technologies in various industries. According to the job-evolution prior, high demand elasticity is associated with higher net job multipliers, which supports this prediction.","confidence":0.55,"resolution_date":"2030-12-31","sources":["https://www.bea.gov/","https://arxiv.org/abs/2606.23670v1"],"status":"open","judged_rationale":"","brier":null,"id":"081dfcca5494434d","statement":"The share of GDP attributed to the 'information' sector will increase by at least 2% by 2030-Q4, compared to 2026-Q4, driven by the growing adoption of AI and digital technologies.","category":"macro","horizon":"2030-Q4","resolution_criteria":"Comparison of the share of GDP attributed to the 'information' sector in 2026-Q4 and 2030-Q4, using data from the Bureau of Economic Analysis (BEA) or equivalent sources.","created_at":"2026-06-23T19:36:24.629754","outcome":null,"resolved_at":null}
3
- {"rationale":"The papers on multimodal content generation, vision-language-action models, and text-to-image reward modeling suggest a growing interest in multimodal capabilities. According to the fresh evidence ingested in this cycle, there is a growing trend towards more sophisticated AI applications.","confidence":0.65,"resolution_date":"2027-03-31","sources":["https://arxiv.org/abs/2606.23643v1","https://arxiv.org/abs/2606.23617v1"],"status":"open","judged_rationale":"","brier":null,"id":"96013f86014aab86","statement":"By 2027-Q1, at least 20% of large language models (LLMs) will incorporate multimodal capabilities, such as text-to-image or vision-language-action, driven by the growing demand for more sophisticated AI applications.","category":"compute","horizon":"2027-Q1","resolution_criteria":"Survey of large language models (LLMs) and their capabilities, using data from industry reports or equivalent sources.","created_at":"2026-06-23T19:36:24.629865","outcome":null,"resolved_at":null}
4
- {"rationale":"The papers on AI-driven optimization of quality of recovery, AI-assisted decision-making, and neural networks suggest a growing interest in AI applications in healthcare. According to the job-evolution prior, high skill distances are associated with longer lags in job transitions, which supports this prediction.","confidence":0.5,"resolution_date":"2029-09-30","sources":["https://www.bls.gov/","https://arxiv.org/abs/2606.23631v1"],"status":"open","judged_rationale":"","brier":null,"id":"c911767e3dd8d6d4","statement":"By 2029-Q3, the number of jobs in the 'healthcare' sector that involve AI-assisted decision-making will increase by at least 10% compared to 2026-Q3, driven by the growing adoption of AI in healthcare.","category":"labor","horizon":"2029-Q3","resolution_criteria":"Comparison of the number of jobs in the 'healthcare' sector that involve AI-assisted decision-making in 2026-Q3 and 2029-Q3, using data from the Bureau of Labor Statistics (BLS) or equivalent sources.","created_at":"2026-06-23T19:36:24.629940","outcome":null,"resolved_at":null}
5
- {"rationale":"This prediction is based on the recent investments and community support announcements by Google, such as the $1.5 billion investment in Alabama and the new community investments in Virginia. These efforts are likely to create new job opportunities in the AI and data science sector. I have chosen to focus on job postings rather than employment numbers to avoid the wrong_metric failure mode, as job postings can provide a more timely and sensitive indicator of labor market trends.","confidence":0.7,"resolution_date":"2027-01-15","sources":["https://www.bls.gov/jlt/","https://blog.google/innovation-and-ai/infrastructure-and-cloud/global-network/alabama-investment-june-2026/"],"status":"open","judged_rationale":"","brier":null,"id":"22b780e78d985ddc","statement":"The number of job postings in the AI and data science sector will increase by at least 15% by the end of 2026-Q4, compared to the same period in 2025.","category":"labor","horizon":"2026-Q4","resolution_criteria":"The statement will be judged true or false based on the data from the Bureau of Labor Statistics (BLS) on job openings and labor turnover, specifically the Job Openings and Labor Turnover Survey (JOLTS).","created_at":"2026-06-24T01:15:27.651702","outcome":null,"resolved_at":null}
6
- {"rationale":"This prediction is based on the recent announcements from Google, such as the launch of Gemini Omni and Gemini 3.5, which are likely to improve the efficiency and reduce the costs of cloud computing services. I have chosen to focus on the average price of cloud computing services rather than the overall market size to avoid the wrong_granularity failure mode, as prices can provide a more nuanced indicator of market trends.","confidence":0.6,"resolution_date":"2027-07-15","sources":["https://cloud.google.com/","https://blog.google/innovation-and-ai/models-and-research/gemini-models/gemini-omni-3-5-videos/"],"status":"open","judged_rationale":"","brier":null,"id":"7efc75b2f6642e67","statement":"The average price of cloud computing services will decrease by at least 5% by the end of 2027-Q2, driven by increased competition and improvements in AI-powered infrastructure management.","category":"compute","horizon":"2027-Q2","resolution_criteria":"The statement will be judged true or false based on the data from the cloud computing service providers, such as Amazon Web Services (AWS), Microsoft Azure, and Google Cloud Platform (GCP), as well as market research reports from firms like Gartner or Forrester.","created_at":"2026-06-24T01:15:27.651950","outcome":null,"resolved_at":null}
7
- {"rationale":"This prediction is based on the recent trends in AI adoption, such as the use of conversational AI systems like AMIE, which can help SMEs improve their customer service and marketing capabilities. I have chosen to focus on SMEs rather than large enterprises to avoid the wrong_segment failure mode, as SMEs are more likely to benefit from the adoption of AI-powered tools.","confidence":0.65,"resolution_date":"2027-04-15","sources":["https://blog.google/innovation-and-ai/models-and-research/google-research/amie-for-disease-management-in-nature/","https://www.nsba.com/"],"status":"open","judged_rationale":"","brier":null,"id":"60f3fe50468e8e5a","statement":"The number of small and medium-sized enterprises (SMEs) adopting AI-powered tools for customer service and marketing will increase by at least 20% by the end of 2027-Q1, compared to the same period in 2026.","category":"adoption","horizon":"2027-Q1","resolution_criteria":"The statement will be judged true or false based on the data from market research reports and surveys, such as those conducted by the National Small Business Association (NSBA) or the Small Business Administration (SBA).","created_at":"2026-06-24T01:15:27.652044","outcome":null,"resolved_at":null}
8
- {"rationale":"This prediction is based on the recent announcements from governments and private sector companies, such as the Federal Reserve's request for comment on a proposal to require certain payment stablecoin issuers to maintain an effective customer identification program. I have chosen to focus on the total investment in AI research and development rather than specific areas of investment to avoid the wrong_metric failure mode, as total investment can provide a broader indicator of trend.","confidence":0.75,"resolution_date":"2028-01-15","sources":["https://www.federalreserve.gov/newsevents/pressreleases/bcreg20260618a.htm","https://www.nsf.gov/"],"status":"open","judged_rationale":"","brier":null,"id":"67f3daccc3d3429b","statement":"The total investment in AI research and development will increase by at least 10% by the end of 2027, compared to the same period in 2026, driven by government initiatives and private sector investments.","category":"capital","horizon":"2027","resolution_criteria":"The statement will be judged true or false based on the data from government agencies, such as the National Science Foundation (NSF), and private sector research firms, such as IDC or Gartner.","created_at":"2026-06-24T01:15:27.652114","outcome":null,"resolved_at":null}
9
- {"rationale":"This prediction is grounded in the theory of augmentation vs automation, where new work emerges in areas that complement AI technology. The recent investments and community support announcements by Google in Alabama and Virginia suggest a growing demand for AI talent. To avoid the wrong_granularity failure mode, I have chosen to focus on the specific occupation of AI and machine learning engineers rather than overall developer employment.","confidence":0.7,"resolution_date":"2027-12-31","sources":["https://www.bls.gov/","https://blog.google/innovation-and-ai/infrastructure-and-cloud/global-network/alabama-investment-june-2026/"],"status":"open","judged_rationale":"","brier":null,"id":"344f076d73d5cbf9","statement":"The number of job postings for AI and machine learning engineers in the United States will increase by at least 15% year-over-year by the end of 2027","category":"labor","horizon":"2027","resolution_criteria":"The statement will be deemed true if the year-over-year growth in job postings for AI and machine learning engineers exceeds 15% according to data from the Bureau of Labor Statistics or a similar reputable source","created_at":"2026-06-24T01:20:01.026916","outcome":null,"resolved_at":null}
10
- {"rationale":"This prediction is based on the concept of comparative advantage, where companies that adopt AI technologies are likely to experience increased productivity and competitiveness, leading to higher valuations. The recent announcements by Google about their AI research and investments provide evidence of the growing importance of AI adoption in the business world. To avoid the wrong_attribution failure mode, I have controlled for the overall impact of macroeconomic factors by focusing on the relative performance of AI-adopting companies within the S&P 500 index.","confidence":0.6,"resolution_date":"2028-12-31","sources":["https://finance.yahoo.com/","https://blog.google/innovation-and-ai/models-and-research/gemini-models/gemini-omni-3-5-videos/"],"status":"open","judged_rationale":"","brier":null,"id":"53c9a9c7dd85221e","statement":"The price-to-earnings ratio of companies in the S&P 500 index that have adopted AI technologies will be at least 10% higher than those that have not adopted AI by the end of 2028","category":"capital","horizon":"2028","resolution_criteria":"The statement will be deemed true if the average price-to-earnings ratio of AI-adopting companies in the S&P 500 index exceeds that of non-AI-adopting companies by at least 10% according to data from Yahoo Finance or a similar reputable source","created_at":"2026-06-24T01:20:01.027170","outcome":null,"resolved_at":null}
11
- {"rationale":"This prediction is based on the concept of induced demand, where the growing availability and accessibility of AI technologies leads to increased demand for education and training in these areas. The recent announcements by Google about their AI research and investments, as well as the growing interest in AI-related topics, provide evidence of the growing demand for AI education. To avoid the wrong_metric failure mode, I have chosen to focus on the specific metric of enrollment numbers in online courses rather than overall interest or engagement.","confidence":0.65,"resolution_date":"2027-12-31","sources":["https://www.coursera.org/","https://blog.google/innovation-and-ai/technology/ai/university-waterloo-labs/"],"status":"open","judged_rationale":"","brier":null,"id":"6966c08193e3a916","statement":"The number of students enrolled in online courses related to AI and machine learning will increase by at least 20% year-over-year by the end of 2027","category":"adoption","horizon":"2027","resolution_criteria":"The statement will be deemed true if the year-over-year growth in enrollment numbers for online courses related to AI and machine learning exceeds 20% according to data from online course platforms such as Coursera or edX","created_at":"2026-06-24T01:20:01.027258","outcome":null,"resolved_at":null}
12
- {"rationale":"This prediction is based on the concept of policy response to technological change, where regulatory bodies adapt to new technologies by establishing guidelines and regulations. The recent announcements by the Federal Reserve about their plans to regulate stablecoins and other digital assets provide evidence of the growing attention to AI-powered financial instruments. To avoid the wrong_horizon failure mode, I have chosen a relatively long-term horizon to allow for the development and implementation of regulatory policies.","confidence":0.55,"resolution_date":"2028-12-31","sources":["https://www.federalreserve.gov/","https://www.federalreserve.gov/newsevents/pressreleases/bcreg20260618a.htm"],"status":"open","judged_rationale":"","brier":null,"id":"09c6211873bb0412","statement":"The Federal Reserve will establish clear guidelines for the regulation of AI-powered financial instruments by the end of 2028","category":"policy","horizon":"2028","resolution_criteria":"The statement will be deemed true if the Federal Reserve issues clear guidelines for the regulation of AI-powered financial instruments by the end of 2028 according to official Federal Reserve announcements or publications","created_at":"2026-06-24T01:20:01.027334","outcome":null,"resolved_at":null}
13
- {"rationale":"This prediction is grounded in the concept of augmentation vs automation (Autor et al.) and the job-evolution prior, which suggests a high augmentation ratio for data scientists. The increasing number of papers on AI and machine learning applications, such as those listed in the fresh evidence ingested in this cycle, supports this claim. I have chosen the occupation 'Data Scientists and Statisticians' to avoid the wrong_granularity failure mode, as it is a specific segment within the broader category of developer employment.","confidence":0.7,"resolution_date":"2028-12-31","sources":["https://www.bls.gov/"],"status":"open","judged_rationale":"","brier":null,"id":"e2e39b7dc82c9e84","statement":"The number of jobs in the 'Data Scientists and Statisticians' occupation will increase by at least 15% between 2026 and 2028, driven by the growing demand for AI and machine learning expertise.","category":"labor","horizon":"2028-Q4","resolution_criteria":"The Bureau of Labor Statistics (BLS) will report an increase of at least 15% in the number of employed data scientists and statisticians between 2026 and 2028.","created_at":"2026-06-24T09:00:13.724586","outcome":null,"resolved_at":null}
14
- {"rationale":"This prediction is based on the concept of creative destruction (Schumpeter) and the increasing availability of AI technologies, as evidenced by the papers on large language models and multimodal learning. The growing demand for efficient and accurate decision-making in large corporations supports this claim. To avoid the wrong_horizon failure mode, I have chosen a relatively short time horizon of 2027.","confidence":0.6,"resolution_date":"2027-12-31","sources":["https://www.spglobal.com/"],"status":"open","judged_rationale":"","brier":null,"id":"f7ca42ec0d210da2","statement":"By 2027, at least 20% of the top 100 companies in the S&P 500 will have implemented some form of AI-powered decision support system, such as those described in the papers on agentic models and autonomous driving.","category":"adoption","horizon":"2027-Q4","resolution_criteria":"A survey of the top 100 companies in the S&P 500 will reveal that at least 20% have implemented AI-powered decision support systems by the end of 2027.","created_at":"2026-06-24T09:00:13.724845","outcome":null,"resolved_at":null}
15
- {"rationale":"This prediction is grounded in the concept of induced demand (Jevons' paradox) and the rapidly evolving nature of computing technologies. The increasing demand for large language models and the growing availability of optimized training methods support this claim. To avoid the wrong_metric failure mode, I have chosen to focus on the average training time rather than a specific metric like compute hours or energy consumption.","confidence":0.8,"resolution_date":"2028-12-31","sources":["https://www.marketresearchfirm.com/"],"status":"open","judged_rationale":"","brier":null,"id":"84df68e1dbe33091","statement":"The average training time for large language models will decrease by at least 30% between 2026 and 2028, driven by advancements in computing hardware and software optimization techniques, such as those described in the papers on scaling laws and decentralized training.","category":"compute","horizon":"2028-Q4","resolution_criteria":"A report by a reputable industry analyst firm will document a decrease of at least 30% in the average training time for large language models between 2026 and 2028.","created_at":"2026-06-24T09:00:13.724931","outcome":null,"resolved_at":null}
16
- {"rationale":"This prediction is based on the concept of comparative advantage (Kremer) and the increasing importance of R&D in driving economic growth. The growing demand for AI and machine learning technologies, as evidenced by the papers on large language models and multimodal learning, supports this claim. To avoid the wrong_granularity failure mode, I have chosen to focus on the share of GDP allocated to R&D at the national level rather than a specific industry or sector.","confidence":0.65,"resolution_date":"2030-12-31","sources":["https://www.bea.gov/"],"status":"open","judged_rationale":"","brier":null,"id":"9361df9db0c4e103","statement":"The share of GDP allocated to research and development (R&D) in the United States will increase by at least 1.5 percentage points between 2026 and 2030, driven by the growing demand for AI and machine learning technologies.","category":"macro","horizon":"2030-Q4","resolution_criteria":"The Bureau of Economic Analysis (BEA) will report an increase of at least 1.5 percentage points in the share of GDP allocated to R&D between 2026 and 2030.","created_at":"2026-06-24T09:00:13.724999","outcome":null,"resolved_at":null}
 
 
 
 
 
1
+ {"category":"labor","id":"2384fe381c30a311","statement":"By 2028-Q2, the number of jobs in the 'data scientist' category will increase by at least 15% compared to 2026-Q2, driven by the growing demand for AI-related skills.","horizon":"2028-Q2","resolution_criteria":"Comparison of the number of data scientist jobs in 2026-Q2 and 2028-Q2, using data from the Bureau of Labor Statistics (BLS) or equivalent sources.","created_at":"2026-06-23T19:36:24.629511","outcome":null,"resolved_at":null,"rationale":"The papers on AI-driven optimization, diffusion models, and neural networks suggest a growing need for professionals with expertise in AI and data analysis. According to the job-evolution prior, high augmentation ratios are associated with higher net job multipliers, which supports this prediction.","confidence":0.6,"resolution_date":"2028-06-30","sources":["https://www.bls.gov/","https://arxiv.org/abs/2606.23689v1"],"status":"open","judged_rationale":"","brier":null}
2
+ {"category":"macro","id":"081dfcca5494434d","statement":"The share of GDP attributed to the 'information' sector will increase by at least 2% by 2030-Q4, compared to 2026-Q4, driven by the growing adoption of AI and digital technologies.","horizon":"2030-Q4","resolution_criteria":"Comparison of the share of GDP attributed to the 'information' sector in 2026-Q4 and 2030-Q4, using data from the Bureau of Economic Analysis (BEA) or equivalent sources.","created_at":"2026-06-23T19:36:24.629754","outcome":null,"resolved_at":null,"rationale":"The papers on diffusion models, neural networks, and AI-driven optimization suggest a growing importance of digital technologies in various industries. According to the job-evolution prior, high demand elasticity is associated with higher net job multipliers, which supports this prediction.","confidence":0.55,"resolution_date":"2030-12-31","sources":["https://www.bea.gov/","https://arxiv.org/abs/2606.23670v1"],"status":"open","judged_rationale":"","brier":null}
3
+ {"category":"compute","id":"96013f86014aab86","statement":"By 2027-Q1, at least 20% of large language models (LLMs) will incorporate multimodal capabilities, such as text-to-image or vision-language-action, driven by the growing demand for more sophisticated AI applications.","horizon":"2027-Q1","resolution_criteria":"Survey of large language models (LLMs) and their capabilities, using data from industry reports or equivalent sources.","created_at":"2026-06-23T19:36:24.629865","outcome":null,"resolved_at":null,"rationale":"The papers on multimodal content generation, vision-language-action models, and text-to-image reward modeling suggest a growing interest in multimodal capabilities. According to the fresh evidence ingested in this cycle, there is a growing trend towards more sophisticated AI applications.","confidence":0.65,"resolution_date":"2027-03-31","sources":["https://arxiv.org/abs/2606.23643v1","https://arxiv.org/abs/2606.23617v1"],"status":"open","judged_rationale":"","brier":null}
4
+ {"category":"labor","id":"c911767e3dd8d6d4","statement":"By 2029-Q3, the number of jobs in the 'healthcare' sector that involve AI-assisted decision-making will increase by at least 10% compared to 2026-Q3, driven by the growing adoption of AI in healthcare.","horizon":"2029-Q3","resolution_criteria":"Comparison of the number of jobs in the 'healthcare' sector that involve AI-assisted decision-making in 2026-Q3 and 2029-Q3, using data from the Bureau of Labor Statistics (BLS) or equivalent sources.","created_at":"2026-06-23T19:36:24.629940","outcome":null,"resolved_at":null,"rationale":"The papers on AI-driven optimization of quality of recovery, AI-assisted decision-making, and neural networks suggest a growing interest in AI applications in healthcare. According to the job-evolution prior, high skill distances are associated with longer lags in job transitions, which supports this prediction.","confidence":0.5,"resolution_date":"2029-09-30","sources":["https://www.bls.gov/","https://arxiv.org/abs/2606.23631v1"],"status":"open","judged_rationale":"","brier":null}
5
+ {"category":"labor","id":"22b780e78d985ddc","statement":"The number of job postings in the AI and data science sector will increase by at least 15% by the end of 2026-Q4, compared to the same period in 2025.","horizon":"2026-Q4","resolution_criteria":"The statement will be judged true or false based on the data from the Bureau of Labor Statistics (BLS) on job openings and labor turnover, specifically the Job Openings and Labor Turnover Survey (JOLTS).","created_at":"2026-06-24T01:15:27.651702","outcome":null,"resolved_at":null,"rationale":"This prediction is based on the recent investments and community support announcements by Google, such as the $1.5 billion investment in Alabama and the new community investments in Virginia. These efforts are likely to create new job opportunities in the AI and data science sector. I have chosen to focus on job postings rather than employment numbers to avoid the wrong_metric failure mode, as job postings can provide a more timely and sensitive indicator of labor market trends.","confidence":0.7,"resolution_date":"2027-01-15","sources":["https://www.bls.gov/jlt/","https://blog.google/innovation-and-ai/infrastructure-and-cloud/global-network/alabama-investment-june-2026/"],"status":"open","judged_rationale":"","brier":null}
6
+ {"category":"compute","id":"7efc75b2f6642e67","statement":"The average price of cloud computing services will decrease by at least 5% by the end of 2027-Q2, driven by increased competition and improvements in AI-powered infrastructure management.","horizon":"2027-Q2","resolution_criteria":"The statement will be judged true or false based on the data from the cloud computing service providers, such as Amazon Web Services (AWS), Microsoft Azure, and Google Cloud Platform (GCP), as well as market research reports from firms like Gartner or Forrester.","created_at":"2026-06-24T01:15:27.651950","outcome":null,"resolved_at":null,"rationale":"This prediction is based on the recent announcements from Google, such as the launch of Gemini Omni and Gemini 3.5, which are likely to improve the efficiency and reduce the costs of cloud computing services. I have chosen to focus on the average price of cloud computing services rather than the overall market size to avoid the wrong_granularity failure mode, as prices can provide a more nuanced indicator of market trends.","confidence":0.6,"resolution_date":"2027-07-15","sources":["https://cloud.google.com/","https://blog.google/innovation-and-ai/models-and-research/gemini-models/gemini-omni-3-5-videos/"],"status":"open","judged_rationale":"","brier":null}
7
+ {"category":"adoption","id":"60f3fe50468e8e5a","statement":"The number of small and medium-sized enterprises (SMEs) adopting AI-powered tools for customer service and marketing will increase by at least 20% by the end of 2027-Q1, compared to the same period in 2026.","horizon":"2027-Q1","resolution_criteria":"The statement will be judged true or false based on the data from market research reports and surveys, such as those conducted by the National Small Business Association (NSBA) or the Small Business Administration (SBA).","created_at":"2026-06-24T01:15:27.652044","outcome":null,"resolved_at":null,"rationale":"This prediction is based on the recent trends in AI adoption, such as the use of conversational AI systems like AMIE, which can help SMEs improve their customer service and marketing capabilities. I have chosen to focus on SMEs rather than large enterprises to avoid the wrong_segment failure mode, as SMEs are more likely to benefit from the adoption of AI-powered tools.","confidence":0.65,"resolution_date":"2027-04-15","sources":["https://blog.google/innovation-and-ai/models-and-research/google-research/amie-for-disease-management-in-nature/","https://www.nsba.com/"],"status":"open","judged_rationale":"","brier":null}
8
+ {"category":"capital","id":"67f3daccc3d3429b","statement":"The total investment in AI research and development will increase by at least 10% by the end of 2027, compared to the same period in 2026, driven by government initiatives and private sector investments.","horizon":"2027","resolution_criteria":"The statement will be judged true or false based on the data from government agencies, such as the National Science Foundation (NSF), and private sector research firms, such as IDC or Gartner.","created_at":"2026-06-24T01:15:27.652114","outcome":null,"resolved_at":null,"rationale":"This prediction is based on the recent announcements from governments and private sector companies, such as the Federal Reserve's request for comment on a proposal to require certain payment stablecoin issuers to maintain an effective customer identification program. I have chosen to focus on the total investment in AI research and development rather than specific areas of investment to avoid the wrong_metric failure mode, as total investment can provide a broader indicator of trend.","confidence":0.75,"resolution_date":"2028-01-15","sources":["https://www.federalreserve.gov/newsevents/pressreleases/bcreg20260618a.htm","https://www.nsf.gov/"],"status":"open","judged_rationale":"","brier":null}
9
+ {"category":"labor","id":"344f076d73d5cbf9","statement":"The number of job postings for AI and machine learning engineers in the United States will increase by at least 15% year-over-year by the end of 2027","horizon":"2027","resolution_criteria":"The statement will be deemed true if the year-over-year growth in job postings for AI and machine learning engineers exceeds 15% according to data from the Bureau of Labor Statistics or a similar reputable source","created_at":"2026-06-24T01:20:01.026916","outcome":null,"resolved_at":null,"rationale":"This prediction is grounded in the theory of augmentation vs automation, where new work emerges in areas that complement AI technology. The recent investments and community support announcements by Google in Alabama and Virginia suggest a growing demand for AI talent. To avoid the wrong_granularity failure mode, I have chosen to focus on the specific occupation of AI and machine learning engineers rather than overall developer employment.","confidence":0.7,"resolution_date":"2027-12-31","sources":["https://www.bls.gov/","https://blog.google/innovation-and-ai/infrastructure-and-cloud/global-network/alabama-investment-june-2026/"],"status":"open","judged_rationale":"","brier":null}
10
+ {"category":"capital","id":"53c9a9c7dd85221e","statement":"The price-to-earnings ratio of companies in the S&P 500 index that have adopted AI technologies will be at least 10% higher than those that have not adopted AI by the end of 2028","horizon":"2028","resolution_criteria":"The statement will be deemed true if the average price-to-earnings ratio of AI-adopting companies in the S&P 500 index exceeds that of non-AI-adopting companies by at least 10% according to data from Yahoo Finance or a similar reputable source","created_at":"2026-06-24T01:20:01.027170","outcome":null,"resolved_at":null,"rationale":"This prediction is based on the concept of comparative advantage, where companies that adopt AI technologies are likely to experience increased productivity and competitiveness, leading to higher valuations. The recent announcements by Google about their AI research and investments provide evidence of the growing importance of AI adoption in the business world. To avoid the wrong_attribution failure mode, I have controlled for the overall impact of macroeconomic factors by focusing on the relative performance of AI-adopting companies within the S&P 500 index.","confidence":0.6,"resolution_date":"2028-12-31","sources":["https://finance.yahoo.com/","https://blog.google/innovation-and-ai/models-and-research/gemini-models/gemini-omni-3-5-videos/"],"status":"open","judged_rationale":"","brier":null}
11
+ {"category":"adoption","id":"6966c08193e3a916","statement":"The number of students enrolled in online courses related to AI and machine learning will increase by at least 20% year-over-year by the end of 2027","horizon":"2027","resolution_criteria":"The statement will be deemed true if the year-over-year growth in enrollment numbers for online courses related to AI and machine learning exceeds 20% according to data from online course platforms such as Coursera or edX","created_at":"2026-06-24T01:20:01.027258","outcome":null,"resolved_at":null,"rationale":"This prediction is based on the concept of induced demand, where the growing availability and accessibility of AI technologies leads to increased demand for education and training in these areas. The recent announcements by Google about their AI research and investments, as well as the growing interest in AI-related topics, provide evidence of the growing demand for AI education. To avoid the wrong_metric failure mode, I have chosen to focus on the specific metric of enrollment numbers in online courses rather than overall interest or engagement.","confidence":0.65,"resolution_date":"2027-12-31","sources":["https://www.coursera.org/","https://blog.google/innovation-and-ai/technology/ai/university-waterloo-labs/"],"status":"open","judged_rationale":"","brier":null}
12
+ {"category":"policy","id":"09c6211873bb0412","statement":"The Federal Reserve will establish clear guidelines for the regulation of AI-powered financial instruments by the end of 2028","horizon":"2028","resolution_criteria":"The statement will be deemed true if the Federal Reserve issues clear guidelines for the regulation of AI-powered financial instruments by the end of 2028 according to official Federal Reserve announcements or publications","created_at":"2026-06-24T01:20:01.027334","outcome":null,"resolved_at":null,"rationale":"This prediction is based on the concept of policy response to technological change, where regulatory bodies adapt to new technologies by establishing guidelines and regulations. The recent announcements by the Federal Reserve about their plans to regulate stablecoins and other digital assets provide evidence of the growing attention to AI-powered financial instruments. To avoid the wrong_horizon failure mode, I have chosen a relatively long-term horizon to allow for the development and implementation of regulatory policies.","confidence":0.55,"resolution_date":"2028-12-31","sources":["https://www.federalreserve.gov/","https://www.federalreserve.gov/newsevents/pressreleases/bcreg20260618a.htm"],"status":"open","judged_rationale":"","brier":null}
13
+ {"category":"labor","id":"e2e39b7dc82c9e84","statement":"The number of jobs in the 'Data Scientists and Statisticians' occupation will increase by at least 15% between 2026 and 2028, driven by the growing demand for AI and machine learning expertise.","horizon":"2028-Q4","resolution_criteria":"The Bureau of Labor Statistics (BLS) will report an increase of at least 15% in the number of employed data scientists and statisticians between 2026 and 2028.","created_at":"2026-06-24T09:00:13.724586","outcome":null,"resolved_at":null,"rationale":"This prediction is grounded in the concept of augmentation vs automation (Autor et al.) and the job-evolution prior, which suggests a high augmentation ratio for data scientists. The increasing number of papers on AI and machine learning applications, such as those listed in the fresh evidence ingested in this cycle, supports this claim. I have chosen the occupation 'Data Scientists and Statisticians' to avoid the wrong_granularity failure mode, as it is a specific segment within the broader category of developer employment.","confidence":0.7,"resolution_date":"2028-12-31","sources":["https://www.bls.gov/"],"status":"open","judged_rationale":"","brier":null}
14
+ {"category":"adoption","id":"f7ca42ec0d210da2","statement":"By 2027, at least 20% of the top 100 companies in the S&P 500 will have implemented some form of AI-powered decision support system, such as those described in the papers on agentic models and autonomous driving.","horizon":"2027-Q4","resolution_criteria":"A survey of the top 100 companies in the S&P 500 will reveal that at least 20% have implemented AI-powered decision support systems by the end of 2027.","created_at":"2026-06-24T09:00:13.724845","outcome":null,"resolved_at":null,"rationale":"This prediction is based on the concept of creative destruction (Schumpeter) and the increasing availability of AI technologies, as evidenced by the papers on large language models and multimodal learning. The growing demand for efficient and accurate decision-making in large corporations supports this claim. To avoid the wrong_horizon failure mode, I have chosen a relatively short time horizon of 2027.","confidence":0.6,"resolution_date":"2027-12-31","sources":["https://www.spglobal.com/"],"status":"open","judged_rationale":"","brier":null}
15
+ {"category":"compute","id":"84df68e1dbe33091","statement":"The average training time for large language models will decrease by at least 30% between 2026 and 2028, driven by advancements in computing hardware and software optimization techniques, such as those described in the papers on scaling laws and decentralized training.","horizon":"2028-Q4","resolution_criteria":"A report by a reputable industry analyst firm will document a decrease of at least 30% in the average training time for large language models between 2026 and 2028.","created_at":"2026-06-24T09:00:13.724931","outcome":null,"resolved_at":null,"rationale":"This prediction is grounded in the concept of induced demand (Jevons' paradox) and the rapidly evolving nature of computing technologies. The increasing demand for large language models and the growing availability of optimized training methods support this claim. To avoid the wrong_metric failure mode, I have chosen to focus on the average training time rather than a specific metric like compute hours or energy consumption.","confidence":0.8,"resolution_date":"2028-12-31","sources":["https://www.marketresearchfirm.com/"],"status":"open","judged_rationale":"","brier":null}
16
+ {"category":"macro","id":"9361df9db0c4e103","statement":"The share of GDP allocated to research and development (R&D) in the United States will increase by at least 1.5 percentage points between 2026 and 2030, driven by the growing demand for AI and machine learning technologies.","horizon":"2030-Q4","resolution_criteria":"The Bureau of Economic Analysis (BEA) will report an increase of at least 1.5 percentage points in the share of GDP allocated to R&D between 2026 and 2030.","created_at":"2026-06-24T09:00:13.724999","outcome":null,"resolved_at":null,"rationale":"This prediction is based on the concept of comparative advantage (Kremer) and the increasing importance of R&D in driving economic growth. The growing demand for AI and machine learning technologies, as evidenced by the papers on large language models and multimodal learning, supports this claim. To avoid the wrong_granularity failure mode, I have chosen to focus on the share of GDP allocated to R&D at the national level rather than a specific industry or sector.","confidence":0.65,"resolution_date":"2030-12-31","sources":["https://www.bea.gov/"],"status":"open","judged_rationale":"","brier":null}
17
+ {"category":"labor","id":"ee22977eae648df8","statement":"By 2028-Q2, the percentage of job postings in the US that require AI-related skills will exceed 25%.","horizon":"2028-Q2","resolution_criteria":"According to data from the Bureau of Labor Statistics (BLS) and online job platforms such as Indeed or LinkedIn, the percentage of job postings requiring AI-related skills will be calculated and compared to the 25% threshold.","created_at":"2026-06-24T13:35:12.146504","outcome":null,"resolved_at":null,"rationale":"This prediction is based on the observed trend of increasing demand for AI-related skills in the job market, which is driven by the growing adoption of AI technologies across various industries. The papers on AI-powered AAC interfaces, Grad Detect, and UniDrive demonstrate the expanding applications of AI, supporting this trend. By focusing on job postings, this prediction avoids the wrong_granularity failure mode by using a specific metric (percentage of job postings) rather than aggregate employment numbers.","confidence":0.6,"resolution_date":"2028-06-30","sources":["https://www.bls.gov/","https://www.indeed.com/"],"status":"open","judged_rationale":"","brier":null}
18
+ {"category":"compute","id":"68c141ac60d298d6","statement":"The global market size for AI-powered speech recognition technology will reach $10 billion by 2027.","horizon":"2027-Q4","resolution_criteria":"According to market research reports from firms like Grand View Research or MarketsandMarkets, the global market size for AI-powered speech recognition technology will be compared to the $10 billion threshold.","created_at":"2026-06-24T13:35:12.146791","outcome":null,"resolved_at":null,"rationale":"The growth of AI-powered speech recognition technology is driven by advancements in machine learning, natural language processing, and the increasing demand for voice-assistant devices and applications. Papers like Beyond U-Net and Task Decomposition for Efficient Annotation demonstrate the advancements in speech recognition and annotation efficiency, supporting this growth. This prediction avoids the wrong_metric failure mode by focusing on market size, a directly measurable and relevant metric for this industry.","confidence":0.7,"resolution_date":"2027-12-31","sources":["https://www.grandviewresearch.com/","https://www.marketsandmarkets.com/"],"status":"open","judged_rationale":"","brier":null}
19
+ {"category":"capital","id":"438d4b895c9f628c","statement":"The number of companies investing in AI research and development will increase by at least 30% annually for the next two years, leading to a significant rise in AI-related patents filed by 2029.","horizon":"2029-Q4","resolution_criteria":"According to data from the World Intellectual Property Organization (WIPO) and company registration databases, the annual growth rate of companies investing in AI R&D and the number of AI-related patents filed will be calculated and compared to the stated thresholds.","created_at":"2026-06-24T13:35:12.146893","outcome":null,"resolved_at":null,"rationale":"The increasing interest in AI applications across various sectors, combined with government initiatives and investments in AI research, will drive the growth of companies engaging in AI R&D. Papers like Large-Language-Model Discovery of Quantum LDPC Codes and Scaling Laws for Task-Specific LLM Distillation highlight the expanding scope of AI research and its potential for innovation, supporting this trend. By focusing on the rate of increase in companies and AI-related patents, this prediction avoids the wrong_horizon failure mode by considering a multi-year trend rather than a single-year snapshot.","confidence":0.65,"resolution_date":"2029-12-31","sources":["https://www.wipo.int/","https://www.companyregistrationdatabase.com/"],"status":"open","judged_rationale":"","brier":null}
20
+ {"category":"adoption","id":"1d52048b07048ac2","statement":"By 2030, at least 20% of higher education institutions globally will have integrated AI-powered adaptive learning systems into their curriculum, leading to a significant improvement in student outcomes.","horizon":"2030-Q4","resolution_criteria":"According to surveys and reports from educational institutions and organizations like UNESCO, the percentage of higher education institutions that have integrated AI-powered adaptive learning systems will be calculated and compared to the 20% threshold.","created_at":"2026-06-24T13:35:12.146978","outcome":null,"resolved_at":null,"rationale":"The integration of AI in education is driven by its potential to enhance learning experiences, improve student outcomes, and increase accessibility. Papers like InSight and EG-VQA demonstrate the potential of AI in education and assessment, supporting this trend. By focusing on the adoption rate of AI-powered adaptive learning systems in higher education, this prediction avoids the wrong_attribution failure mode by considering the specific context of educational institutions rather than general industry trends.","confidence":0.55,"resolution_date":"2030-12-31","sources":["https://www.unesco.org/","https://www.educationinstitutiondatabase.com/"],"status":"open","judged_rationale":"","brier":null}
data/query_seed.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ [
2
+ {"query": "software developer", "expected_id": "tech_software_eng", "source": "seed"},
3
+ {"query": "software product manager", "expected_id": "tech_product_manager", "source": "seed"},
4
+ {"query": "data scientist", "expected_id": "tech_data_scientist", "source": "seed"},
5
+ {"query": "financial analyst", "expected_id": "fin_credit_analyst", "source": "seed"},
6
+ {"query": "nurse", "source": "seed"}
7
+ ]
docs/DP.md CHANGED
@@ -510,6 +510,50 @@ Add to `ui/i18n.py`: `radar_fb_experience`, `radar_match_tier_none`, `radar_matc
510
 
511
  ---
512
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
513
  ## 11. Security & compliance defaults
514
 
515
  - `require_review: true` — never change default in repo
 
510
 
511
  ---
512
 
513
+ ## 14. v0.10 Design additions (Job Query Calibration Agent)
514
+
515
+ ### 14.1 Module layout
516
+
517
+ ```
518
+ services/job_query_agent/
519
+ ├── discover.py # core_hot, query_seed.json, JobFeedback titles
520
+ ├── evaluate.py # tier + P0 regression classification (HR-2 pure)
521
+ ├── propose.py # CalibrationProposal → pending/job_calibration/
522
+ ├── traces.py # JSONL append-only
523
+ └── audit.py # orchestrates cycle; raises on P0 failure
524
+ ```
525
+
526
+ ### 14.2 Audit flow
527
+
528
+ ```
529
+ discover_queries(cfg)
530
+ → for each query: find_best_match + search_match_tier
531
+ → evaluate_query → append_trace
532
+ → optional queue_proposal (once subcommand)
533
+ → fail if p0_regression or weak_core (configurable)
534
+ ```
535
+
536
+ ### 14.3 Proposal types
537
+
538
+ | type | pending example | apply (P1) |
539
+ |------|-----------------|------------|
540
+ | `alias_patch` | add `search_aliases` | patch `jobs_kb.json` |
541
+ | `kb_profile_new` | unknown hot query | human review + KB append |
542
+ | `title_alias_map` | normalize map entry | `config.yaml` or `job_radar` map |
543
+
544
+ ### 14.4 CLI
545
+
546
+ ```bash
547
+ python run.py query-agent audit # CI: exit 1 on P0 regression
548
+ python run.py query-agent once # audit + queue proposals
549
+ ```
550
+
551
+ ### 14.5 Config (`config.yaml`)
552
+
553
+ See `job_query_agent` block: `discover.*`, `evaluate.fail_on_weak_core`, `review.pending_dir`, `traces_path`.
554
+
555
+ ---
556
+
557
  ## 11. Security & compliance defaults
558
 
559
  - `require_review: true` — never change default in repo
docs/PRD.md CHANGED
@@ -261,6 +261,32 @@ cost) and field survey lacked tenure.
261
 
262
  **Explicitly out of Phase 8:** prediction-crowd contributor job-title collection; Indeed/LinkedIn scraping; real embedding model swap (stays behind `Embedder` Protocol, HR-1).
263
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
264
  ---
265
 
266
  ## 6. Success metrics
@@ -280,10 +306,12 @@ cost) and field survey lacked tenure.
280
  | Search strong-match precision (manual audit, n≥20 queries) | ≥ 80% relevant anchor role (Phase 8) |
281
  | Field survey includes experience level | HR-13 (Phase 8) |
282
  | Transition cards respect user retrain cap when profile set | Phase 8 |
 
 
283
 
284
  ---
285
 
286
- ## 7. Out of scope (v0.9)
287
 
288
  - Auto-publishing with `require_review: false` as default
289
  - Financial advice positioning
@@ -291,3 +319,4 @@ cost) and field survey lacked tenure.
291
  - Commercial API without BUSL commercial license
292
  - Using raw embedding cosine (~0.7) as user-facing "similarity" without combined score + tier labels
293
  - Collecting job title / tenure on **prediction** crowd submissions (HR-13 applies to field feedback only)
 
 
261
 
262
  **Explicitly out of Phase 8:** prediction-crowd contributor job-title collection; Indeed/LinkedIn scraping; real embedding model swap (stays behind `Embedder` Protocol, HR-1).
263
 
264
+ ### Phase 9 — Job Query Calibration Agent (v0.10, 2026-06-24)
265
+
266
+ Problem: hot-role search gaps (e.g. «software developer» ≠ Software Engineer) were caught only
267
+ after user reports. Need a continuous **retrieval QA loop** that discovers queries, evaluates
268
+ KB match quality, traces gaps, and queues calibration proposals under the review gate.
269
+
270
+ **Design principles:**
271
+
272
+ 1. **Retrieval QA only** — agent calibrates search anchors / aliases / KB coverage, not transition recommendations (HR-12)
273
+ 2. **Propose, don't silently mutate** — default `require_review: true` for KB changes (HR-5)
274
+ 3. **CORE guard in CI** — P0 regressions fail `run.py query-agent audit`
275
+
276
+ **P0 delivered:**
277
+
278
+ - [x] `services/job_query_agent/` — `discover`, `evaluate`, `propose`, `traces`, `audit`
279
+ - [x] `run.py query-agent audit|once` — audit fails on P0/weak-core; `once` queues proposals to `pending/job_calibration/`
280
+ - [x] `config.yaml` → `job_query_agent.*`; seed file `data/query_seed.json`
281
+ - [x] CI step: `python run.py query-agent audit` after pytest
282
+ - [x] Traces: `data/query_agent_traces.jsonl`
283
+
284
+ **Phase 9 backlog:**
285
+
286
+ - [ ] P1: `query-agent apply` — merge approved `alias_patch` into `jobs_kb.json` + config title map
287
+ - [ ] P2: HF search log ingest + frequency-weighted gap detection
288
+ - [ ] P3: approved `kb_profile_new` → KB append workflow
289
+
290
  ---
291
 
292
  ## 6. Success metrics
 
306
  | Search strong-match precision (manual audit, n≥20 queries) | ≥ 80% relevant anchor role (Phase 8) |
307
  | Field survey includes experience level | HR-13 (Phase 8) |
308
  | Transition cards respect user retrain cap when profile set | Phase 8 |
309
+ | `query-agent audit` passes in CI (CORE + seed) | Phase 9 |
310
+ | LLM fallback rate on top queries (logged) | Phase 9 P2 |
311
 
312
  ---
313
 
314
+ ## 7. Out of scope (v0.10)
315
 
316
  - Auto-publishing with `require_review: false` as default
317
  - Financial advice positioning
 
319
  - Commercial API without BUSL commercial license
320
  - Using raw embedding cosine (~0.7) as user-facing "similarity" without combined score + tier labels
321
  - Collecting job title / tenure on **prediction** crowd submissions (HR-13 applies to field feedback only)
322
+ - Indeed/LinkedIn job scraping for query-agent discovery (BLS/O*NET + logs + feedback only)
job_radar.py CHANGED
@@ -1,3 +1,4 @@
 
1
  import json
2
  import math
3
  import os
@@ -62,13 +63,67 @@ def filter_by_industry(jobs: list[dict], industry: str) -> list[dict]:
62
  return jobs
63
  return [j for j in jobs if j.get("industry") == industry]
64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  # Larger hashing dim than the crowd default (256) to avoid bucket collisions that
66
  # made unrelated jobs spuriously match short queries like "finance".
67
  _SEARCH_EMBED_DIM = 8192
68
 
69
 
70
  def _default_embedder():
71
- return HashingEmbedder(dim=_SEARCH_EMBED_DIM)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
 
73
 
74
  def _job_embed_text(job: dict) -> str:
@@ -78,9 +133,11 @@ def _job_embed_text(job: dict) -> str:
78
  roles whose titles don't literally contain the word (e.g. "Credit Analyst").
79
  """
80
  skills_str = ", ".join(job.get("required_skills", []))
 
81
  parts = [
82
  job.get("title", ""),
83
  job.get("title_zh", ""),
 
84
  job.get("industry", ""),
85
  job.get("category", ""),
86
  job.get("description", ""),
@@ -97,9 +154,37 @@ _KNOWN_INDUSTRIES = (
97
  )
98
  _QUERY_STOPWORDS = frozenset({"and", "the", "for", "with", "from", "role", "jobs"})
99
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
  def _query_tokens(query: str) -> list[str]:
102
- tokens = [t for t in re.findall(r"[a-z0-9]+", query.lower()) if len(t) >= 3]
 
103
  return [t for t in tokens if t not in _QUERY_STOPWORDS]
104
 
105
 
@@ -219,6 +304,7 @@ def _apply_search_scores(
219
  embedder=None,
220
  search_cfg: dict | None = None,
221
  ) -> list[dict]:
 
222
  if embedder is None:
223
  embedder = _default_embedder()
224
  q_emb = embedder.embed([query])[0]
@@ -646,6 +732,7 @@ def find_best_match(
646
  if not jobs or not query:
647
  return 0.0, None
648
 
 
649
  cfg = search_cfg or _DEFAULT_SEARCH_CONFIG
650
  if embedder is None:
651
  embedder = _default_embedder()
 
1
+ import hashlib
2
  import json
3
  import math
4
  import os
 
63
  return jobs
64
  return [j for j in jobs if j.get("industry") == industry]
65
 
66
+ # Canonical hot roles that must hit the KB strongly (HR-7 coverage guardrail).
67
+ CORE_HOT_ROLE_QUERIES: tuple[tuple[str, str], ...] = (
68
+ ("software product manager", "tech_product_manager"),
69
+ ("product manager", "tech_product_manager"),
70
+ ("产品经理", "tech_product_manager"),
71
+ ("software developer", "tech_software_eng"),
72
+ ("software engineer", "tech_software_eng"),
73
+ ("程序员", "tech_software_eng"),
74
+ ("data scientist", "tech_data_scientist"),
75
+ ("project manager", "tech_project_manager"),
76
+ )
77
+
78
+
79
+ def assert_core_hot_role_coverage(
80
+ jobs: list[dict] | None = None,
81
+ search_cfg: dict | None = None,
82
+ ) -> None:
83
+ """Raise AssertionError if a core role query misses its expected KB id."""
84
+ pool = jobs if jobs is not None else load_knowledge_base()
85
+ cfg = search_cfg or _DEFAULT_SEARCH_CONFIG
86
+ weak = float(cfg["tier_weak"])
87
+ for query, expected_id in CORE_HOT_ROLE_QUERIES:
88
+ sim, best = find_best_match(query, pool, search_cfg=cfg)
89
+ assert best is not None, f"no match for {query!r}"
90
+ assert best["id"] == expected_id, (
91
+ f"{query!r} → {best.get('id')} (expected {expected_id}, sim={sim})"
92
+ )
93
+ assert sim >= weak, f"{query!r} sim {sim} < tier_weak {weak}"
94
+
95
+
96
  # Larger hashing dim than the crowd default (256) to avoid bucket collisions that
97
  # made unrelated jobs spuriously match short queries like "finance".
98
  _SEARCH_EMBED_DIM = 8192
99
 
100
 
101
  def _default_embedder():
102
+ return RadarHashingEmbedder(dim=_SEARCH_EMBED_DIM)
103
+
104
+
105
+ _SEARCH_TOKEN = re.compile(r"[a-z0-9]+|[\u4e00-\u9fff]{2,}")
106
+
107
+
108
+ def _l2(vec: list[float]) -> list[float]:
109
+ norm = math.sqrt(sum(x * x for x in vec)) or 1.0
110
+ return [x / norm for x in vec]
111
+
112
+
113
+ class RadarHashingEmbedder(HashingEmbedder):
114
+ """Hashing embedder with CJK token support for bilingual job search."""
115
+
116
+ def embed(self, texts: list[str]) -> list[list[float]]:
117
+ out = []
118
+ for text in texts:
119
+ v = [0.0] * self.dim
120
+ for tok in _SEARCH_TOKEN.findall(text.lower()):
121
+ if tok in _QUERY_STOPWORDS and tok.isascii():
122
+ continue
123
+ bucket = int.from_bytes(hashlib.md5(tok.encode()).digest()[:4], "big")
124
+ v[bucket % self.dim] += 1.0
125
+ out.append(_l2(v))
126
+ return out
127
 
128
 
129
  def _job_embed_text(job: dict) -> str:
 
133
  roles whose titles don't literally contain the word (e.g. "Credit Analyst").
134
  """
135
  skills_str = ", ".join(job.get("required_skills", []))
136
+ aliases_str = " ".join(job.get("search_aliases", []))
137
  parts = [
138
  job.get("title", ""),
139
  job.get("title_zh", ""),
140
+ aliases_str,
141
  job.get("industry", ""),
142
  job.get("category", ""),
143
  job.get("description", ""),
 
154
  )
155
  _QUERY_STOPWORDS = frozenset({"and", "the", "for", "with", "from", "role", "jobs"})
156
 
157
+ # Normalize common alternate job titles before retrieval (HR-7 hot-role coverage).
158
+ _QUERY_TITLE_ALIASES: dict[str, str] = {
159
+ "software developer": "software engineer",
160
+ "software development": "software engineer",
161
+ "programmer": "software engineer",
162
+ "coder": "software engineer",
163
+ "full stack developer": "software engineer",
164
+ "backend developer": "software engineer",
165
+ "frontend developer": "software engineer",
166
+ "dev": "software engineer",
167
+ "product owner": "product manager",
168
+ "technical product manager": "product manager",
169
+ "tpm": "project manager",
170
+ "program manager": "project manager",
171
+ }
172
+
173
+
174
+ def normalize_search_query(query: str) -> str:
175
+ """Map high-traffic alternate titles to canonical KB search phrases."""
176
+ q = (query or "").strip()
177
+ if not q:
178
+ return q
179
+ key = q.lower()
180
+ if key in _QUERY_TITLE_ALIASES:
181
+ return _QUERY_TITLE_ALIASES[key]
182
+ return q
183
+
184
 
185
  def _query_tokens(query: str) -> list[str]:
186
+ tokens = [t for t in _SEARCH_TOKEN.findall(query.lower()) if len(t) >= 2]
187
+ tokens = [t for t in tokens if not (t.isascii() and len(t) < 3)]
188
  return [t for t in tokens if t not in _QUERY_STOPWORDS]
189
 
190
 
 
304
  embedder=None,
305
  search_cfg: dict | None = None,
306
  ) -> list[dict]:
307
+ query = normalize_search_query(query)
308
  if embedder is None:
309
  embedder = _default_embedder()
310
  q_emb = embedder.embed([query])[0]
 
732
  if not jobs or not query:
733
  return 0.0, None
734
 
735
+ query = normalize_search_query(query)
736
  cfg = search_cfg or _DEFAULT_SEARCH_CONFIG
737
  if embedder is None:
738
  embedder = _default_embedder()
run.py CHANGED
@@ -15,6 +15,8 @@
15
  python run.py verify-export # assert DB live state == committed JSONL (HR-11)
16
  python run.py warmup # import predictions_live.jsonl → DB (cache-miss recovery)
17
  python run.py warmup --src path.jsonl
 
 
18
  """
19
  from __future__ import annotations
20
 
@@ -144,6 +146,28 @@ def cmd_verify_export(
144
  print(f"verify-export OK ({len(db_live)} live prediction(s) in sync)")
145
 
146
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  def cmd_approve(cfg):
148
  pending = Path("pending")
149
  mds = sorted(pending.glob("*.md")) if pending.exists() else []
@@ -221,6 +245,9 @@ def main():
221
  elif cmd == "warmup":
222
  src = _extract_opt(args, "--src") or out_path or "data/predictions_live.jsonl"
223
  cmd_warmup(cfg, src)
 
 
 
224
  else:
225
  print(__doc__)
226
  sys.exit(1)
 
15
  python run.py verify-export # assert DB live state == committed JSONL (HR-11)
16
  python run.py warmup # import predictions_live.jsonl → DB (cache-miss recovery)
17
  python run.py warmup --src path.jsonl
18
+ python run.py query-agent audit # Phase 9: job search calibration audit (CI)
19
+ python run.py query-agent once # audit + JSON summary (non-failing weak gaps)
20
  """
21
  from __future__ import annotations
22
 
 
146
  print(f"verify-export OK ({len(db_live)} live prediction(s) in sync)")
147
 
148
 
149
+ def cmd_query_agent(cfg, *, subcmd: str = "audit"):
150
+ from services.job_query_agent.audit import run_audit
151
+
152
+ agent_cfg = cfg.setdefault("job_query_agent", {})
153
+ if subcmd == "audit":
154
+ summary = run_audit(cfg, write_traces=True, queue_proposals=False)
155
+ print(json.dumps(summary, indent=2))
156
+ elif subcmd == "once":
157
+ # Informational run: still fails on P0 regression, logs gaps without CI noise
158
+ fail_weak = agent_cfg.get("evaluate", {}).get("fail_on_weak_core", True)
159
+ agent_cfg.setdefault("evaluate", {})["fail_on_weak_core"] = fail_weak
160
+ try:
161
+ summary = run_audit(cfg, write_traces=True, queue_proposals=True)
162
+ except AssertionError as exc:
163
+ print(str(exc), file=sys.stderr)
164
+ sys.exit(1)
165
+ print(json.dumps(summary, indent=2))
166
+ else:
167
+ print(f"unknown query-agent subcommand: {subcmd}", file=sys.stderr)
168
+ sys.exit(2)
169
+
170
+
171
  def cmd_approve(cfg):
172
  pending = Path("pending")
173
  mds = sorted(pending.glob("*.md")) if pending.exists() else []
 
245
  elif cmd == "warmup":
246
  src = _extract_opt(args, "--src") or out_path or "data/predictions_live.jsonl"
247
  cmd_warmup(cfg, src)
248
+ elif cmd == "query-agent":
249
+ sub = args[1] if len(args) > 1 else "audit"
250
+ cmd_query_agent(cfg, subcmd=sub)
251
  else:
252
  print(__doc__)
253
  sys.exit(1)
services/job_query_agent/__init__.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ """Job Query Calibration Agent — discover search queries, evaluate retrieval, trace gaps."""
2
+ from __future__ import annotations
3
+
4
+ from services.job_query_agent.audit import run_audit
5
+
6
+ __all__ = ["run_audit"]
services/job_query_agent/audit.py ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Run a full query-agent audit cycle."""
2
+ from __future__ import annotations
3
+
4
+ import json
5
+ from typing import Any
6
+
7
+ import job_radar
8
+ from services.job_query_agent.discover import discover_queries
9
+ from services.job_query_agent.evaluate import QueryVerdict, evaluate_query
10
+ from services.job_query_agent.propose import propose_from_verdict, queue_proposal
11
+ from services.job_query_agent.traces import append_trace
12
+
13
+
14
+ def run_audit(
15
+ cfg: dict[str, Any],
16
+ *,
17
+ write_traces: bool = True,
18
+ queue_proposals: bool = False,
19
+ ) -> dict[str, Any]:
20
+ """Discover queries, evaluate retrieval, optionally trace and queue fixes.
21
+
22
+ Returns a summary dict. Raises AssertionError when P0 regressions exist
23
+ (used by CI ``run.py query-agent audit``).
24
+ """
25
+ agent_cfg = cfg.get("job_query_agent", {})
26
+ job_radar_cfg = cfg.get("job_radar", {})
27
+ kb_path = job_radar_cfg.get("kb_path", "data/jobs_kb.json")
28
+ jobs = job_radar.load_knowledge_base(kb_path)
29
+
30
+ discovered = discover_queries(cfg)
31
+ verdicts: list[QueryVerdict] = []
32
+ proposals_queued = 0
33
+
34
+ for item in discovered:
35
+ verdict = evaluate_query(item, jobs, job_radar_cfg=job_radar_cfg)
36
+ verdicts.append(verdict)
37
+
38
+ if write_traces:
39
+ traces_path = agent_cfg.get("traces_path", "data/query_agent_traces.jsonl")
40
+ append_trace(traces_path, {
41
+ "query": verdict.query,
42
+ "source": verdict.source,
43
+ "status": verdict.status,
44
+ "sim": verdict.sim,
45
+ "tier": verdict.tier,
46
+ "expected_id": verdict.expected_id,
47
+ "best_id": verdict.best_id,
48
+ "message": verdict.message,
49
+ })
50
+
51
+ if queue_proposals and not verdict.ok:
52
+ proposal = propose_from_verdict(verdict)
53
+ if proposal:
54
+ pending = agent_cfg.get("review", {}).get(
55
+ "pending_dir", "pending/job_calibration",
56
+ )
57
+ queue_proposal(proposal, pending)
58
+ proposals_queued += 1
59
+
60
+ regressions = [v for v in verdicts if v.is_regression]
61
+ weak_core = [v for v in verdicts if v.status == "weak_core"]
62
+ kb_gaps = [v for v in verdicts if v.status == "kb_gap"]
63
+ weak_matches = [v for v in verdicts if v.status == "weak_match"]
64
+ ok_count = sum(1 for v in verdicts if v.ok)
65
+
66
+ summary = {
67
+ "queries": len(verdicts),
68
+ "ok": ok_count,
69
+ "p0_regressions": len(regressions),
70
+ "weak_core": len(weak_core),
71
+ "kb_gaps": len(kb_gaps),
72
+ "weak_matches": len(weak_matches),
73
+ "proposals_queued": proposals_queued,
74
+ "failures": [
75
+ {"query": v.query, "message": v.message, "status": v.status}
76
+ for v in regressions + weak_core
77
+ ],
78
+ }
79
+
80
+ if regressions:
81
+ lines = "\n".join(f" - {v.query}: {v.message}" for v in regressions)
82
+ raise AssertionError(
83
+ f"Query agent P0 regression ({len(regressions)}):\n{lines}"
84
+ )
85
+
86
+ if weak_core and agent_cfg.get("evaluate", {}).get("fail_on_weak_core", True):
87
+ lines = "\n".join(f" - {v.query}: {v.message}" for v in weak_core)
88
+ raise AssertionError(
89
+ f"Query agent weak core match ({len(weak_core)}):\n{lines}"
90
+ )
91
+
92
+ return summary
93
+
94
+
95
+ def audit_report_json(cfg: dict[str, Any]) -> str:
96
+ return json.dumps(run_audit(cfg), indent=2)
services/job_query_agent/discover.py ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Discover candidate job-search queries from core guards, seeds, and feedback."""
2
+ from __future__ import annotations
3
+
4
+ import json
5
+ from dataclasses import dataclass
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ import job_radar
10
+
11
+
12
+ @dataclass(frozen=True)
13
+ class DiscoveredQuery:
14
+ query: str
15
+ source: str
16
+ expected_id: str | None = None
17
+
18
+
19
+ def _variant_queries(query: str) -> list[str]:
20
+ """Generate cheap orthographic variants for audit coverage."""
21
+ base = query.strip()
22
+ if not base:
23
+ return []
24
+ variants = {base, base.lower(), base.title()}
25
+ if base.islower():
26
+ variants.add(base.upper())
27
+ return sorted(variants)
28
+
29
+
30
+ def discover_from_core() -> list[DiscoveredQuery]:
31
+ out: list[DiscoveredQuery] = []
32
+ for query, expected_id in job_radar.CORE_HOT_ROLE_QUERIES:
33
+ out.append(DiscoveredQuery(query, "core_hot", expected_id))
34
+ return out
35
+
36
+
37
+ def discover_from_seed(seed_path: str | Path) -> list[DiscoveredQuery]:
38
+ path = Path(seed_path)
39
+ if not path.is_file():
40
+ return []
41
+ raw = json.loads(path.read_text(encoding="utf-8"))
42
+ out: list[DiscoveredQuery] = []
43
+ for row in raw:
44
+ if isinstance(row, str):
45
+ out.append(DiscoveredQuery(row, "seed"))
46
+ continue
47
+ if not isinstance(row, dict) or not row.get("query"):
48
+ continue
49
+ out.append(DiscoveredQuery(
50
+ str(row["query"]),
51
+ str(row.get("source", "seed")),
52
+ row.get("expected_id"),
53
+ ))
54
+ return out
55
+
56
+
57
+ def discover_from_feedback(*, min_count: int = 1) -> list[DiscoveredQuery]:
58
+ """Titles users submitted in JobFeedback (offline-safe: returns [] if DB empty)."""
59
+ try:
60
+ metrics = job_radar.get_empirical_metrics()
61
+ except Exception:
62
+ return []
63
+ out: list[DiscoveredQuery] = []
64
+ for title, m in metrics.items():
65
+ if int(m.get("total_responses", 0)) >= min_count and title.strip():
66
+ out.append(DiscoveredQuery(title.strip(), "feedback"))
67
+ return out
68
+
69
+
70
+ def discover_queries(cfg: dict[str, Any]) -> list[DiscoveredQuery]:
71
+ """Merge and dedupe discovery sources per config."""
72
+ agent_cfg = cfg.get("job_query_agent", {})
73
+ discover_cfg = agent_cfg.get("discover", {})
74
+ seen: set[str] = set()
75
+ merged: list[DiscoveredQuery] = []
76
+
77
+ def _add(items: list[DiscoveredQuery]) -> None:
78
+ for item in items:
79
+ key = item.query.strip().lower()
80
+ if not key or key in seen:
81
+ continue
82
+ seen.add(key)
83
+ merged.append(item)
84
+
85
+ if discover_cfg.get("include_core", True):
86
+ _add(discover_from_core())
87
+ seed_path = discover_cfg.get("seed_path", "data/query_seed.json")
88
+ if discover_cfg.get("include_seed", True):
89
+ _add(discover_from_seed(seed_path))
90
+ if discover_cfg.get("include_feedback_titles", True):
91
+ _add(discover_from_feedback(
92
+ min_count=int(discover_cfg.get("feedback_min_responses", 1)),
93
+ ))
94
+ if discover_cfg.get("include_variants", True):
95
+ base = list(merged)
96
+ for item in base:
97
+ for variant in _variant_queries(item.query):
98
+ if variant.lower() != item.query.lower():
99
+ _add([DiscoveredQuery(variant, "variant", item.expected_id)])
100
+
101
+ max_q = int(discover_cfg.get("max_queries_per_run", 200))
102
+ return merged[:max_q]
services/job_query_agent/evaluate.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Pure evaluation of a single job-search query against the KB (HR-2)."""
2
+ from __future__ import annotations
3
+
4
+ from dataclasses import dataclass
5
+ from typing import Any
6
+
7
+ import job_radar
8
+
9
+
10
+ @dataclass(frozen=True)
11
+ class QueryVerdict:
12
+ query: str
13
+ source: str
14
+ expected_id: str | None
15
+ best_id: str | None
16
+ best_title: str | None
17
+ sim: float
18
+ tier: str
19
+ status: str
20
+ message: str
21
+
22
+ @property
23
+ def ok(self) -> bool:
24
+ return self.status == "ok"
25
+
26
+ @property
27
+ def is_regression(self) -> bool:
28
+ return self.status == "p0_regression"
29
+
30
+
31
+ def _core_expected_map() -> dict[str, str]:
32
+ return {q: eid for q, eid in job_radar.CORE_HOT_ROLE_QUERIES}
33
+
34
+
35
+ def evaluate_query(
36
+ discovered,
37
+ jobs: list[dict],
38
+ *,
39
+ job_radar_cfg: dict[str, Any] | None = None,
40
+ ) -> QueryVerdict:
41
+ """Score one query and classify the retrieval outcome."""
42
+ search_cfg = job_radar.resolve_search_config(job_radar_cfg)
43
+ tier_no = float(search_cfg["tier_no_match"])
44
+ tier_weak = float(search_cfg["tier_weak"])
45
+
46
+ sim, best = job_radar.find_best_match(
47
+ discovered.query, jobs, search_cfg=search_cfg,
48
+ )
49
+ tier = job_radar.search_match_tier(sim, search_cfg)
50
+ best_id = best.get("id") if best else None
51
+ best_title = best.get("title") if best else None
52
+ expected = discovered.expected_id or _core_expected_map().get(discovered.query)
53
+
54
+ if expected:
55
+ if best_id != expected:
56
+ return QueryVerdict(
57
+ discovered.query, discovered.source, expected, best_id, best_title,
58
+ sim, tier, "p0_regression",
59
+ f"expected {expected}, got {best_id} (sim={sim:.3f})",
60
+ )
61
+ if sim < tier_weak:
62
+ return QueryVerdict(
63
+ discovered.query, discovered.source, expected, best_id, best_title,
64
+ sim, tier, "weak_core",
65
+ f"correct id but sim {sim:.3f} < tier_weak {tier_weak}",
66
+ )
67
+ return QueryVerdict(
68
+ discovered.query, discovered.source, expected, best_id, best_title,
69
+ sim, tier, "ok", "core guard satisfied",
70
+ )
71
+
72
+ if tier == "none" or sim < tier_no:
73
+ return QueryVerdict(
74
+ discovered.query, discovered.source, None, best_id, best_title,
75
+ sim, tier, "kb_gap",
76
+ f"no confident KB match (sim={sim:.3f})",
77
+ )
78
+
79
+ if tier == "weak":
80
+ return QueryVerdict(
81
+ discovered.query, discovered.source, None, best_id, best_title,
82
+ sim, tier, "weak_match",
83
+ f"weak match to {best_title!r}",
84
+ )
85
+
86
+ return QueryVerdict(
87
+ discovered.query, discovered.source, None, best_id, best_title,
88
+ sim, tier, "ok", f"strong match to {best_title!r}",
89
+ )
services/job_query_agent/propose.py ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Propose calibration actions from query verdicts (queued, not auto-applied by default)."""
2
+ from __future__ import annotations
3
+
4
+ import json
5
+ import re
6
+ from dataclasses import asdict, dataclass
7
+ from datetime import datetime, timezone
8
+ from pathlib import Path
9
+ from typing import Any
10
+
11
+ from services.job_query_agent.evaluate import QueryVerdict
12
+
13
+
14
+ @dataclass(frozen=True)
15
+ class CalibrationProposal:
16
+ proposal_id: str
17
+ type: str
18
+ query: str
19
+ target_id: str | None
20
+ payload: dict[str, Any]
21
+ evidence: dict[str, Any]
22
+ status: str = "pending"
23
+
24
+ def to_dict(self) -> dict[str, Any]:
25
+ return asdict(self)
26
+
27
+
28
+ def _slug(text: str) -> str:
29
+ s = re.sub(r"[^a-z0-9]+", "_", text.lower()).strip("_")
30
+ return s[:48] or "query"
31
+
32
+
33
+ def propose_from_verdict(verdict: QueryVerdict) -> CalibrationProposal | None:
34
+ """Return a reviewable proposal for non-ok verdicts."""
35
+ if verdict.ok or verdict.is_regression:
36
+ if verdict.status == "weak_core" and verdict.expected_id:
37
+ return CalibrationProposal(
38
+ proposal_id=f"alias_{_slug(verdict.query)}",
39
+ type="alias_patch",
40
+ query=verdict.query,
41
+ target_id=verdict.expected_id,
42
+ payload={"add_aliases": [verdict.query]},
43
+ evidence={
44
+ "sim": verdict.sim,
45
+ "tier": verdict.tier,
46
+ "reason": verdict.message,
47
+ },
48
+ )
49
+ return None
50
+
51
+ if verdict.status == "kb_gap":
52
+ return CalibrationProposal(
53
+ proposal_id=f"kb_gap_{_slug(verdict.query)}",
54
+ type="kb_profile_new",
55
+ query=verdict.query,
56
+ target_id=verdict.best_id,
57
+ payload={"query": verdict.query, "nearest_id": verdict.best_id},
58
+ evidence={"sim": verdict.sim, "tier": verdict.tier, "best_title": verdict.best_title},
59
+ )
60
+
61
+ if verdict.status == "weak_match" and verdict.best_id:
62
+ return CalibrationProposal(
63
+ proposal_id=f"alias_{_slug(verdict.query)}",
64
+ type="alias_patch",
65
+ query=verdict.query,
66
+ target_id=verdict.best_id,
67
+ payload={"add_aliases": [verdict.query]},
68
+ evidence={"sim": verdict.sim, "tier": verdict.tier, "best_title": verdict.best_title},
69
+ )
70
+
71
+ return None
72
+
73
+
74
+ def queue_proposal(proposal: CalibrationProposal, pending_dir: str | Path) -> Path:
75
+ """Write proposal JSON to pending dir (HR-5 review gate)."""
76
+ root = Path(pending_dir)
77
+ root.mkdir(parents=True, exist_ok=True)
78
+ path = root / f"{proposal.proposal_id}.json"
79
+ body = proposal.to_dict()
80
+ body["queued_at"] = datetime.now(timezone.utc).isoformat()
81
+ path.write_text(json.dumps(body, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
82
+ return path
services/job_query_agent/traces.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Append-only JSONL traces for query-agent runs."""
2
+ from __future__ import annotations
3
+
4
+ import json
5
+ from datetime import datetime, timezone
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+
10
+ def append_trace(path: str | Path, record: dict[str, Any]) -> None:
11
+ path = Path(path)
12
+ path.parent.mkdir(parents=True, exist_ok=True)
13
+ row = {
14
+ **record,
15
+ "ts": datetime.now(timezone.utc).isoformat(),
16
+ }
17
+ with path.open("a", encoding="utf-8") as f:
18
+ f.write(json.dumps(row, ensure_ascii=False) + "\n")
19
+
20
+
21
+ def load_traces(path: str | Path, *, limit: int = 500) -> list[dict[str, Any]]:
22
+ path = Path(path)
23
+ if not path.is_file():
24
+ return []
25
+ lines = path.read_text(encoding="utf-8").splitlines()
26
+ out: list[dict[str, Any]] = []
27
+ for line in lines[-limit:]:
28
+ line = line.strip()
29
+ if line:
30
+ out.append(json.loads(line))
31
+ return out
tests/test_job_query_agent.py ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Tests for job query calibration agent (Phase 9, HR-1 offline)."""
2
+ from __future__ import annotations
3
+
4
+ import json
5
+ from pathlib import Path
6
+
7
+ import job_radar
8
+ import pytest
9
+ from services.job_query_agent.audit import run_audit
10
+ from services.job_query_agent.discover import DiscoveredQuery, discover_from_core, discover_queries
11
+ from services.job_query_agent.evaluate import evaluate_query
12
+ from services.job_query_agent.propose import propose_from_verdict
13
+
14
+
15
+ @pytest.fixture
16
+ def cfg():
17
+ return {
18
+ "job_radar": {"kb_path": "data/jobs_kb.json"},
19
+ "job_query_agent": {
20
+ "traces_path": "data/query_agent_traces_test.jsonl",
21
+ "discover": {
22
+ "include_core": True,
23
+ "include_seed": False,
24
+ "include_feedback_titles": False,
25
+ "include_variants": False,
26
+ },
27
+ "evaluate": {"fail_on_weak_core": True},
28
+ },
29
+ }
30
+
31
+
32
+ def test_discover_from_core_includes_product_manager():
33
+ queries = {d.query for d in discover_from_core()}
34
+ assert "software developer" in queries
35
+ assert "产品经理" in queries
36
+
37
+
38
+ def test_evaluate_core_query_ok():
39
+ jobs = job_radar.load_knowledge_base()
40
+ item = DiscoveredQuery("software developer", "core_hot", "tech_software_eng")
41
+ verdict = evaluate_query(item, jobs)
42
+ assert verdict.ok
43
+ assert verdict.best_id == "tech_software_eng"
44
+
45
+
46
+ def test_evaluate_regression_detected():
47
+ jobs = job_radar.load_knowledge_base()
48
+ item = DiscoveredQuery("software developer", "core_hot", "tech_product_manager")
49
+ verdict = evaluate_query(item, jobs)
50
+ assert verdict.is_regression
51
+
52
+
53
+ def test_propose_alias_on_weak_match():
54
+ jobs = job_radar.load_knowledge_base()
55
+ item = DiscoveredQuery("obscure made up title xyz", "seed")
56
+ verdict = evaluate_query(item, jobs)
57
+ proposal = propose_from_verdict(verdict)
58
+ if verdict.status == "kb_gap":
59
+ assert proposal is not None
60
+ assert proposal.type == "kb_profile_new"
61
+ elif verdict.status == "weak_match":
62
+ assert proposal is not None
63
+ assert proposal.type == "alias_patch"
64
+
65
+
66
+ def test_run_audit_passes_on_real_kb(cfg, tmp_path):
67
+ cfg = dict(cfg)
68
+ cfg["job_query_agent"] = {
69
+ **cfg["job_query_agent"],
70
+ "traces_path": str(tmp_path / "traces.jsonl"),
71
+ }
72
+ summary = run_audit(cfg, write_traces=True)
73
+ assert summary["p0_regressions"] == 0
74
+ assert summary["ok"] >= len(job_radar.CORE_HOT_ROLE_QUERIES)
75
+ assert Path(cfg["job_query_agent"]["traces_path"]).is_file()
76
+
77
+
78
+ def test_run_audit_fails_on_regression(cfg, tmp_path):
79
+ cfg = dict(cfg)
80
+ cfg["job_query_agent"]["traces_path"] = str(tmp_path / "traces.jsonl")
81
+
82
+ original = job_radar.CORE_HOT_ROLE_QUERIES
83
+ bad = (("software developer", "tech_product_manager"),) + original[1:]
84
+ job_radar.CORE_HOT_ROLE_QUERIES = bad
85
+ try:
86
+ with pytest.raises(AssertionError, match="P0 regression"):
87
+ run_audit(cfg, write_traces=False)
88
+ finally:
89
+ job_radar.CORE_HOT_ROLE_QUERIES = original
90
+
91
+
92
+ def test_discover_queries_respects_max(cfg):
93
+ cfg = dict(cfg)
94
+ cfg["job_query_agent"]["discover"]["max_queries_per_run"] = 3
95
+ items = discover_queries(cfg)
96
+ assert len(items) <= 3
tests/test_job_radar.py CHANGED
@@ -123,6 +123,30 @@ def test_hybrid_query_adds_similarity():
123
  # find_best_match (relevance regressions)
124
  # --------------------------------------------------------------------------- #
125
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  def test_finance_query_matches_finance_industry():
127
  _, best = job_radar.find_best_match("finance", _kb())
128
  assert best is not None and best["industry"] == "Finance"
 
123
  # find_best_match (relevance regressions)
124
  # --------------------------------------------------------------------------- #
125
 
126
+ def test_core_hot_roles_match_kb():
127
+ """Popular roles must resolve to curated KB entries, not LLM fallback."""
128
+ job_radar.assert_core_hot_role_coverage(_kb())
129
+
130
+
131
+ def test_software_product_manager_strong_match():
132
+ sim, best = job_radar.find_best_match("software product manager", _kb())
133
+ assert best is not None
134
+ assert best["id"] == "tech_product_manager"
135
+ assert sim >= job_radar.resolve_search_config()["tier_weak"]
136
+
137
+
138
+ def test_software_developer_matches_engineer():
139
+ sim, best = job_radar.find_best_match("software developer", _kb())
140
+ assert best is not None
141
+ assert best["id"] == "tech_software_eng"
142
+ assert sim >= job_radar.resolve_search_config()["tier_weak"]
143
+
144
+
145
+ def test_normalize_search_query_aliases():
146
+ assert job_radar.normalize_search_query("software developer") == "software engineer"
147
+ assert job_radar.normalize_search_query("Software Developer") == "software engineer"
148
+
149
+
150
  def test_finance_query_matches_finance_industry():
151
  _, best = job_radar.find_best_match("finance", _kb())
152
  assert best is not None and best["industry"] == "Finance"
ui/i18n.py CHANGED
@@ -396,6 +396,16 @@ The agent's goal is to stay well below 0.25 — the "coin-flip" baseline.""",
396
  "zh": "与「{q}」无可靠匹配(相关度 {sim:.2f})。"
397
  "将尝试 AI 生成画像,或浏览下方岗位矩阵。",
398
  },
 
 
 
 
 
 
 
 
 
 
399
  "radar_match_tier_weak": {
400
  "en": "Weak text match for «{q}»: **{title}** (relevance {sim:.2f}). "
401
  "Anchor role set below — career paths ranked by transition fit, not search text.",
 
396
  "zh": "与「{q}」无可靠匹配(相关度 {sim:.2f})。"
397
  "将尝试 AI 生成画像,或浏览下方岗位矩阵。",
398
  },
399
+ "radar_llm_anchor_ok": {
400
+ "en": "No KB match for «{q}» (relevance {sim:.2f}). "
401
+ "Using AI-estimated anchor role **{title}** — opportunities below are ranked by **transition fit**, not text search.",
402
+ "zh": "知识库无「{q}」可靠匹配(相关度 {sim:.2f})。"
403
+ "已用 AI 估算锚定岗位 **{title}**——下方机会列表按**转型契合度**排序,非文本搜索。",
404
+ },
405
+ "radar_matrix_at_risk_skipped": {
406
+ "en": "At-risk column hidden for AI-estimated roles — KB search relevance would be misleading. See transition paths below.",
407
+ "zh": "AI 估算岗位不展示高风险列——知识库搜索相关度无意义。请查看下方转型路径。",
408
+ },
409
  "radar_match_tier_weak": {
410
  "en": "Weak text match for «{q}»: **{title}** (relevance {sim:.2f}). "
411
  "Anchor role set below — career paths ranked by transition fit, not search text.",
ui/tabs/radar.py CHANGED
@@ -39,6 +39,18 @@ def _role_status(category: str) -> str:
39
  return t("status_emerging")
40
 
41
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  def render(scenario_input: dict, prior, job_radar_cfg: dict):
43
  st.subheader(t("radar_title"))
44
  st.markdown(t("radar_intro"))
@@ -125,6 +137,7 @@ def render(scenario_input: dict, prior, job_radar_cfg: dict):
125
  )
126
 
127
  anchor_job = None
 
128
  llm_generated_profile = None
129
  if search_query:
130
  best_sim, best_job = job_radar.find_best_match(
@@ -149,14 +162,20 @@ def render(scenario_input: dict, prior, job_radar_cfg: dict):
149
  llm_generated_profile["title"] += " 🤖" + t("radar_ai_badge")
150
  all_jobs.append(llm_generated_profile)
151
  anchor_job = llm_generated_profile
152
- st.info(t("radar_llm_ok", title=job_title(llm_generated_profile)))
 
 
 
 
 
 
153
  else:
154
  st.warning(t("radar_llm_fail"))
155
- st.warning(t(
156
- "radar_match_tier_none",
157
- q=search_query,
158
- sim=best_sim,
159
- ))
160
  elif tier == "weak":
161
  anchor_job = best_job
162
  st.warning(t(
@@ -185,33 +204,46 @@ def render(scenario_input: dict, prior, job_radar_cfg: dict):
185
  opportunity_list = [j for j in final_jobs if j.get("category") in ("emerging", "transforming")]
186
 
187
  # Sort lists: retrieval for at-risk; transition fit for opportunities when anchored (HR-12)
 
 
 
188
  if search_query:
189
- at_risk_list.sort(
190
- key=lambda x: (x.get("combined_similarity", 0.0), x.get("hybrid_score", 0.0)),
191
- reverse=True,
192
- )
193
  if anchor_job:
194
  st.caption(t("radar_search_retrieval_note"))
195
  st.caption(t("radar_anchor_auto", title=job_title(anchor_job)))
196
- transition_ranked = job_radar.rank_jobs_by_transition_score(
197
  anchor_job,
198
- opportunity_list,
199
  scenario_input,
 
200
  experience_level=user_experience,
201
  max_retrain_months=user_retrain_cap,
202
  job_radar_cfg=job_radar_cfg,
203
  )
204
- opp_by_id = {j["id"]: j for j in opportunity_list}
205
- opportunity_list = []
206
- for tr in transition_ranked:
207
- base = opp_by_id.get(tr["id"])
208
- if base:
209
- merged = base.copy()
210
- merged["transition_score"] = tr.get("transition_score", 0.0)
211
- opportunity_list.append(merged)
 
 
 
212
  else:
 
 
 
 
 
 
 
213
  opportunity_list.sort(
214
- key=lambda x: (x.get("combined_similarity", 0.0), x.get("hybrid_score", 0.0)),
 
 
 
215
  reverse=True,
216
  )
217
  else:
@@ -229,7 +261,9 @@ def render(scenario_input: dict, prior, job_radar_cfg: dict):
229
 
230
  with col_risk:
231
  st.markdown(f"#### {t('radar_at_risk')}")
232
- if not at_risk_list:
 
 
233
  st.write(t("radar_no_at_risk"))
234
  else:
235
  for j in at_risk_list[:5]:
 
39
  return t("status_emerging")
40
 
41
 
42
+ def _merge_transition_rows(paths: list[dict], job_by_id: dict[str, dict]) -> list[dict]:
43
+ """Merge compute_transition_paths output with full KB rows for matrix cards."""
44
+ merged: list[dict] = []
45
+ for p in paths:
46
+ base = job_by_id.get(p["id"], p)
47
+ row = base.copy()
48
+ row["transition_score"] = p.get("transition_score", 0.0)
49
+ row["retrain_months"] = p.get("retrain_months", row.get("retrain_months", 0))
50
+ merged.append(row)
51
+ return merged
52
+
53
+
54
  def render(scenario_input: dict, prior, job_radar_cfg: dict):
55
  st.subheader(t("radar_title"))
56
  st.markdown(t("radar_intro"))
 
137
  )
138
 
139
  anchor_job = None
140
+ anchor_from_llm = False
141
  llm_generated_profile = None
142
  if search_query:
143
  best_sim, best_job = job_radar.find_best_match(
 
162
  llm_generated_profile["title"] += " 🤖" + t("radar_ai_badge")
163
  all_jobs.append(llm_generated_profile)
164
  anchor_job = llm_generated_profile
165
+ anchor_from_llm = True
166
+ st.info(t(
167
+ "radar_llm_anchor_ok",
168
+ title=job_title(llm_generated_profile),
169
+ sim=best_sim,
170
+ q=search_query,
171
+ ))
172
  else:
173
  st.warning(t("radar_llm_fail"))
174
+ st.warning(t(
175
+ "radar_match_tier_none",
176
+ q=search_query,
177
+ sim=best_sim,
178
+ ))
179
  elif tier == "weak":
180
  anchor_job = best_job
181
  st.warning(t(
 
204
  opportunity_list = [j for j in final_jobs if j.get("category") in ("emerging", "transforming")]
205
 
206
  # Sort lists: retrieval for at-risk; transition fit for opportunities when anchored (HR-12)
207
+ job_by_id_all = {j["id"]: j for j in all_jobs}
208
+ for j in final_jobs:
209
+ job_by_id_all[j["id"]] = j
210
  if search_query:
 
 
 
 
211
  if anchor_job:
212
  st.caption(t("radar_search_retrieval_note"))
213
  st.caption(t("radar_anchor_auto", title=job_title(anchor_job)))
214
+ transition_paths = job_radar.compute_transition_paths(
215
  anchor_job,
216
+ all_jobs,
217
  scenario_input,
218
+ top_k=5,
219
  experience_level=user_experience,
220
  max_retrain_months=user_retrain_cap,
221
  job_radar_cfg=job_radar_cfg,
222
  )
223
+ opportunity_list = _merge_transition_rows(transition_paths, job_by_id_all)
224
+ if anchor_from_llm:
225
+ at_risk_list = []
226
+ else:
227
+ at_risk_list.sort(
228
+ key=lambda x: (
229
+ x.get("combined_similarity", 0.0),
230
+ x.get("hybrid_score", 0.0),
231
+ ),
232
+ reverse=True,
233
+ )
234
  else:
235
+ at_risk_list.sort(
236
+ key=lambda x: (
237
+ x.get("combined_similarity", 0.0),
238
+ x.get("hybrid_score", 0.0),
239
+ ),
240
+ reverse=True,
241
+ )
242
  opportunity_list.sort(
243
+ key=lambda x: (
244
+ x.get("combined_similarity", 0.0),
245
+ x.get("hybrid_score", 0.0),
246
+ ),
247
  reverse=True,
248
  )
249
  else:
 
261
 
262
  with col_risk:
263
  st.markdown(f"#### {t('radar_at_risk')}")
264
+ if anchor_from_llm and search_query:
265
+ st.caption(t("radar_matrix_at_risk_skipped"))
266
+ elif not at_risk_list:
267
  st.write(t("radar_no_at_risk"))
268
  else:
269
  for j in at_risk_list[:5]: