The unfinished AirLife repository in `airlife/` must be productionized as an offline, stateful ETL application over the authentic nycflights13 v1.0.2 materials in `reference/nycflights13/`. Preserve everything under `reference/` byte-for-byte; place all implementation, tests, documentation, generated state, and evidence under `airlife/`.

Expose these stable commands from the `airlife/` working directory:

`python -m airlife_etl ingest --source ../reference/nycflights13 --state state/pipeline.sqlite --output output --months VALUE`

`python -m airlife_etl validate --state state/pipeline.sqlite --dataset output/flights.parquet --rules quality/rules.yaml --report evidence/validation_report.json`

`python -m airlife_etl dashboard --state state/pipeline.sqlite --host 127.0.0.1 --port 8000`

`VALUE` accepts `all` or comma-separated calendar months 1–12. Ingestion must read the packaged `.rda` objects without network access and use the package documentation as the semantic authority. Repeating a month must not inflate facts. Loading older months after newer ones must retain accepted rows, count records earlier than the prior event-time watermark as late, and keep the watermark monotonic. A clean annual build and every eventually complete month ordering must converge to the same canonical dataset. An incompatible or failed run must record its diagnostic and leave the last successfully published dataset intact.

Enrich each flight with airline name, origin and destination airport names, available plane manufacturer/model/year/seats, and weather matching origin plus `time_hour`. Joins must preserve every flight, including cancellations and missing plane or weather matches. Normalize R missing values and timestamp types explicitly; missing values must not become strings.

Publish `output/flights.parquet` using Zstandard compression, no dataframe index, and no volatile metadata. Use nullable Arrow-compatible types, UTC `time_hour`, and a date-typed `flight_date`. Rows are ordered by `flight_date`, `sched_dep_time`, `carrier`, `flight`, `origin`, `dest`, then `flight_key`, with nulls last. Columns, in this exact order, are:

`flight_key`, `flight_date`, `year`, `month`, `day`, `dep_time`, `sched_dep_time`, `dep_delay`, `arr_time`, `sched_arr_time`, `arr_delay`, `carrier`, `carrier_name`, `flight`, `tailnum`, `origin`, `origin_name`, `dest`, `dest_name`, `air_time`, `distance`, `hour`, `minute`, `time_hour`, `plane_manufacturer`, `plane_model`, `plane_year`, `seats`, `origin_temp_f`, `origin_dewpoint_f`, `origin_humidity_percent`, `origin_wind_speed_mph`, `origin_visibility_miles`, `origin_precip_inches`.

`flight_key` is the lowercase SHA-256 hex digest of the UTF-8 string `YYYY-MM-DD|carrier|flight|origin|dest|sched_dep_time`, where `flight` is unpadded base-10 and scheduled departure is four-digit zero-padded. Maintain one row per key with update rather than append-conflict semantics. Repeated clean builds in this environment must produce byte-identical Parquet.

Maintain durable run, schema-event, and quality history in `state/pipeline.sqlite`, exposing at least `pipeline_runs`, `schema_events`, and `quality_results`. Run history must include run ID, start/completion timestamps, status, requested months, source, inserted/updated/duplicate/late/output counts, schema-drift count, event-time watermark, dataset SHA-256, and an error message when applicable. Fingerprint every input schema from ordered field names and normalized logical types. Report compatible additions; removal or incompatible typing of a required field must stop publication with a nonzero status and a persisted diagnostic.

Place executable version-controlled contracts in `quality/rules.yaml`, covering source schemas, key uniqueness and required values, calendar and code domains, row preservation, dimension references, timestamps and schedules, cancellation null behavior, schema compatibility, and reproducible publication. Validation emits UTF-8 JSON with top-level `schema_version`, `run_id`, `dataset_path`, `dataset_sha256`, `overall_status`, and `checks`. Sort checks by `id`; each contains `id`, `stage`, `dimension`, `severity`, `status`, `observed`, `expected`, and `message`. Persist the same results in SQLite.

Document table- and field-level provenance in `docs/lineage.md` and `docs/lineage.json`. The JSON contains `schema_version`, `job`, `sources`, `targets`, and `field_lineage`; every target field identifies its source dataset/fields, transformation, join or derivation semantics, and null policy. Source entries retain local path, publisher, source URL, version or commit, byte size, supplied SHA-256, and license basis. The immutable baseline archives are retained in `reference/source_archives/` for provenance.

The dashboard root page must be self-contained, use no external scripts/fonts/stylesheets/APIs, and render persisted latest-run status and watermark, counts, insert/update/duplicate/late metrics, schema changes, failed checks, dataset hash, run history, and quality charts. `GET /api/health` returns `status`, `database`, and `latest_run_id`. `GET /api/metrics` returns `latest_run`, the latest 20 runs in reverse completion order, latest quality results sorted by check ID, and schema events in reverse detection order. Dashboard values must come from SQLite rather than being recomputed in the web layer.

Include `Makefile` targets `rebuild`, `test`, `validate`, `evidence`, and `dashboard`. `make evidence` must execute the implementation and produce actual command records at `evidence/junit.xml`, `evidence/test_output.txt`, `evidence/validation_report.json`, `evidence/run_summary.json`, `evidence/reproducibility.json`, `evidence/versions.json`, and `evidence/checksums.sha256`. Reproducibility evidence records the two compared run IDs, row counts, dataset hashes, and equivalence boolean. The checksum file uses standard lowercase SHA-256 lines sorted by relative path. The delivered test suite must cover clean construction, repeated and out-of-order ingestion, transactional publication failure, documented nullable values, schema compatibility, persisted quality results, deterministic output, and dashboard APIs. The project must remain runnable after deleting `airlife/output/`, `airlife/state/`, and `airlife/evidence/`.
