aerocontext-core 0.1.0

Provider-neutral aeronautical-context model and the pluggable ContextProvider contract
Documentation

aerocontext

Pluggable aeronautical-context system: fetch weather/briefing products from provider adapters behind capability traits, then compare them across sources with per-source attribution. Serves a pilot as a briefing and an agent as grounded context.

Crates

  • aerocontext-core — domain model, provider identity/capability traits, cycle-aware navdata snapshots, and compare (cross-source reconciliation). No transport deps.
  • aerocontext-awc — aviationweather.gov Data API adapter (REST/JSON).
  • aerocontext-leidos — Leidos / 1800wxbrief Pilot Web Service adapter (SOAP AreaBriefing).
  • aerocontext-navdata — NASR→snapshot packer: cycle math, versioned blob format, manifest, fetch/ingest pipeline, CLI. The pure slice (cycle/manifest/blob-decode) is wasm-clean; ingest/fetch/cli features are native-only.
  • aerocontext — facade: gather one request across providers, then compare.

Use

let provider: Arc<dyn WeatherBriefingProvider> = Arc::new(AwcClient::new(AwcConfig::default())?);
let briefing = provider.area_briefing(&request).await?;   // request: AreaBriefingRequest
let report = compare(&briefings);                          // who said what, where they disagree

Navigation Data

Identifier-based areas use NavDataSnapshot: a serializable list of airports, waypoints, and navaids tagged with NavDataCycle. NavDataCycle::faa_nasr models the FAA 28 Day NASR Subscription cadence and records the source used to produce the snapshot. Core does not download or cache FAA files; web, WASM, iOS, and CLI shells fetch/cache data through their platform layer and pass the same snapshot into Rust.

aerocontext-navdata produces those snapshots: .acnav blobs built from the NASR CSV subscriber files (current + preview cycle), published per cycle to GitHub Releases by .github/workflows/navdata-publish.yml. Shells bake in one URL — the rolling manifest at releases/download/navdata-manifest/manifest.json — and pick blobs by effective date with Manifest::entry_for (derive "today" in UTC; cycle boundaries are UTC-anchored).

On a user device the same crate is the consumer (cargo install it; the library compiles for wasm32 and iOS with --no-default-features for the pure slice, full features for on-device sync):

aerocontext-navdata sync          # idempotent; run from cron/launchd; --gateway adds IPFS fallback
aerocontext-navdata resolve KSFO --blob "$(aerocontext-navdata current)"

sync follows a subscription list (default: the official manifest; add other sources/authorities as they are published), downloads current + prefetch blobs per authority into ~/.aerocontext/navdata, sha256-verifies every byte, and falls back to an IPFS gateway via the manifest cid when HTTPS fails. Build a cycle from FAA sources yourself:

cargo run -p aerocontext-navdata -- build --cycle current --out dist

Each release also carries a CARv1 archive of the same content for IPFS mirroring; manifest entries record its root cid (IPIP-499 unixfs-v1-2025 profile, pinned ipfs-car under .github/navdata-tools, drift-gated by scripts/cid-guard.sh). HTTPS stays the primary fetch path; the cid is a content address anyone can pin:

curl -LO <car_url from manifest.json>
ipfs dag import faa-nasr-*.acnav.car && ipfs pin add <cid>

A pinning node runs scripts/pin-navdata.sh on a timer: it imports each cycle's CAR, verifies the root CID against the manifest, and republishes one IPNS name pointing at a directory of {manifest.json, blobs}. The IPNS key lives only in that node's kubo keystore — never in CI secrets (the name is the key hash and IPNS has no revocation, so a leaked CI secret would be a permanent hijack; back the key up once with ipfs key export). Devices can then sync entirely over IPFS:

aerocontext-navdata sync --subscriptions subs.json --gateway https://ipfs.io/
# subs.json: { "subscriptions": [ { "name": "us-faa",
#   "manifest_url": "https://ipfs.io/ipns/<name>/manifest.json" } ] }

AWC accepts only coordinate/bbox requests, so attach a snapshot when it needs to serve Area::LocationRadius:

let awc = AwcClient::new(AwcConfig::default())?.with_nav_data(snapshot);

Develop

./ci.sh   # naming guard, fmt, clippy -D warnings, tests, doc, release build

Tests hit mock servers only — no live endpoint. One #[ignore]d live AWC check: cargo test -p aerocontext --test awc_live -- --ignored. Provider wire contracts are pinned by wiremock tests and vendored in reference/.