# Arcadium Data jobs feed: data dictionary

Feed version 1. Machine-readable copy: `schema.json`. Generated by the exporter, do not edit by hand.

## Layout

`<cut>/<table>/dt=YYYY-MM-DD/part-<HHMMSS>.parquet` and `.jsonl.gz` (same rows). Each cut is a self-contained Hive-style tree, so a buyer of one cut gets one prefix. A run manifest with row counts, sizes and sha256 per file is at `<cut>/_manifests/dt=YYYY-MM-DD/manifest-<HHMMSS>.json` (all cuts: `_manifests/`).

| Cut | Directory | Contents |
|---|---|---|
| global | `global/` | All jobs |
| eu | `region=eu/` | Jobs located in Europe (EU-27, EEA, UK, Switzerland) |
| us | `region=us/` | Jobs located in the United States |
| remote | `remote_only/` | Fully remote jobs (any country) |

Europe = AT, BE, BG, CH, CY, CZ, DE, DK, EE, ES, FI, FR, GB, GR, HR, HU, IE, IS, IT, LI, LT, LU, LV, MT, NL, NO, PL, PT, RO, SE, SI, SK. A job with locations in several countries is in every cut that matches one of them.

**Delta semantics.** Keyed by `job_id`. `new` = the job entered the cut, `updated` = `content_hash` changed (or a closed job reopened), `closed` = the job left the cut (`removal_reason` says why). Apply in part order on top of the latest snapshot to rebuild the open set of any day. `last_seen_at` moves daily and does not trigger `updated`.

**No personal data.** No recruiter, hiring-manager or contact names, no emails or phone numbers. Text fields go through a PII filter before export. Job descriptions are left out by default.

## jobs_delta

Jobs that entered, changed in or left the cut since the previous run. Append-only. Cadence: daily (one part per run; several parts in a dt partition are all valid and ordered by name).

| Column | Type | Null | Description |
|---|---|---|---|
| `change_type` | STRING | no | `new` (job enters this cut), `updated` (content_hash changed, or a closed job reopened), `closed` (job left this cut). |
| `removal_reason` | STRING | yes | For `closed` rows: closed (gone from the board), duplicate (same job found on another source), excluded (employer now out of scope, e.g. a staffing agency), deleted (board removed), left_cut (still open, no longer in this cut). |
| `job_id` | STRING | no | Stable job id `<ats>___<native id>`; the key of every delta row. |
| `title` | STRING | no | Job title as posted (emails, phone numbers and personal profile links removed). |
| `company_name` | STRING | yes | Employer display name (cleaned; careers-page slogans dropped). |
| `company_domain` | STRING | yes | Employer website domain, lower case, without www (null when not matched with confidence). |
| `country` | STRING | yes | Primary country, ISO 3166-1 alpha-2 (first of `countries`). |
| `countries` | STRING | yes | All countries of the job locations, ISO alpha-2, `;`-separated. |
| `locations` | STRING | yes | Location texts as posted, `;`-separated. |
| `remote` | BOOLEAN | yes | true = fully remote, false = on-site or hybrid, null = not stated. |
| `employment_type` | STRING | yes | Employment type as stated by the ATS (full-time, part-time, contract ...). |
| `seniority` | STRING | yes | Seniority level when the ATS states one. |
| `department` | STRING | yes | Primary department or team (first of `departments`). |
| `departments` | STRING | yes | All departments or teams, `;`-separated. |
| `salary_min` | DOUBLE | yes | Lower pay bound, only when the posting states pay in a structured field or a clear text range. |
| `salary_max` | DOUBLE | yes | Upper pay bound (same rule). |
| `salary_currency` | STRING | yes | ISO 4217 currency of the pay range. |
| `salary_period` | STRING | yes | Pay period of the range (year, month, hour ...). |
| `salary_source` | STRING | yes | Where the pay range came from (structured ATS field or posting text). |
| `ats` | STRING | no | Source system the job was read from (greenhouse, lever, workday, smartrecruiters, ...). |
| `language` | STRING | yes | Language of the posting when known (ISO 639-1). |
| `posted_at` | TIMESTAMP | yes | Posting date stated by the employer (UTC); null when the ATS gives none. |
| `updated_at` | TIMESTAMP | yes | Last update stated by the employer (UTC). |
| `first_seen_at` | TIMESTAMP | no | When we first saw the job (UTC). Point-in-time stamp: never moves. |
| `last_seen_at` | TIMESTAMP | no | Last crawl that still saw the job open (UTC). |
| `closed_at` | TIMESTAMP | yes | When the job disappeared from the employer board (UTC); null while open. |
| `url` | STRING | no | Public job posting URL on the employer careers site or ATS. |
| `content_hash` | STRING | no | Hash of the exported fields except `last_seen_at` and `description`; changes = an `updated` delta row. |
| `description` | STRING | yes | Full job description, plain text (only in feeds built with --with-descriptions; off by default). |

## jobs_snapshot

Every open job of the cut at export time. One part per dt partition. Cadence: weekly (and on the first run).

