factcircuit
FactCircuit는 불변 출처와 단계별 검증, 제한된 검색, 재현 가능한 평가를 제공하는 감사 가능한 주장·증거 검증 루프입니다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Malayalam-first public project accountability for Kerala. Rust on Cloudflare Workers.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Public project accountability for Kerala: what was sanctioned, who got the contract, what has been paid, how far the work has come. It covers KIIFB projects in all 14 districts from two KIIFB sources, and the Public Works Department's list of finished works still under contractor liability. Every number links to a stored copy of its source.
Live at https://keralakanakku.com (Malayalam) and https://keralakanakku.com/en/ (English). www. and the old kanakku.thesolohacker47.workers.dev address redirect there; POST /admin/ingest works on either host.README 전문 보기 ↗Public project accountability for Kerala: what was sanctioned, who got the contract, what has been paid, how far the work has come. It covers KIIFB projects in all 14 districts from two KIIFB sources, and the Public Works Department's list of finished works still under contractor liability. Every number links to a stored copy of its source.
Live at https://keralakanakku.com (Malayalam) and https://keralakanakku.com/en/ (English). www. and the old kanakku.thesolohacker47.workers.dev address redirect there; POST /admin/ingest works on either host.
The product spec is in kanakku-spec.md. The design of this build is in docs/design.md.
Everything runs on Cloudflare, written in Rust.
| Part | What it does |
|---|---|
crates/core | Pure Rust: the KIIFB parser, flag rules, change diffing, Indian number formatting and the Malayalam/English strings. Tested natively. |
crates/worker | The Worker (workers-rs): server-rendered pages, open-data endpoints and the nightly ingest. |
migrations/ | D1 schema. |
assets/ | Static files: fonts, icons, the share image, and the map script with its two libraries. Pages other than the map load no JavaScript. |
A page is one HTML request with its stylesheet inlined and one D1 round trip. Fonts are self-hosted and cached for a year.
You need Rust with the wasm32-unknown-unknown target, worker-build (cargo install worker-build) and Node.
npm install
npx wrangler d1 migrations apply kanakku --local
npm run dev
.dev.vars needs an INGEST_TOKEN of your choosing, and EDGE_CACHE=off so edits show up immediately. Then load the data:
curl -X POST -H "Authorization: Bearer $INGEST_TOKEN" http://localhost:8787/admin/ingest
The map needs a basemap file in R2. scripts/basemap.sh builds it and explains how to upload it.
These are committed, so you only need the scripts when something changes.
| Script | Writes | Needs |
|---|---|---|
scripts/icons.py | crates/worker/src/icons.rs from Lucide | npm install |
scripts/district.py | crates/worker/src/district.rs, the district outline from OpenStreetMap | network |
scripts/brand.py | share image and app icons in assets/ | Google Chrome, running dev server |
scripts/vendor.sh | map libraries in assets/vendor/ | npm install |
scripts/basemap.sh | tiles/kerala.pmtiles | brew install pmtiles |
scripts/districts.py | crates/worker/src/district.rs (district outlines) | Python 3 |
scripts/constituencies.py | crates/core/src/constituencies.rs | Python 3, a saved dashboard page |
scripts/ogfonts.py | crates/worker/fonts/*.ttf (share-image fonts) | pip install fonttools brotli |
scripts/shot.sh URL out.png WIDTH HEIGHT takes a screenshot with headless Chrome. It cannot go narrower than about 500 px.
cargo test -p kanakku-core
To see what an ingest would store from a saved copy of the dashboard:
cargo run -p kanakku-core --release --example inspect -- page.html '*' 2026-09-30
A cron trigger runs at 02:30 IST. It fetches https://gis.kiifb.org/ once, and only that page. If the data has changed it stores the page in R2, updates the projects that changed and records each changed field. Flags are recomputed on every run, because "overdue" depends on today's date.
The same trigger then reads KIIFB's project status page (https://www.kiifb.org/prjStatus.jsp) through its public form: one request for the district list, then one per project whose figures changed, plus ten of the longest-unchecked, with a second's pause between requests. To run it by hand, capped at 40 work tables:
curl -X POST -H "Authorization: Bearer $INGEST_TOKEN" "https://<your-domain>/admin/ingest?source=status&details=40"
Once a week it also reads the Kerala PWD defect-liability list for the district's divisions (22 requests). To force a read:
curl -X POST -H "Authorization: Bearer $INGEST_TOKEN" "https://<your-domain>/admin/ingest?source=liability"
If KIIFB blocks Cloudflare's addresses, fetch the page from a machine in India and push it instead:
curl -A "KanakkuBot/0.1" https://gis.kiifb.org/ -o page.html
curl -X POST -H "Authorization: Bearer $INGEST_TOKEN" --data-binary @page.html https://<your-domain>/admin/ingest
PILOT_DISTRICT in wrangler.toml is * for the whole state, or one district's name./status shows the last good read of each source; /api/v1/status answers 503 when a source is stale, so any uptime monitor can watch it.npx wrangler secret put ALERT_WEBHOOK.?ref= tags on links we hand out (counted, then redirected away so the tag is not copied onward), and per-page counts for individual projects. Daily totals in visit_counts; top sources and tags on /status. Hand out links like https://keralakanakku.com/?ref=datameet.curl -X POST -H "Authorization: Bearer $INGEST_TOKEN" "https://keralakanakku.com/admin/review?source=dashboard&record=PWD015-69-03&type=overdue" (source=status with a status-page ref for payment flags; add &off=1 to clear). The mark shows on the page and as under_review_since in the API.ALERT_WEBHOOK with the Monday 02:30 IST run. To send one now: curl -X POST -H "Authorization: Bearer $INGEST_TOKEN" https://keralakanakku.com/admin/digest.search_misses), never with who searched. Text that looks like an email address or phone number is not kept. To read them:
npx wrangler d1 execute kanakku --remote --command "SELECT q, surface, SUM(n) AS n FROM search_misses GROUP BY q, surface ORDER BY n DESC LIMIT 50"| Path | What |
|---|---|
/, /d/{district} | Front page for the state and for a district |
/projects, /p/{code} | Dashboard projects; search works in Malayalam |
/funding, /f/{ref} | What KIIFB approved and what has been paid |
/liability | Finished PWD works still under contractor liability |
/contractors, /c/{key} | Contractors across the sources |
/agencies, /a/{key} | Implementing agencies |
/og/p/{code}.png, /og/f/{ref}.png | Share images, drawn on request |
/status, /methodology, /data, /map | Health, method, downloads, map |
/about | Who runs it, corrections, takedown requests, privacy, accuracy and use, licences. The contact shown is CONTACT in wrangler.toml |
/press | Two-minute brief for journalists, with live figures and the payment-listing finding explained |
Everything is under /api/v1/, described in full at /api/v1/openapi.json (a static file in assets/api/v1/). Full downloads: projects, funding, liability (JSON and .csv), projects.geojson, projects/{code}. Paged, 500 rows a page with a next link: changes?since=yyyy-mm-dd, flags?status=open|cleared|all&type=…, snapshots?source=1|2|3; all three take district=. Version 1 only grows; a breaking change would be /api/v2/.
license and attribution.