# Block G Posting Legitimacy in career-ops: How It Detects Scams and Ghost Jobs

> Discover Block G posting legitimacy in career-ops. Learn how this feature uses 13 signals to detect scams and ghost jobs, ensuring real opportunities.

- Repository: [Santiago Fernández de Valderrama/career-ops](https://github.com/santifer/career-ops)
- Tags: how-to-guide
- Published: 2026-08-20

---

**Block G is a qualitative risk-signal layer in career-ops that evaluates whether a job posting represents a real, active opportunity using 13 independent detection signals, producing a three-tier legitimacy assessment that does not affect the numeric match score.**

Block G posting legitimacy serves as a critical safeguard in the santifer/career-ops open-source project, helping job seekers avoid wasted effort on fraudulent listings, ghost jobs, and misleading employment classifications. Unlike the quantitative Blocks A-F that generate a 1-5 global match score, Block G operates as a separate qualitative assessment defined in [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md).

## What Is Block G Posting Legitimacy?

Block G provides a **standalone legitimacy tier** that classifies job postings into three categories:

- **High Confidence** – posting appears legitimate with no significant risk signals
- **Proceed with Caution** – mixed indicators warrant additional verification
- **Suspicious** – multiple ghost-job or scam indicators detected; investigate before applying

This tier system is defined in [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md) at lines 89-97 and remains completely independent from the numeric scoring system. The separation ensures that technical match quality (Blocks A-F) and posting authenticity (Block G) are evaluated distinctly.

## How career-ops Detects Scams and Ghost Jobs

The detection system runs **13 independent signals** in a weighted pipeline, each evaluated in the order specified in [`modes/oferta.md`](https://github.com/santifer/career-ops/blob/main/modes/oferta.md) at lines 38-45. Below are the core detection mechanisms with their implementation locations and typical red flags.

### Posting Freshness Detection

**Signal 1** uses Playwright browser snapshots to verify active posting status. When the `auto-pipeline` mode is enabled, the system captures date stamps, apply-button states, and redirect behavior.

Typical ghost-job cues: postings older than 60 days, missing or disabled apply buttons, generic redirects to career homepages.

Implementation: [`modes/oferta.md`](https://github.com/santifer/career-ops/blob/main/modes/oferta.md) lines 40-44.

### Description Quality Analysis

**Signal 2** evaluates concrete details versus boilerplate content. The system checks for specific tech stack mentions, realistic team sizes, 6-12 month project scopes, salary transparency, and the ratio of role-specific to generic text.

Red flags include vague copy and overly generic requirements that could apply to any position.

Implementation: [`modes/oferta.md`](https://github.com/santifer/career-ops/blob/main/modes/oferta.md) lines 45-52.

### Company Hiring Context

**Signal 3** performs web searches for recent layoffs or hiring freezes affecting the target company or department, operating under bounded budget constraints.

Implementation: [`modes/oferta.md`](https://github.com/santifer/career-ops/blob/main/modes/oferta.md) lines 54-58.

### Reposting Pattern Detection

**Signal 4** cross-references `data/scan-history.tsv` to identify roles reposted two or more times within 90 days. Repeated reposting strongly suggests a ghost job maintained for talent pipeline harvesting rather than active hiring.

Implementation: [`modes/oferta.md`](https://github.com/santifer/career-ops/blob/main/modes/oferta.md) lines 59-62.

### Role Market Sanity Check

**Signal 5** applies qualitative judgment on whether the role makes business sense: typical fill times, relevance to company operations, and alignment between seniority level and expected engagement duration.

Implementation: [`modes/oferta.md`](https://github.com/santifer/career-ops/blob/main/modes/oferta.md) lines 63-66.

### Employment Classification Risk

**Signal 6** identifies contractor-style terminology (e.g., "1099", "self-employed") combined with corroborating omissions: no benefits mentioned, no PTO, no end date. This catches postings that misrepresent true employment status.

Implementation: [`modes/oferta.md`](https://github.com/santifer/career-ops/blob/main/modes/oferta.md) lines 68-83.

### AI Buzzword Infrastructure Mismatch

**Signal 7** requires two of three sub-checks to flag: high AI buzzword density without supporting team size, missing existing systems infrastructure, or unrealistic technical requirements given stated context. This detects over-promised AI roles on legacy stacks.

Implementation: [`modes/oferta.md`](https://github.com/santifer/career-ops/blob/main/modes/oferta.md) lines 87-99.

### Jurisdiction-Specific Validations

Signals 8-13 leverage **candidate location resolution** from [`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml) to apply targeted legal and regional checks:

| Signal | Check | Data Source |
|--------|-------|-------------|
| 8 | Benefits terminology matches stated location | [`modes/oferta.md`](https://github.com/santifer/career-ops/blob/main/modes/oferta.md) lines 103-110 |
| 9 | Platform location tag matches employer page | [`modes/oferta.md`](https://github.com/santifer/career-ops/blob/main/modes/oferta.md) lines 120-130 |
| 10 | Agency licensing requirements | [`templates/agency-licensing.yml`](https://github.com/santifer/career-ops/blob/main/templates/agency-licensing.yml) |
| 11 | Immigration status requirement legality | [`templates/immigration-status-requirements.yml`](https://github.com/santifer/career-ops/blob/main/templates/immigration-status-requirements.yml) |
| 12 | Jurisdiction-prohibited content | [`templates/jurisdiction-prohibited-content.yml`](https://github.com/santifer/career-ops/blob/main/templates/jurisdiction-prohibited-content.yml) |
| 13 | Pay transparency range width | [`modes/oferta.md`](https://github.com/santifer/career-ops/blob/main/modes/oferta.md) lines 88-96 |

**Signal 8** flags mismatches like "401(k)" appearing in Canada postings. **Signal 13** flags ranges where `top - bottom > 0.5 × bottom`, indicating vague compensation.

## Running Block G Detection

### Single URL Evaluation

```bash
node oferta.mjs --url https://jobs.example.com/12345

```

The CLI outputs structured Block G assessment:

```

## Block G — Posting Legitimacy

| Posting legitimacy | Block G assessment tier | ✅ High Confidence
| Employment classification | ⚠️ contractor-style language: "1099 contractor"
| AI-buzzword mismatch | ⚠️ "AI-enabled" but no infrastructure mentioned

```

### Batch Processing

```bash
cat urls.txt | xargs -n1 -P4 node oferta.mjs --url

```

The [`batch/batch-prompt.md`](https://github.com/santifer/career-ops/blob/main/batch/batch-prompt.md) template (lines 217-235) automatically injects Block G sections into all generated reports.

### Playwright-Enabled Mode

```bash
node auto-pipeline.mjs https://linkedin.com/jobs/view/987654321

```

The `auto-pipeline` mode enables **Signal 1 (Posting Freshness)** and **Signal 9 (Location-Tag Mismatch)**, which require browser snapshots unavailable in text-only `openai-eval.mjs` mode.

## Architecture and Implementation

The Block G detection flow follows this sequence:

1. **Input ingestion** – JD text via paste, Playwright capture, or API fetch
2. **Snapshot generation** – `auto-pipeline` runs Playwright for liveness checks
3. **Jurisdiction resolution** – [`config/profile.yml`](https://github.com/santifer/career-ops/blob/main/config/profile.yml) selects applicable template rows
4. **Signal evaluation** – imperative execution in defined order
5. **Tier aggregation** – weighted reliability mapping per [`_shared.md`](https://github.com/santifer/career-ops/blob/main/_shared.md) lines 98-106
6. **Report generation** – Block G section precedes the Risk Summary

All signals produce **descriptive warnings only** (e.g., "⚠️ Employment classification signal...") without prescriptive legal judgments, maintaining ethical boundaries.

## Key Source Files

| Purpose | File | Lines |
|---------|------|-------|
| Tier definition and weights | [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md) | 89-107 |
| Complete signal specifications | [`modes/oferta.md`](https://github.com/santifer/career-ops/blob/main/modes/oferta.md) | 32-130 |
| Agency licensing data | [`templates/agency-licensing.yml`](https://github.com/santifer/career-ops/blob/main/templates/agency-licensing.yml) | 1-8 |
| Immigration status rules | [`templates/immigration-status-requirements.yml`](https://github.com/santifer/career-ops/blob/main/templates/immigration-status-requirements.yml) | 1-8 |
| Prohibited content per jurisdiction | [`templates/jurisdiction-prohibited-content.yml`](https://github.com/santifer/career-ops/blob/main/templates/jurisdiction-prohibited-content.yml) | 1-8 |
| Batch prompt injection | [`batch/batch-prompt.md`](https://github.com/santifer/career-ops/blob/main/batch/batch-prompt.md) | 217-235 |
| Liveness check implementation | `check-liveness.mjs` | Full file |
| Test coverage | `web/tests/lib/report-sections.test.mjs` | Full file |

## Summary

- Block G provides a **separate qualitative tier** for posting legitimacy, independent of numeric match scores
- **13 weighted signals** detect ghost jobs, scams, and misclassified employment
- **Jurisdiction-aware templates** enable location-specific legal compliance checks
- Playwright-powered `auto-pipeline` unlocks freshness and location-mismatch detection
- All outputs are **descriptive warnings**, not legal advice, with clear source attribution

## Frequently Asked Questions

### Does Block G affect my match score with an employer?

No. Block G operates as a **risk-signal layer completely separate** from Blocks A-F. The numeric 1-5 global score reflects technical and cultural fit only. Block G's High Confidence, Proceed with Caution, or Suspicious tier provides parallel due diligence information without modifying match calculations.

### Can Block G detect every scam or ghost job?

No detection system is perfect. Block G uses **observable signals and pattern matching** rather than definitive proof. According to the source code in [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md), signals are weighted by reliability and combined heuristically. Candidates should treat Block G as **informed assistance**, not absolute protection—especially for novel scam techniques not yet represented in the signal set.

### What triggers the "Suspicious" tier versus "Proceed with Caution"?

The tier aggregation logic in [`modes/_shared.md`](https://github.com/santifer/career-ops/blob/main/modes/_shared.md) lines 98-106 uses a **hard-rule weighted system**. Multiple high-reliability signals (like reposting detection combined with posting freshness failures) push toward Suspicious. Single or lower-reliability signals yield Proceed with Caution. The exact threshold weightings are configurable per deployment.

### How do I add new detection signals to Block G?

Extend [`modes/oferta.md`](https://github.com/santifer/career-ops/blob/main/modes/oferta.md) following the existing signal pattern: define the check logic, specify data sources, and update the weighted reliability table in [`_shared.md`](https://github.com/santifer/career-ops/blob/main/_shared.md). Since the architecture evaluates signals **imperatively in order**, new signals slot into the pipeline at the appropriate detection phase.