| Column | Type | Null | Description |
|---|---|---|---|
| `job_id` | STRING | no | Stable job id `<ats>___<native id>`; the key of every delta row. |
| `title` | STRING | no | Job title as posted (emails, phone numbers and personal profile links removed). |
| `company_name` | STRING | yes | Employer display name (cleaned; careers-page slogans dropped). |
| `company_domain` | STRING | yes | Employer website domain, lower case, without www (null when not matched with confidence). |
| `country` | STRING | yes | Primary country, ISO 3166-1 alpha-2 (first of `countries`). |
| `countries` | STRING | yes | All countries of the job locations, ISO alpha-2, `;`-separated. |
| `locations` | STRING | yes | Location texts as posted, `;`-separated. |
| `remote` | BOOLEAN | yes | true = fully remote, false = on-site or hybrid, null = not stated. |
| `employment_type` | STRING | yes | Employment type as stated by the ATS (full-time, part-time, contract ...). |
| `seniority` | STRING | yes | Seniority level when the ATS states one. |
| `department` | STRING | yes | Primary department or team (first of `departments`). |
| `departments` | STRING | yes | All departments or teams, `;`-separated. |
| `salary_min` | DOUBLE | yes | Lower pay bound, only when the posting states pay in a structured field or a clear text range. |
| `salary_max` | DOUBLE | yes | Upper pay bound (same rule). |
| `salary_currency` | STRING | yes | ISO 4217 currency of the pay range. |
| `salary_period` | STRING | yes | Pay period of the range (year, month, hour ...). |
| `salary_source` | STRING | yes | Where the pay range came from (structured ATS field or posting text). |
| `ats` | STRING | no | Source system the job was read from (greenhouse, lever, workday, smartrecruiters, ...). |
| `language` | STRING | yes | Language of the posting when known (ISO 639-1). |
| `posted_at` | TIMESTAMP | yes | Posting date stated by the employer (UTC); null when the ATS gives none. |
| `updated_at` | TIMESTAMP | yes | Last update stated by the employer (UTC). |
| `first_seen_at` | TIMESTAMP | no | When we first saw the job (UTC). Point-in-time stamp: never moves. |
| `last_seen_at` | TIMESTAMP | no | Last crawl that still saw the job open (UTC). |
| `closed_at` | TIMESTAMP | yes | When the job disappeared from the employer board (UTC); null while open. |
| `url` | STRING | no | Public job posting URL on the employer careers site or ATS. |
| `content_hash` | STRING | no | Hash of the exported fields except `last_seen_at` and `description`; changes = an `updated` delta row. |
| `description` | STRING | yes | Full job description, plain text (only in feeds built with --with-descriptions; off by default). |

## companies_signals

One row per company and day: open jobs, 7/30-day hiring change, openings, closures, market entries, remote and pay shares, department mix shift, tech stack and event counts. Cadence: daily; every day is kept (the history is the asset). The latest two days are rewritten as they settle..

| Column | Type | Null | Description |
|---|---|---|---|
| `company_domain` | STRING | no | Company website domain (the company key). |
| `company_name` | STRING | yes | Employer display name. |
| `as_of` | STRING | no | Day the signals describe (UTC, YYYY-MM-DD); equals the dt partition. |
| `provisional` | BOOLEAN | yes | true while the company has under 28 days of history: trend columns are not final yet. |
| `history_days` | INT64 | yes | Days since the company was first tracked. |
| `ats` | STRING | yes | Source systems of the company boards, `;`-separated. |
| `boards` | INT64 | yes | Number of job boards folded into the company. |
| `open_jobs` | INT64 | no | Open jobs at the end of the day. |
| `net_change_7d` | INT64 | yes | Open jobs now minus 7 days ago (boards tracked on both days); null until 7 days of history. |
| `net_change_30d` | INT64 | yes | Open jobs now minus 30 days ago; null until 30 days of history. |
| `change_7d_pct` | DOUBLE | yes | net_change_7d / open jobs 7 days ago. |
| `openings_7d` | INT64 | yes | Jobs posted in the 7 days to as_of. |
| `openings_30d` | INT64 | yes | Jobs posted in the 30 days to as_of. |
| `closures_7d` | INT64 | yes | Jobs that disappeared in the 7 days to as_of. |
| `closures_30d` | INT64 | yes | Jobs that disappeared in the 30 days to as_of. |
| `countries` | INT64 | yes | Countries with open jobs. |
| `cities` | INT64 | yes | Cities with open jobs. |
| `new_countries_30d` | INT64 | yes | Countries entered in the 30 days to as_of (market entries). |
| `new_cities_30d` | INT64 | yes | Cities entered in the 30 days to as_of. |
| `remote_share` | DOUBLE | yes | Share of open jobs that are fully remote. |
| `remote_share_change_30d` | DOUBLE | yes | Change of remote_share against ~30 days ago. |
| `posted_pay_share` | DOUBLE | yes | Share of open jobs that state pay. |
| `ghost_share` | DOUBLE | yes | Share of open jobs posted (or first seen) over 90 days ago. |
| `top_department` | STRING | yes | Department with the most open jobs. |
| `department_shift_30d` | DOUBLE | yes | Total variation distance of the department mix against ~30 days ago (0-1). |
| `top_country` | STRING | yes | Country with the most open jobs (ISO alpha-2). |
| `tech_tools` | INT64 | yes | Number of tools named in the open job posts (tech stack). |
| `top_tech` | STRING | yes | Most named tools, `;`-separated. |
| `events_30d` | STRING | yes | Hiring-change events in the 30 days to as_of, `type:count;...` (market_entry, ats_switch, hiring_surge, hiring_freeze, new_department). |
