ALL WRITING
White Paper · GitScout · Part 2 of 3

The Moat Is a Pure Function

How "trust is the product" becomes code: an async FastAPI backend, a Next.js frontend, a data model built on a natural bounty key, and a pure-function trust engine that rejects farms and scams before any network call — validated by unit tests and a live re-probe against a real farm.

FastAPISQLAlchemy AsyncNext.jsSecurityTesting
Live App Part 1 Part 3

Part 1 established the thesis: trust is the product. This paper describes how that thesis is implemented — an async FastAPI backend, a Next.js frontend, an SQLAlchemy data model built around a natural bounty key, and a pure-function trust engine that is the moat. We cover the layered scraping pipeline, the security posture, and how each trust rule is validated by unit tests and by a live re-probe against a real farm.

01System architecture

GitScout is a two-tier application deployed across Render (backend) and Vercel (frontend):

Next.js (App Router, TS)  ──HTTP──▶  FastAPI (async)  ──▶  SQLAlchemy async  ──▶  Postgres (Neon) / SQLite
        Vercel                          Render                                       (SSL: require)

Backend layout (backend/app/):

  • api/v1/ — versioned REST surface: bounties, issues, triage, notifications, billing, health, wired through router.py.
  • scrapers/ — the ingestion pipeline: github_client, orchestrator, bounty_extractor, classifier, domain_registry, and the trust engine bounty_trust.py.
  • triage/ — issue intelligence: ast_localizer (free, deterministic AST triage), llm_engine/enhancer (optional LLM enrichment), repro_generator, fix_planner.
  • security/headers.py and rate_limiter.py.
  • dispatcher/ — multi-channel notification (Discord, email, Telegram, WhatsApp).
  • models/, schemas/ — ORM models and Pydantic schemas kept deliberately separate.

02Data model

The model is designed around a natural, collision-proof key rather than a surrogate id:

class Issue(Base):
    __tablename__ = "issues"
    # Natural PK: "repo_owner/repo_name#issue_number"
    id: Mapped[str] = mapped_column(String(255), primary_key=True, index=True)
    ...
    has_bounty:        Mapped[bool]            = mapped_column(Boolean, default=False, index=True)
    bounty_amount_usd: Mapped[Optional[float]] = mapped_column(Float, nullable=True, index=True)
    bounty_source:     Mapped[Optional[str]]   = mapped_column(String(50),  nullable=True)
    bounty_url:        Mapped[Optional[str]]   = mapped_column(String(500), nullable=True)
    hourly_roi:        Mapped[Optional[float]] = mapped_column(Float, nullable=True, index=True)
  • id = "owner/name#number" makes re-ingestion idempotent — the same GitHub issue always maps to the same row, so scrapes can run repeatedly without duplicating data.
  • Bounty fields are nullable and indexed. An issue is an issue first; a bounty is an optional overlay. bounty_amount_usd and hourly_roi are indexed because they are the primary sort keys of the product ("show me the highest-ROI real bounties").
  • bounty_source and bounty_url preserve provenance — every bounty links back to its source of truth, a trust requirement, not a nicety.
  • Async everywhere. create_async_engine with pool_pre_ping and pool_recycle=300; the connection layer switches ssl: require for Postgres/Neon and check_same_thread: False for SQLite so the same code runs in tests and in production.

03The trust engine (bounty_trust.py)

This is the moat. It is a pure module — no network, no I/O — so it is fast, free, and exhaustively unit-testable. It runs before any reputation call. Three layers of defense, in order:

L1
Hard blocklist. Known scam sources rejected outright: bounty-plaza and its owner account are permanently blocked. No heuristics, no appeal.
L2
Structural farm prefilter. Numeric/throwaway owner heuristic, junk-title detection, the engagement/vanity-token gate, and a star gate (MIN_BOUNTY_REPO_STARS = 50).
L3
Reputation assessment for survivors: fork/archived checks and curation against an allowlist of known-good paying orgs (tscircuit, activepieces, onyx-dot-app, …).

The engagement / vanity-token gate

The subtle case is a repo that clears the star gate but still pays nothing real — it rewards social engagement with vanity tokens. The gate encodes exactly that shape:

  • _SOCIAL_TASK_RE — "star the repo," "join our Discord," "follow on X," "post a video."
  • _REAL_CURRENCIES vs _NON_TOKEN_UNITS / _REWARD_TOKEN_RE — distinguishes $, USD, from made-up point tokens ("RTC", "points").
  • _BOUNTY_TAG_RE — crucially, the token check only fires inside a bounty/pool context, so a normal repo that merely mentions a token name is not misclassified.
The safety propertyThe guard is intentionally conservative: it must never reject a real cash bounty. That property is asserted directly by a test.

04Scraping pipeline correctness

Two correctness fixes shaped the pipeline:

  1. Real cash lives behind platform markers, not the raw label. The orchestrator queries algora.io in:body, Funding on Polar in:body, and 💎 Bounty — not bare label:bounty, which is ~40% farm noise.
  2. Separate GitHub-valid passes, then merge (d51ea96). A single over-combined search query can be silently rejected by the GitHub Search API and return zero results. Running each qualifier as its own valid pass and merging makes discovery robust.

05Validation

The trust engine ships with 11 passing unit tests (test_bounty_trust.py), including the three that pin the engagement gate's contract:

  • test_engagement_bounty_detection — a star-for-tokens farm is rejected.
  • test_engagement_filter_spares_real_cash_bounties — a genuine $-denominated bounty is not rejected (the safety property).
  • test_prefilter_rejects_engagement_farms — end-to-end through prefilter_farm.
20 → 0
A real farm (Scottcjn/rustchain-bounties, paying "RTC" tokens for stars) admitted 20 candidates before the gate — and 0 after.
11/11
Trust-engine unit tests green.

Beyond unit tests, the gate was validated by that live re-probe against a real farm — the difference between a rule that passes a synthetic test and one that works on the live web. The wider backend carries a full suite (test_api_*, test_scrapers, test_security, test_ast_localizer, test_dispatcher, test_health), so the trust engine is validated in the context of the running API, not in isolation.

06Security posture

  • Dedicated security/ layer — security headers (headers.py) and a rate limiter (rate_limiter.py), tested by test_security.py.
  • Transport securityssl: require enforced for Postgres/Neon connections.
  • Secret hygiene — a prior incident (real credentials pasted in plaintext into hand-off docs, not committed to git) drove a redaction-and-logging fix and a rotation task. The lesson is documented so it is not repeated: secrets never live in docs, and key material is redacted in logs.
  • Anti-abuse as a first-class concern — the trust engine itself is a security control: it stops GitScout from becoming a distribution channel for a crypto-deposit scam. That is a security property, not merely a data-quality one.

07What this buys the product

The architecture makes the thesis operational: a small, trustworthy feed produced by a cheap, testable, layered filter, with provenance on every row. Part 3 → shows what happens when that engine meets the real bounty market — and why the honest outcome was to not ship a fabricated win.

Code references are to the live backend/app/ tree.