AHMAD:// Available for work — open to remote roles and contracts

← ~/work

CivicShield AI

Shipped APPLICATION

A civic assistant that would rather refuse than hallucinate: retrieval-before-generation, a fail-closed evidence policy, reviewer queues, and a Known-Limitations register that became my documentation standard.

built: 2026-06-28 → 06-29 (48h) role: solo — spec, build, docs, tests stack: Next.js 15 · React 19 · Prisma · PostgreSQL · Better Auth · Groq · Zod repo: 3★ · pushed 1mo ago

> attest CivicShield AI

claims → status → evidence — every row opens something you can check yourself
claimstatusevidence
Refuses to answer when verified evidence is insufficient — pinned in the model's response contract SHIPPED src/lib/ai/prompts.ts
Policy and retrieval test suites run through a zero-dependency custom runner TESTED tests/run.ts
README carries five Mermaid architecture diagrams plus a Known Limitations register DOCUMENTED github.com/ahmadrrrtx/CivicShield-ai

01Why civic answers deserve different engineering

When an assistant explains a benefit program or an urgent support pathway, a confident wrong answer isn't a bug report — it's someone skipping a deadline. So the product constraint came first: the system's default output is "I can't verify this," and every answer must earn its way past that. A 48-hour build, deliberately disclosed: fast because the policy was clear beforehand, not because anything was skipped silently.

02The flow: generation is the last step, not the first

Questions enter retrieval over official-source documents; candidates are validated against Zod schemas into VerifiedEvidenceItems; the model may only see that list, must answer in a typed JSON contract with per-citation traceIds, and its output is refused if it cites anything outside the evidence set. Low-confidence fallback isn't UI sugar — it's the policy's observable surface.

CivicShield-ai/src/lib/ai/prompts.ts the refusal contract as actually shipped in the system prompt view on GitHub ↗
'You must never fabricate facts, citations, departments, dates, URLs, eligibility rules, or trace identifiers.',
 'You must never claim certainty when evidence is incomplete.',
 'Only use the verified evidence provided to you. Do not cite any source outside that evidence list.',
 'If verified evidence is insufficient, set grounded to false, confidence to 0.2 or lower, include the sentence "I cannot confidently verify this information." inside text, and keep citations empty.',

03What's real under the hood

  • Typed provider registry (src/lib/ai/providers/) with fallback — Groq wired as primary, and the abstraction is the reason a second provider is a config change.
  • Conversation state in a single honest 22.8 KB module rather than a framework of interfaces about an interface.
  • Policy + retrieval test suites behind a zero-dependency runner (tests/run.ts) — pass/fail in CI terms, not vibes.
  • Rate limiting on chat, encrypted provider-key storage, security headers; reviewer queue + audit trail for refused queries.
  • Five Mermaid architecture diagrams in the README — the same files this site's diagram lane restyles.

Known limitations — the section that started as an apology and became the standard

  • Better Auth is wired but email verification / OAuth are not enabled. MVP honesty, documented.
  • One active AI provider; the registry's fallback path is tested in isolation, not in traffic.
  • No live deployment — the case study says so instead of shipping a 502 button. Retrieval quality is benchmarked on a seeded corpus, not the open web.
  • Built in 48 hours with heavy AI-tool assist; what I own is the policy design and every reviewed line.

04Aftermath

The Known-Limitations section here became a rule for every repo I touch, including this site's own verifier: if the docs admit the weak parts first, readers trust the strong parts too. That's also why the ledger above this essay lists six claims and not forty adjectives.

ahmad@xr:~% ask — grounded in this site · no LLM, no invented answers

try: