Offline contract tools
Validate and project job data with Python
Use source-specific, dependency-free scripts to reject malformed canonical rows, validate completion summaries, produce compact display records, or derive the shared table projection.
Choose the source validator first
LinkedIn and EURAXESS share the six-root nomad-agent-job-v1 envelope, but their source identity, custom extension, fields, and availability rules differ. Run the validator bundled with the matching Agent Skill instead of a generic “has title and URL” check.
validate_contract.pychecks the closed canonical row and source-specific contract.validate_run_summary.pychecks the public v4 completion record.parse_output.pyproduces a compact, human-readable representation without replacing the source record.flatten_output.pycreatesnomad-agent-flat-job-v1only for a table destination.
Validate and flatten EURAXESS output
python3 .agents/skills/euraxess-enrich-translate-normalize-scraper/scripts/validate_contract.py actor-output.json
python3 .agents/skills/euraxess-enrich-translate-normalize-scraper/scripts/flatten_output.py \
actor-output.json --output flat-output.jsonUse the LinkedIn skill path for LinkedIn rows. The scripts accept JSON or JSONL; flattening can optionally include a bounded serialized canonical record, but the separate original dataset remains the source of truth.
Integrate the gate into ETL
- Fetch a terminal exact Actor run and its
RUN-SUMMARY. - Validate the summary before the dataset, including the one-retry boundary for scraper v4.
- Fetch and paginate the exact default dataset and reconcile the complete count.
- Run the source-specific contract validator.
- Write the canonical records to durable storage if downstream evidence matters.
- Only then generate flat rows and upsert them by
jobKey.
The Python scripts do not prove build identity or retrieve Apify state; the caller owns those checks.
Fit scoring uses a different adapter
integrations/shared/ai_job_fit_adapter.py validates the closed nomad-ai-job-fit-v1 evaluation and derives nomad-ai-job-fit-destination-v1. It omits ai_failed rows and preserves candidate-safe matchKey.
Do not pass fit evaluations to the normalized-job flat mapper. A fit row includes a complete nested canonical job, but it is a separate candidate-specific result.
Projection is explicit information loss
The flat job view emits primitive fields suitable for Airtable, Sheets, CSV, and relational staging. It cannot preserve every nested requirement, contact, custom source field, raw fact, or provenance detail. It serializes arrays so unknown null remains different from explicitly empty [].
Troubleshooting
- Root keys mismatch: verify the exact Actor/build and that the input file contains dataset items rather than an API wrapper.
- Source mismatch: use the skill matching
identity.source; do not weaken the validator. - Missing
jobKey: the row needs source plus an external ID or fallback URL before flattening. - Encoding or JSONL error: validate that each JSONL line is one complete object and retain UTF-8.