How `rejection-latency.mjs` Signals Companies Exceeding 30-Day Post-Interview Silence
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— Contains per-company interview progress with date-stamped round entriesdata/applications.md— Tracks application states; only rows in theInterviewstate 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:
// 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 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:
node rejection-latency.mjs
Produce a review-ready markdown table:
node rejection-latency.mjs --summary
Adjust the silence threshold to 45 days:
node rejection-latency.mjs --courtesy-days 45 --summary
Evaluate against a fixed date for deterministic testing:
node rejection-latency.mjs --today 2026-07-17 --summary
Run the built-in test suite (includes a 217-day silent fixture case):
node rejection-latency.mjs --self-test
Typical Blacklisting Workflow
# 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 |
data/active-interviews.md |
Interview round dates and progress notes | View source |
data/applications.md |
Application state ledger (Interview filter source) |
View source |
data/blacklist.md |
Manual destination for rejected companies | View source |
AGENTS.md |
Tool contract documentation (line 114) | View source |
docs/SCRIPTS.md |
CLI usage examples (line 466) | View source |
Summary
rejection-latency.mjsscansdata/active-interviews.mdanddata/applications.mdforInterview-state entries with stale activity- The 30-day courtesy threshold is configurable via
--courtesy-daysand 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 - The tool honors the non-writing contract specified in
AGENTS.mdand 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. 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 (line 114) explicitly prohibits unattended writes. Users must manually copy suggested entries to 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 is automatically excluded, regardless of data/active-interviews.md content. Additionally, companies with silence at or below the courtesy threshold (default 30 days) generate no signal.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →