Skip to content

Add Jev job-lead shadow observations - #418

Merged
michaelmwu merged 4 commits into
evals/jev-job-leadfrom
feat/jev-job-lead-shadow
Sep 21, 2026
Merged

michaelmwu merged 4 commits into
evals/jev-job-leadfrom
feat/jev-job-lead-shadow

Conversation

@michaelmwu

@michaelmwu michaelmwu commented Sep 21, 2026

Copy link
Copy Markdown
Member

Summary

  • share the evaluated Jev decision contract and OpenRouter transport with production
  • run a disabled-by-default, deterministic 10% Jev shadow sample after the authoritative job-lead classifier
  • expose agreement, confidence-gate coverage, latency, usage, cost, failures, and bounded review items in each scrape job result
  • add runtime configuration, documentation, and focused tests

Safety

  • Jev never changes the production classification or persistence decision
  • one Jev failure opens a circuit breaker for the rest of that scrape run
  • raw HN post text and raw provider responses are omitted from shadow reports
  • the feature remains disabled until JOB_LEAD_JEV_SHADOW_ENABLED is set

Viewing shadow data

Enable the Jev shadow under Dashboard > Configuration > AI. Then open Dashboard > Background tasks, select a scrape_job_leads_job run, choose Details, and inspect Result > classifier_shadow.

Validation

  • 91 focused job-lead and runtime-config tests passed
  • full Python suite: 2178 passed, 25 skipped; two process-discovery tests required host process visibility and passed outside the sandbox
  • admin dashboard: 17 tests passed
  • Ruff lint and format checks passed
  • Pyrefly passed with zero errors
  • uv lock check and git diff check passed
  • live OpenRouter Jev smoke: 48 of 48 calls succeeded, 100% binary F1, 95.8% joint accuracy, 242 ms p50, 313 ms p95, and 0.001031 USD total cost

Dependency

This PR is stacked on #417 because that PR introduces the evaluated corpus and harness contract reused here. PR #417 is green and mergeable, but GitHub requires approval from someone other than its last pusher before merge-queue admission.


Note

Medium Risk
Extends the scrape-time classifier with bounded OpenRouter calls and new metadata, but production decisions are unchanged; misconfiguration or provider outages only affect shadow telemetry and scrape latency within configured budgets.

Overview
Adds an optional, disabled-by-default Jev shadow on HN job-lead scraping: after the authoritative LLM/heuristic classifier runs, a shared job_lead_jev module can call OpenRouter Decisions on a deterministic sample and attach normalized observations without changing production labels or persistence.

Configuration and ops: New JOB_LEAD_JEV_SHADOW_* settings land in worker config, dashboard runtime config (AI), .env.example, and docs. Scrape results gain Result → classifier_shadow with agreement rates, confidence-gate stats, latency, token/cost usage, bounded review items (IDs/URLs only), and run-level caps (default 25 calls / 20s). One provider failure disables further Jev calls for that scrape run.

Refactor: Eval harness Jev path delegates to the same contract/transport as production shadow.

Reviewed by Cursor Bugbot for commit 1c05c6c. Bugbot is set up for automated code reviews on this repo. Configure here.

@coderabbitai

coderabbitai Bot commented Sep 21, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 258dfd64-ac4a-4c1e-b514-83c13eca9a4e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cursor

cursor Bot commented Sep 21, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_85ed22b1-a972-44f5-9e70-5fbda0b46adf)

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 21, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-21T08:05:52.424608Z 1c05c6c New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 51f6842027

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .env.example Outdated
Comment thread packages/shared/src/five08/job_lead_jev.py
Comment thread packages/shared/src/five08/job_lead_sources.py
@cursor

cursor Bot commented Sep 21, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_154d5dc7-6390-4910-b749-6674ed4b4a18)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d9e0450ed0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/shared/src/five08/job_lead_sources.py Outdated
@michaelmwu
michaelmwu force-pushed the feat/jev-job-lead-shadow branch from d9e0450 to 88d919d Compare September 21, 2026 07:44
@cursor

cursor Bot commented Sep 21, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_3cc78085-5f98-44e1-8881-7fba085264c8)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 88d919d103

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/shared/src/five08/job_lead_sources.py
Comment thread packages/shared/src/five08/job_lead_jev.py
@michaelmwu
michaelmwu force-pushed the feat/jev-job-lead-shadow branch from 88d919d to e2cabae Compare September 21, 2026 07:56
@cursor

cursor Bot commented Sep 21, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_db3849e3-e9cc-445a-8b1c-72544e6adec9)

@cursor

cursor Bot commented Sep 21, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_deaf352e-a6b5-4b88-9ce2-6c75e3717fba)

@michaelmwu
michaelmwu merged commit ed13287 into evals/jev-job-lead Sep 21, 2026
3 checks passed
@michaelmwu
michaelmwu deleted the feat/jev-job-lead-shadow branch September 21, 2026 08:00

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1c05c6c4d2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +526 to +529
value_type="float",
env_names=("JOB_LEAD_JEV_SHADOW_SAMPLE_RATE",),
min_value=0.0,
max_value=1.0,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject non-finite Jev runtime values

When an administrator enters NaN for this dashboard-managed float, coerce_runtime_config_value accepts it because both range comparisons against NaN are false. _bounded_float then converts that NaN to the configured maximum, so a NaN sample rate unexpectedly becomes 1.0; the new timeout and run-budget fields have the same issue and become their maximums. This can turn a partial or paused experiment into 100% sampling with maximum execution limits, so these float settings should reject non-finite values before persistence.

Useful? React with 👍 / 👎.

Comment on lines +980 to +982
agrees_with_primary=(
decision.is_contractor_friendly == classification.is_contractor_friendly
),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include posting type in shadow agreement metrics

When Jev and the primary classifier produce the same contractor-friendly boolean but different posting types, this records an agreement and the report creates no review item unless the confidence gate also falls back. Posting type affects downstream forum selection, so differences such as part_time versus part_time_or_full_time are production-relevant, yet they disappear from the aggregate experiment results even though both values are collected. Track posting-type or joint agreement separately and surface those disagreements for review.

Useful? React with 👍 / 👎.

result = float(value)
except (TypeError, ValueError):
return None
return result if result >= 0 else None

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject infinite provider costs before persistence

If OpenRouter returns an overflowing JSON number such as 1e999, or the string "Infinity", for usage.cost, float(value) produces positive infinity and this accepts it as a valid cost. The infinite value is then placed in lead metadata and the scrape-job result; Python serializes it as the non-JSON token Infinity, which PostgreSQL jsonb rejects when the lead or job result is persisted. Thus a malformed non-authoritative shadow response can fail the authoritative scrape instead of being isolated as a shadow failure; require provider usage values to be finite.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant