Skip to content

fix(eval): gate dead links before evaluation in oferta/auto-pipeline#937

Merged
santifer merged 1 commit into
santifer:mainfrom
maxmilian:fix/835-eval-liveness-gate
Jun 11, 2026
Merged

fix(eval): gate dead links before evaluation in oferta/auto-pipeline#937
santifer merged 1 commit into
santifer:mainfrom
maxmilian:fix/835-eval-liveness-gate

Conversation

@maxmilian

@maxmilian maxmilian commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds a liveness gate at the evaluation entry points so a dead/expired job link can no longer trigger a full A–G evaluation, a written report, and a tailored PDF on phantom content.

  • modes/auto-pipeline.md — new Step 0.5 — Liveness gate between Step 0 (Extract JD) and Step 1 (A–G eval). The Step 0 Playwright snapshot is already in hand, so the gate judges it inline; a closed/dead/redirected/404 page stops before Step 1 and marks the data/pipeline.md entry dead.
  • modes/oferta.md — new Liveness gate (URL inputs) before Block A (covers direct-URL entry, e.g. running oferta on a pending pipeline link). When auto-pipeline already cleared the link in its Step 0.5, oferta reuses that snapshot instead of re-navigating. JD-text input (no URL) skips the gate.
  • test-all.mjs — +1 regression assertion that both eval modes carry the gate (mirrors the apply-mode gate test).

Related issue

Fixes #835

Notes / design choices

Type of change

  • Bug fix (non-breaking change that fixes an issue)

Checklist

  • I have read the CONTRIBUTING guide
  • My PR is linked to a related issue (Fixes #835)
  • No personal data (real CV / email / phone / name) is included
  • I ran node test-all.mjs locally — 231 passed, 0 failed (16 pre-existing warnings: cv-sync without user data + README translation false-positives, unrelated)
  • My changes respect the Data Contract (System Layer only: modes/*.md, test-all.mjs)
  • Changes align with the project roadmap / philosophy (simple, minimal)

Summary by CodeRabbit

Release Notes

  • New Features

    • Added liveness verification that checks if job postings are active before evaluation begins
    • Supports both direct URL inputs and pasted job descriptions
    • Automatically stops processing when a posting is detected as closed or inactive
  • Tests

    • Added validation to ensure liveness detection functionality is properly implemented

Level-3 scan results enter pipeline.md as pending entries with no
liveness check. oferta and auto-pipeline then run the full A-G
evaluation, write a report, and generate a tailored PDF before anyone
discovers the posting is gone — a 404/expired page served as a static
fallback ("position filled", empty shell) scores against phantom
content.

Add a liveness gate at the eval entry points, mirroring the apply-mode
preflight gate (santifer#887): auto-pipeline gets a Step 0.5 that judges the
Step 0 snapshot before Step 1, and oferta gets a URL-input gate before
Block A. A closed/dead/redirected page stops the flow — no eval, report,
or CV — and marks the pipeline entry dead. JD-text input (no URL) skips
the gate. When auto-pipeline drives oferta, oferta reuses the already-
cleared snapshot instead of re-navigating.

Inline-snapshot judgment (not a check-liveness.mjs call) keeps the
convention consistent with apply.md and avoids a second navigation,
since Step 0 already holds the snapshot.

+1 regression test asserting both eval modes carry the gate.

Fixes santifer#835

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds a liveness gate step to the job evaluation workflows. Before evaluating job postings, both auto-pipeline and oferta modes now verify the posting is still active using Playwright-based snapshot and content classification. Dead links trigger early termination and optional tracker marking. Test coverage validates the gate documentation exists in both mode files.

Changes

Liveness Gate Documentation and Testing

Layer / File(s) Summary
Liveness gate workflow documentation
modes/oferta.md, modes/auto-pipeline.md
auto-pipeline Step 0.5 and oferta pre-Block A now document a liveness-check gate that uses Playwright snapshots to classify postings as active vs closed, stopping evaluation early for dead links with optional tracker updates. Block G freshness guidance references the snapshot captured during this gate.
Liveness gate test coverage
test-all.mjs
Mode-integrity tests assert that both modes/oferta.md and modes/auto-pipeline.md contain the expected liveness-gate headings and "closed posting evidence" markers, validating the gate documentation is present.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related PRs

  • santifer/career-ops#487: Adds the underlying Playwright liveness probe and --verify flow that identifies and drops expired postings, complementing this PR's documentation of the gate.
  • santifer/career-ops#887: Introduces similar liveness-gate documentation and test assertions for the apply mode, extending the gate pattern across other workflows.

Suggested labels

📄 docs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding liveness gates to prevent dead links from triggering evaluations in oferta and auto-pipeline modes.
Linked Issues check ✅ Passed The PR implements all primary coding objectives from issue #835: liveness gates in auto-pipeline (Step 0.5) and oferta (before Block A), snapshot reuse to minimize re-navigation, and regression tests. The changes comprehensively address the requirement to verify link liveness before evaluation.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #835 objectives: documentation updates to modes, test additions for regression verification, and no unrelated modifications introduced.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

@github-actions

Copy link
Copy Markdown
Contributor

Welcome to career-ops, @maxmilian! Thanks for your first PR.

A few things to know:

  • Tests will run automatically — check the status below
  • Make sure you've linked a related issue (required for features)
  • Read CONTRIBUTING.md if you haven't

We'll review your PR soon. Join our Discord if you have questions.

@maxmilian maxmilian marked this pull request as ready for review June 11, 2026 14:56

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test-all.mjs`:
- Around line 515-528: The test currently checks for presence of liveness gate
strings in ofertaMode and autoPipelineMode (variables ofertaMode,
autoPipelineMode) but not their order; add optional positional assertions to
ensure the liveness gate heading appears before the evaluation start markers:
verify indexOf('## Liveness gate (URL inputs)') < indexOf('Block A') in
ofertaMode and indexOf('## Step 0.5 — Liveness gate') < indexOf('Step 1') in
autoPipelineMode, and only pass when both presence and ordering checks succeed
(update the pass/fail branch that currently calls pass('eval modes ...') /
fail('eval modes ...')).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: e463d7eb-fe54-43d4-b8da-4f6d36fe0ee2

📥 Commits

Reviewing files that changed from the base of the PR and between edc971a and c230119.

📒 Files selected for processing (3)
  • modes/auto-pipeline.md
  • modes/oferta.md
  • test-all.mjs

Comment thread test-all.mjs
Comment on lines +515 to +528
const ofertaMode = readFile('modes/oferta.md');
const autoPipelineMode = readFile('modes/auto-pipeline.md');
if (
ofertaMode.includes('## Liveness gate (URL inputs)') &&
ofertaMode.includes('closed posting evidence') &&
ofertaMode.includes('Do not continue to Block A until this gate is resolved') &&
autoPipelineMode.includes('## Step 0.5 — Liveness gate') &&
autoPipelineMode.includes('closed posting evidence') &&
autoPipelineMode.includes('Do not continue to Step 1 until this gate is resolved')
) {
pass('eval modes (oferta/auto-pipeline) gate dead links before evaluation');
} else {
fail('eval modes missing liveness gate before evaluation');
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | 💤 Low value

Test coverage looks good; consider optional positional validation.

The test correctly validates that both evaluation modes include the required liveness gate documentation elements:

  • Specific heading text for each mode
  • "closed posting evidence" classification criteria
  • Gate resolution requirement before proceeding

The test follows the existing pattern established by the apply mode preflight gate test above it (lines 502-513).

Optional enhancement: The current test checks for text presence but not position. Consider adding a check that the liveness gate heading appears before the evaluation start point (before "Block A" in oferta.md and before "Step 1" in auto-pipeline.md) to ensure the gate actually runs first. However, this is a nice-to-have rather than a requirement, as the current test already validates the contract sufficiently.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test-all.mjs` around lines 515 - 528, The test currently checks for presence
of liveness gate strings in ofertaMode and autoPipelineMode (variables
ofertaMode, autoPipelineMode) but not their order; add optional positional
assertions to ensure the liveness gate heading appears before the evaluation
start markers: verify indexOf('## Liveness gate (URL inputs)') < indexOf('Block
A') in ofertaMode and indexOf('## Step 0.5 — Liveness gate') < indexOf('Step 1')
in autoPipelineMode, and only pass when both presence and ordering checks
succeed (update the pass/fail branch that currently calls pass('eval modes ...')
/ fail('eval modes ...')).

@santifer santifer merged commit ebf9a13 into santifer:main Jun 11, 2026
8 checks passed
@santifer

Copy link
Copy Markdown
Owner

Merged — this closes the loop on #835 (@PaulaBarszcz's report): no more full evaluations + PDFs burned on postings that died yesterday. Token-friendly AND tracker-friendly. With #936, #938 and the #923 fix, that's four merges today, @maxmilian — quietly becoming one of the most productive contributors here. 🚀

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dead links enter pipeline without liveness verification — full eval + PDF generated for expired postings

2 participants