How analyze-patterns.mjs Identifies Trends in Rejection Reasons and Application Success
analyze-patterns.mjs parses the master application tracker, normalizes status values against a canonical schema, and computes statistical aggregates to surface which rejection reasons occur most frequently and which role keywords correlate with offers.
The analyze-patterns.mjs script is the pattern-analysis engine of the Career-Ops repository. It transforms raw application history into actionable intelligence by quantifying why jobs are rejected and what factors drive successful outcomes. This lightweight JavaScript module operates without external dependencies, making it portable across any environment where the Career-Ops repository is cloned.
Data Ingestion from the Master Tracker
The script begins by reading data/applications.md, which stores the complete application history in a markdown table format.
analyze-patterns.mjs splits the markdown table and converts each row into a structured record containing fields for date, company, role, status, score, and notes. This parsing step creates a machine-readable dataset from the human-friendly tracker, enabling downstream statistical operations.
// Conceptual flow of the ingestion phase
const records = parseTracker('data/applications.md');
// Each record: { date, company, role, status, score, notes }
Signal Extraction and Status Normalization
Once ingested, the script normalizes status values against the canonical state list defined in templates/states.yml. This ensures that custom status text (such as "Declined" or "Pass") maps to standard tokens like Rejected, Discarded, Offer, or Applied.
For rejection reason extraction, the script inspects the notes column whenever the normalized status is Rejected or Discarded. It identifies keywords such as "salary", "culture", or "lack-of-experience" and stores these as rejectionReason attributes. Similarly, it marks records with Offer status or high scores as success signals, capturing the role and company context for each positive outcome.
Statistical Aggregation and Trend Calculation
The core analysis logic builds two primary frequency maps:
rejectionCounts[reason]– Tally of rejections grouped by extracted reasonsuccessCounts[roleKeyword]– Count of offers grouped by role keyword (derived from job title parsing)
The script then calculates percentages relative to total applications and ranks the top-N items by frequency. It also groups data by dimensions such as company, role category, keyword, and time window (weekly or monthly) to surface temporal trends.
// Aggregation logic within analyze-patterns.mjs
const trends = [
{ type: 'RejectionReason', label: 'salary-mis-match', count: 14, percentage: 28 },
{ type: 'SuccessKeyword', label: 'machine-learning', count: 5, percentage: 12 }
];
JSON Output Generation
The computed aggregates are serialized to output/patterns/patterns.json. This JSON payload contains a list of trend objects, each specifying the type (rejection or success), label, count, and percentage.
Other Career-Ops modules—including the follow-up cadence script—consume this file to suggest improvements. For example, if salary-mis-match appears in 28% of rejections, the system might recommend researching market rates before the next application wave.
import fs from 'fs';
const trends = JSON.parse(fs.readFileSync('output/patterns/patterns.json', 'utf8'));
for (const t of trends) {
console.log(`${t.type}: ${t.label} → ${t.percentage}% (${t.count} occurrences)`);
}
Running the Analysis
Execute the script from the repository root to regenerate trend statistics:
node analyze-patterns.mjs
This command reads the current state of data/applications.md and produces fresh aggregates in output/patterns/. Because the script is pure JavaScript with no external dependencies, it runs on any Node.js environment without additional package installation.
Summary
analyze-patterns.mjsserves as the statistical engine for the Career-Ops repository, converting application history into quantified trend data.- The script reads from
data/applications.md, normalizes statuses usingtemplates/states.yml, and extracts rejection reasons from the notes field. - It computes frequency maps for rejection reasons and success keywords, calculating percentages and ranking top-N trends.
- Results are exported to
output/patterns/patterns.jsonfor consumption by other tools or manual review. - The architecture is stateless and portable, allowing re-execution at any time to track how patterns evolve as new applications are added.
Frequently Asked Questions
How does analyze-patterns.mjs handle inconsistent status labels?
The script references templates/states.yml to map any custom status text to canonical tokens such as Rejected, Offer, or Applied. This normalization ensures that variations like "Declined" or "Not Moving Forward" are counted consistently under the Rejected category.
What specific rejection keywords does the script detect?
The extraction logic scans the notes column for terms such as "salary", "culture", and "lack-of-experience". These keywords are stored as rejectionReason values and aggregated in the rejectionCounts map to calculate frequency percentages.
Where are the trend statistics stored after analysis?
The script writes a JSON file to output/patterns/patterns.json. This file contains trend objects with type, label, count, and percentage fields, which can be imported by visualization tools or other Career-Ops automation scripts.
Can I run analyze-patterns.mjs without installing dependencies?
Yes. The script is implemented in pure JavaScript with no external dependencies beyond Node.js itself. Simply run node analyze-patterns.mjs from the repository root after cloning santifer/career-ops.
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 →