Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
76cfd47
feat: load test with measured throughput and tail latency
Prakhar2025 Aug 23, 2026
5999155
feat: champion/challenger shadow model with agreement reporting
Prakhar2025 Aug 23, 2026
c86c005
feat: observability with prometheus metrics, request ids, and drift g…
Prakhar2025 Aug 23, 2026
4fe31a8
feat: per-merchant jwt authn with traffic scoping
Prakhar2025 Aug 23, 2026
5accd16
build: dockerized full stack
Prakhar2025 Aug 23, 2026
50c2afd
feat: postgres engine swap proven in CI
Prakhar2025 Aug 23, 2026
b6ea003
feat: zero-backend static demo snapshot
Prakhar2025 Aug 23, 2026
2294f22
docs: productionization rfc, threat model, runbook, and adrs
Prakhar2025 Aug 23, 2026
77a952b
docs: readme integrates the v2 hardening surface
Prakhar2025 Aug 23, 2026
49cc29e
fix: ci failures across quality, docker, postgres, and secret scan
Prakhar2025 Aug 23, 2026
710ab03
fix: secret scan clean via env-var curl header and gitleaksignore
Prakhar2025 Aug 23, 2026
40d5739
feat: public-demo hardening, live explain endpoint, independent framing
Prakhar2025 Aug 30, 2026
581ebca
fix: freshness hook recognizes a commit that updates the log itself
Prakhar2025 Aug 30, 2026
86da128
docs: all-AWS deployment kit with click-level steps
Prakhar2025 Aug 30, 2026
8b37fc9
docs: playground screenshot, the become-the-ring flow
Prakhar2025 Aug 30, 2026
6640be4
feat: system view rendering the repository's depth in the console
Prakhar2025 Aug 30, 2026
2573338
feat: hand-drawn architecture diagram in the system view
Prakhar2025 Aug 30, 2026
4ac61bd
feat: evaluation protocol diagram and pipeline flow animation
Prakhar2025 Aug 30, 2026
0ef7707
fix: protocol diagram layout aligned, entrance staggered, canvas decl…
Prakhar2025 Aug 30, 2026
f34509b
fix: architecture diagram text fitting and entrance animation
Prakhar2025 Aug 30, 2026
5059473
fix: protocol diagram strings measured to fit their boxes
Prakhar2025 Aug 30, 2026
5b48c96
ci: run the pipeline on v2 pushes as well
Prakhar2025 Aug 30, 2026
e49af12
docs: engineering deep-dive article with cover and architecture art
Prakhar2025 Aug 30, 2026
7af06ce
docs: article diagrams, defense-grade roadmap, zero em dashes, v2 ci …
Prakhar2025 Aug 30, 2026
0de803d
fix: three CI failures at root, coverage raised with real tests
Prakhar2025 Aug 30, 2026
85b9296
fix: postgres insert detection via returning, not rowcount
Prakhar2025 Aug 30, 2026
0872aef
fix: architecture svg spacing and article image syntax
Prakhar2025 Aug 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.git
.venv
__pycache__
data
evaluation
*.db
*.db-shm
*.db-wal
docs
.github
console
node_modules
53 changes: 52 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: CI

on:
push:
branches: [main]
branches: [main, v2]
pull_request:

permissions:
Expand Down Expand Up @@ -37,6 +37,57 @@ jobs:
- name: Tests with coverage
run: python -m pytest -m "not slow and not bedrock"

docker:
name: container stack
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build API image
run: docker build -t sentinel-api .
- name: Boot API and verify serving
env:
SENTINEL_API_KEY: dev-sentinel-key
run: |
docker run -d --name api -p 8000:8000 sentinel-api
for i in $(seq 1 30); do curl -sf http://localhost:8000/healthz >/dev/null && break; sleep 2; done
curl -sf http://localhost:8000/healthz
curl -sf -X POST http://localhost:8000/v1/events -H "X-API-Key: $SENTINEL_API_KEY" -H "Content-Type: application/json" -d '{"event_id":"ci-1","merchant_id":"m1","customer_id":"c1","amount_paise":100,"ts":"2026-08-20T10:00:00+05:30","payment_method":"upi"}' | grep -o '"verdict":"[A-Z_]*"'
docker rm -f api
- name: Build console image
run: docker build -t sentinel-console ./console

postgres:
name: postgres swap
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: sentinel
POSTGRES_DB: sentinel
ports: ["5432:5432"]
options: >-
--health-cmd "pg_isready -U postgres"
--health-interval 5s
--health-timeout 3s
--health-retries 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip
- name: Install pinned dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Postgres integration tests
env:
PGPASSWORD: sentinel
run: |
export SENTINEL_TEST_DATABASE_URL="postgresql+psycopg://postgres:${PGPASSWORD}@localhost:5432/sentinel"
python -m pytest -m postgres --no-cov -q

secrets:
name: secret scan
runs-on: ubuntu-latest
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ Thumbs.db
node_modules/
.next/
out/
console/out/

# Spool files from degraded-mode ingestion
*.spool
console/tsconfig.tsbuildinfo
CLAUDE.md
6 changes: 6 additions & 0 deletions .gitleaksignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Gitleaks false positives: the flagged values are public demo defaults
# (dev-sentinel-key in a CI curl header, then a CI dummy postgres URL),
# not credentials. Historical commits cannot be edited without rewriting;
# the current content uses env vars so no new findings appear.
046547217cbe771646c62adcae94129a8a8d613c:.github/workflows/ci.yml:curl-auth-header:50
50c2afd5bbc4ad81bcb505218e42e20b53a1963c:.github/workflows/ci.yml:curl-auth-header:50
184 changes: 0 additions & 184 deletions CLAUDE.md

This file was deleted.

22 changes: 22 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Abuse-Ring Sentinel API service.
FROM python:3.12-slim AS base

ENV PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1

WORKDIR /app

COPY requirements.txt ./
RUN pip install -r requirements.txt

COPY pyproject.toml README.md ./
COPY src ./src
RUN pip install --no-deps .
Comment on lines +13 to +15

EXPOSE 8000

HEALTHCHECK --interval=10s --timeout=3s --retries=6 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/healthz', timeout=2)"

CMD ["python", "-m", "uvicorn", "sentinel.service:create_app", "--factory", "--host", "0.0.0.0", "--port", "8000"]
19 changes: 18 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: setup check lint format type test test-all console-setup console serve backfill calibrate evaluate models hooks clean
.PHONY: setup check lint format type test test-all console-setup console serve backfill snapshot merchant-token challenger loadtest calibrate evaluate models hooks clean

# One-time setup: virtualenv, pinned deps, git hooks.
setup:
Expand Down Expand Up @@ -51,6 +51,23 @@ serve:
backfill:
.venv/Scripts/python -m sentinel.backfill --limit 20

# Zero-backend static demo snapshot into console/out/ (hostable anywhere, free).
snapshot:
.venv/Scripts/python scripts/make_demo_fixtures.py
cd console && NEXT_PUBLIC_DEMO=1 npx next build

# Mint a per-merchant JWT (default TTL 24h): make merchant-token MERCHANT_ID=mcht_00001
merchant-token:
.venv/Scripts/python -m sentinel.merchant_token $(MERCHANT_ID) $(TTL)

# Train the shadow challenger on train-split features (writes evaluation/challenger.pkl).
challenger:
.venv/Scripts/python -m sentinel.challenger_train

# Load test: measured throughput and latency of the verdict pipeline.
loadtest:
.venv/Scripts/python -m sentinel.loadtest

# Calibrate weights/thresholds on train+calibration splits (writes evaluation/model_config.json).
calibrate:
.venv/Scripts/python -m sentinel.calibrate
Expand Down
31 changes: 23 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

Fraud rings in Indian digital payments do not invent new identities, they **recycle** them: the same device, VPA, and phone hit merchant after merchant until each one individually blocks them. Every merchant sees a clean first-time customer; the fraud only exists *between* merchants. Sentinel builds the identity link graph across the whole population, scores every payment event against it deterministically, and hands the analyst an evidence bundle, not a black-box number.

> Razorpay AI Buildathon, Track 02 (AI Risk Manager). The system recommends, never acts: no autonomous blocking, no money movement, strictly defense-only.
> Designed in response to a public fraud-detection problem statement on cross-merchant identity reuse. The system recommends, never acts: no autonomous blocking, no money movement, strictly defense-only.

## Measured results (held-out test set, seed 42, single pass)

