# How `rejection-latency.mjs` Signals Companies Exceeding 30-Day Post-Interview Silence

> Learn how rejection-latency.mjs in santifer/career-ops identifies companies exceeding 30-day post-interview silence, helping you blacklist them effectively.

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

---

**`rejection-latency.mjs` in santifer/career-ops detects silent employers by comparing the most recent interview date to a configurable 30-day courtesy threshold, then emits JSON or markdown suggestions for manual blacklisting without ever writing to files.**

The `rejection-latency.mjs` utility addresses a common job-search frustration: companies that interview candidates then disappear. As implemented in `santifer/career-ops`, this tool implements a **suggest-only contract**—it identifies post-interview silence exceeding the default 30-day window but leaves all decisions to the user. This article explains the detection mechanism, output formats, and practical workflows.

---

## How the 30-Day Silence Detection Works

The script operates as a pure analyzer across two data sources, never modifying any files.

### Data Sources and State Matching

`rejection-latency.mjs` cross-references two markdown ledgers:

- **[`data/active-interviews.md`](https://github.com/santifer/career-ops/blob/main/data/active-interviews.md)** — Contains per-company interview progress with date-stamped round entries
- **[`data/applications.md`](https://github.com/santifer/career-ops/blob/main/data/applications.md)** — Tracks application states; only rows in the **`Interview`** state are considered

The script loads every `Interview`-state entry, then extracts the **latest interview round date** from the corresponding active-interviews record (the most recent timestamp in the interview notes).

### Date Comparison and Threshold Logic

For each candidate record, the script calculates the delta between the last interview date and the reference date:

```javascript
// Conceptual flow based on source lines 38-45 of rejection-latency.mjs
const daysSilent = calculateDays(lastInterviewDate, referenceDate);
const threshold = options.courtesyDays || 30;  // default: 30 days

if (daysSilent > threshold) {
  emitSignal(companyRecord);  // Generate suggestion only
}

```

The **default courtesy window is 30 days**, defined in the script header. Users can override this with `--courtesy-days <N>` for stricter or more lenient thresholds.

### Suggest-Only Output Design

Per the contract documented in [`AGENTS.md`](https://github.com/santifer/career-ops/blob/main/AGENTS.md) at line 114, the tool **never writes to disk**. It emits signals through stdout in two formats:

| Format | Flag | Output |
|--------|------|--------|
| JSON (machine-readable) | *(default)* | Array of objects with `company`, `role`, `lastInterviewDate`, `daysSilent`, and ready-to-paste blacklist line |
| Markdown table | `--summary` | Human-readable table with *Add to blacklist* snippets |

---

## CLI Commands and Practical Workflows

### Basic Usage Patterns

Generate the default JSON report for programmatic processing:

```bash
node rejection-latency.mjs

```

Produce a review-ready markdown table:

```bash
node rejection-latency.mjs --summary

```

Adjust the silence threshold to 45 days:

```bash
node rejection-latency.mjs --courtesy-days 45 --summary

```

Evaluate against a fixed date for deterministic testing:

```bash
node rejection-latency.mjs --today 2026-07-17 --summary

```

Run the built-in test suite (includes a 217-day silent fixture case):

```bash
node rejection-latency.mjs --self-test

```

### Typical Blacklisting Workflow

```bash

# Step 1: Generate human-readable report

node rejection-latency.mjs --summary > latency-report.md

# Step 2: Review suggested entries

cat latency-report.md

# Step 3: Manually copy desired blacklist lines to data/blacklist.md

# (No automated write occurs—user controls all changes)

```

---

## Key Configuration Options

| Option | Default | Purpose |
|--------|---------|---------|
| `--courtesy-days <N>` | 30 | Days of silence before triggering a signal |
| `--today <ISO-date>` | System date | Reference date for calculations (testing/reproducibility) |
| `--summary` | false | Output markdown table instead of JSON |
| `--self-test` | false | Execute validation against fixture data |

---

## Source File Architecture

Understanding the file relationships clarifies how silence detection integrates with the broader career-ops system:

| File | Function | Source Link |
|------|----------|-------------|
| `rejection-latency.mjs` | Core silence detection and signal generation | [View source](https://github.com/santifer/career-ops/blob/main/rejection-latency.mjs) |
| [`data/active-interviews.md`](https://github.com/santifer/career-ops/blob/main/data/active-interviews.md) | Interview round dates and progress notes | [View source](https://github.com/santifer/career-ops/blob/main/data/active-interviews.md) |
| [`data/applications.md`](https://github.com/santifer/career-ops/blob/main/data/applications.md) | Application state ledger (`Interview` filter source) | [View source](https://github.com/santifer/career-ops/blob/main/data/applications.md) |
| [`data/blacklist.md`](https://github.com/santifer/career-ops/blob/main/data/blacklist.md) | Manual destination for rejected companies | [View source](https://github.com/santifer/career-ops/blob/main/data/blacklist.md) |
| [`AGENTS.md`](https://github.com/santifer/career-ops/blob/main/AGENTS.md) | Tool contract documentation (line 114) | [View source](https://github.com/santifer/career-ops/blob/main/AGENTS.md#L114) |
| [`docs/SCRIPTS.md`](https://github.com/santifer/career-ops/blob/main/docs/SCRIPTS.md) | CLI usage examples (line 466) | [View source](https://github.com/santifer/career-ops/blob/main/docs/SCRIPTS.md#L466) |

---

## Summary

- **`rejection-latency.mjs`** scans [`data/active-interviews.md`](https://github.com/santifer/career-ops/blob/main/data/active-interviews.md) and [`data/applications.md`](https://github.com/santifer/career-ops/blob/main/data/applications.md) for `Interview`-state entries with stale activity
- The **30-day courtesy threshold** is configurable via `--courtesy-days` and compares the latest interview round date to today (or `--today`)
- Output is **strictly suggest-only**—JSON or markdown tables emitted to stdout, with no file modifications
- Users manually review signals and optionally append entries to [`data/blacklist.md`](https://github.com/santifer/career-ops/blob/main/data/blacklist.md)
- The tool honors the non-writing contract specified in [`AGENTS.md`](https://github.com/santifer/career-ops/blob/main/AGENTS.md) and supports deterministic testing via date overrides

---

## Frequently Asked Questions

### What happens if a company has multiple interview rounds?

The script extracts the **most recent timestamp** from the interview notes field in [`data/active-interviews.md`](https://github.com/santifer/career-ops/blob/main/data/active-interviews.md). Only the latest round date matters for silence calculation—earlier rounds are ignored.

### Can I automate the blacklisting process?

No—by design. The suggest-only contract in [`AGENTS.md`](https://github.com/santifer/career-ops/blob/main/AGENTS.md) (line 114) explicitly prohibits unattended writes. Users must manually copy suggested entries to [`data/blacklist.md`](https://github.com/santifer/career-ops/blob/main/data/blacklist.md), ensuring intentional decisions about each company.

### How does `--today` differ from the actual current date?

The `--today` flag accepts an ISO-formatted date (e.g., `2026-07-17`) that replaces the system clock for all calculations. This enables reproducible reports and testing scenarios, such as verifying how the tool would have behaved on a past date.

### What companies are excluded from detection?

Any application **not in the `Interview` state** in [`data/applications.md`](https://github.com/santifer/career-ops/blob/main/data/applications.md) is automatically excluded, regardless of [`data/active-interviews.md`](https://github.com/santifer/career-ops/blob/main/data/active-interviews.md) content. Additionally, companies with silence **at or below** the courtesy threshold (default 30 days) generate no signal.