factcircuit
FactCircuit는 불변 출처와 단계별 검증, 제한된 검색, 재현 가능한 평가를 제공하는 감사 가능한 주장·증거 검증 루프입니다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기A repository orchestrating the Montana Mesonet Air Quality monitoring program
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
This repository archives data nightly from the PurpleAir air-quality sensors at Montana Mesonet stations.
It also publishes derived products:
• hourly summaries,
• EPA-corrected PM2.5, NowCast and AQI,
• a latest snapshot.
Everything is served through the Montana Climate Office data CDN.
• Data:. Start at
manifest.json.
The public data README is at
README.md; its source is
src/mesonet_aq/PUBLIC_README.md.
• Explorer:. The source is docs/.
The bucket (mco-mesonet) is private and cannot be listed. It is readable only through CloudFront (OAC).
Clients enumerate files from manifest.json.README 전문 보기 ↗This repository archives data nightly from the PurpleAir air-quality sensors at Montana Mesonet stations. It also publishes derived products:
Everything is served through the Montana Climate Office data CDN.
manifest.json.
The public data README is at
README.md; its source is
src/mesonet_aq/PUBLIC_README.md.docs/.air-quality/
README.md manifest.json stations.parquet stations.geojson
latest/latest.json latest/latest.parquet
raw/station=<id>/year=YYYY/<id>_YYYY-MM.parquet ~2-min A/B readings, one file per station-month
hourly/station=<id>/year=YYYY/<id>_YYYY.parquet hourly + EPA PM2.5 + NowCast/AQI, one per station-year
The bucket (mco-mesonet) is private and cannot be listed. It is readable only through CloudFront (OAC).
Clients enumerate files from manifest.json.
Every file has one fixed Arrow schema (schema.py), so multi-file reads need no type fixes.
Cache policy:
| Files | Cache-Control |
|---|---|
| Closed months and years | max-age=86400; invalidated if they are ever rewritten |
| Current month and year, indexes | max-age=300 |
The R example is read-archive.R.
EventBridge Scheduler (01:30 America/Denver)
→ ECS Fargate task `mesonet-aq` (image: ECR mesonet-aq:latest, `mesonet-aq run`)
Airtable Deployments → which sensor is at which station since when
PurpleAir history API → each UTC day after the station's `fetched_through`
→ merge into raw station-months → rebuild hourly station-years
→ stations.*, latest/*, manifest.json (written last) → CloudFront invalidation
→ CloudWatch MesonetAQ/RunSucceeded (dead-man alarm → mco-ops-alerts)
| Concern | Where |
|---|---|
| Pipeline code | src/mesonet_aq/, with tests in tests/ |
| Infrastructure | terraform/: ECR, ECS, schedule, task + CI roles, secrets, alarm |
| Bucket and lifecycle | mco-aws stacks/mco-mesonet-bucket (not here) |
| CDN | mco-data-cdn (not here) |
| Explorer hosting | GitHub Pages /docs, proxied at /air by mesonet-gateway |
mesonet-aq run [--since YYYY-MM-DD] [--station ID] # nightly; --since re-fetches (repair/backfill)
mesonet-aq migrate [--station ID] # one-shot: legacy station=/date= tree → this layout
mesonet-aq rebuild-derived # recompute hourly/latest/manifest from raw (no API calls)
The run command handles failures this way:
fetched_through in the manifest.run refuses to start while legacy files exist and no manifest has been written.Run a command on Fargate with the run-task workflow (Actions → run-task).
uv sync
uv run pytest
cp .env.example .env # add PURPLEAIR_API_KEY / AIRTABLE_TOKEN
set -a; . ./.env; set +a
AQ_STORE=/tmp/aq uv run mesonet-aq run --station acebirne --since 2026-10-01 # writes to a local dir
Code: merge to main. build-push.yml pushes :latest and :<sha>, and the next scheduled run uses the new image. No Terraform is needed.
Infrastructure: applies are manual and local (mco-aws ADR 0006):
cd terraform
export AWS_PROFILE=mco
terraform init
terraform plan -out=tfplan # read it: expect 0 to destroy, 0 to replace
terraform apply tfplan
After the first apply, finish setup:
aws secretsmanager put-secret-value; see the header of terraform/secrets.tf.AWS_ROLE_ARN, ECS_CLUSTER, ECS_TASK_FAMILY and ECS_NETWORK.Python ≥ 3.12 and uv. Terraform ≥ 1.10.
MIT