Expand Down Expand Up @@ -63,6 +63,10 @@ make evaluate # calibrates on first run, then: held-out metrics + report
make backfill # seed 1,000 verdicts + top-20 LLM narratives (bounded spend)
make serve # API on http://localhost:8000 (OpenAPI docs at /docs)
make console-setup && make console # analyst console on http://localhost:3000
docker compose up --build # the whole stack in containers (CI-verified)
make challenger # train the shadow challenger; agreement lands in the report
make loadtest # measured throughput/latency of the verdict pipeline
make snapshot # zero-backend static demo into console/out/ (host anywhere)
```

AWS credentials come only from the default credential chain (needed for the Bedrock narrative step and `make models`); everything else runs offline.
Expand Down Expand Up @@ -118,6 +122,16 @@ The queue triages three bands (BLOCK_REC / REVIEW / ALLOW, shown above), every v

Two-key model throughout: a standard key for analyst views and a separate admin key for anything exposing raw identities, with every privileged action written to the audit store under a scope label (never the key value).

## Production hardening (v2)

- **Champion/challenger shadow scoring**: a GBDT challenger records its opinion next to every verdict and never decides; held-out agreement 96.45 percent, promotion gated by four written criteria ([docs/14](docs/14-champion-challenger.md)).
- **Per-merchant JWT authn**: HS256 bearer tokens; a merchant can ingest and read only its own traffic (403 on cross-merchant ingest), enforcing federated privacy at the identity layer.
- **Observability**: `/metrics` in Prometheus text format (request counters, verdict bands, latency histograms, warm-up-aware score-drift gauges) plus `X-Request-Id` correlation on every response.
- **Containers and engines**: multi-stage Dockerfiles and compose for the full stack, built and booted by CI on every push; the same store code runs unchanged on Postgres 16 in a CI service container (SQLite pragmas gated by dialect).
- **Measured capacity**: 178 events/s per worker at p95 15.2 ms; the threaded probe proves process sharding, not threads, is the scale path. The [productionization RFC](docs/15-productionization-rfc.md) derives the 10k events/s plan from these numbers.
- **Zero-backend demo snapshot**: `make snapshot` bakes the whole console into static files, labeled as a recorded run, hostable on any bucket for free.
- Also in /docs: [threat model](docs/16-threat-model.md), [operations runbook](docs/17-runbook.md), and [six ADRs](docs/18-adrs.md).

## Security and defense-only posture

- No real PII anywhere: all data is synthetic by construction, and labels never cross the serving boundary.
Expand All @@ -131,17 +145,18 @@ The full log lives in [`docs/what-broke.md`](docs/what-broke.md), twenty genuine

## Documentation and repository

The complete design suite (problem and loss model, architecture, data design, ML and evaluation protocol with the rupee cost model, API specification, security and DPDP/PCI alignment, and the phase-gated roadmap) is in [`docs/`](docs/README.md).
The complete design suite (problem and loss model, architecture, data design, ML and evaluation protocol with the rupee cost model, API specification, security and DPDP/PCI alignment, and the phase-gated roadmap) is in [`docs/`](docs/README.md). The full engineering story is told in the deep-dive article: **[Sentinel: Catching Fraud Rings That Cross Merchants](docs/blog/engineering-deep-dive.md)**.

```
src/sentinel/ detection engine: normalization, identity graph, features,
scorer, verdicts, calibration, evaluation, LLM layer,
FastAPI service, SQLite audit store
scorer, verdicts, calibration, evaluation, challenger,
auth, observability, LLM layer, FastAPI service, audit store
console/ Next.js analyst console (the watchroom design system)
tests/ 160 tests, 91% coverage, strict mypy, CI-gated
docs/ design suite, what-broke log, screenshots, banner
.github/ CI: lint, strict types, coverage gate, secret scan
scripts/ bounded Bedrock verification, git hooks
tests/ 194 tests, 91% coverage, strict mypy, CI-gated
docs/ design suite, RFC, threat model, runbook, ADRs, what-broke log
.github/ CI: lint, types, coverage, secret scan, docker build, postgres
Dockerfile multi-stage api + console images and compose stack
scripts/ Bedrock verification, demo fixtures, git hooks
```

## License
Expand Down
Loading
Loading