Skip to content

phase-1: CCTNS analyst agent — NL→SQL→Answer#15

Open
singhalvivek wants to merge 4 commits into
mainfrom
feature/cctns-analyst-v0.1
Open

phase-1: CCTNS analyst agent — NL→SQL→Answer#15
singhalvivek wants to merge 4 commits into
mainfrom
feature/cctns-analyst-v0.1

Conversation

@singhalvivek

Copy link
Copy Markdown

Initial build from /zero-shot-build. PR targets main per intentional branch-from-clean-tree — main is boilerplate-only per commit 127bc20, src/ first appears on this feature branch.

Built (Phase 1, smallest user-testable win):

  • 4 capabilities: nl_to_sql, execute_bounded_query, summarize_results, answer_question
  • LangGraph state machine with one self-correction retry on SQL validation
  • Gemini provider (real key), mock CCTNS mirror with ≥ 600 synthetic FIRs across 5 tables
  • FastAPI /v1/answer, /health, static /app/ on :8001
  • Data-locality prompt-spy + full-data correctness (≥ 500 rows, sample≠full) tests
  • 31 tests pass (unit + integration w/ recording-LLM stub)
  • Next.js 15 + Tailwind v4 static export at /app/

DEFERRAL: Phase 2 (history + RBAC) and Phase 3 (live CCTNS connector + audit log) are documented in spec/roadmap.md but not built yet; this PR ships only Phase 1.

- Spec filled for all placeholder files; phase plan laid out across
  P1 (NL→SQL→Answer, 4 caps), P2 (history+RBAC, 3 caps), P3 (live CCTNS,
  3 caps).
- src/cctns_analyst/* scaffolded per project-layout. LangGraph state
  machine with one self-correction retry on SQL validation. Lazy
  FastAPI app factory (no eager SDK import).
- Mock CCTNS mirror with 75 districts, ~600 seeded FIRs across 5
  tables. Tiny SELECT evaluator for Phase 1 SQL subset.
- pyproject.toml + alembic + 0001_initial migration.

NOTE: src/ does not exist on main per latest commit message; this is
the deliberate single-exception bootstrap on feature/cctns-analyst-v0.1.
- 31 unit + integration tests pass (recording-LLM stub for graph E2E,
  full-data correctness, data-locality prompt-spy, bounded query).
- Next.js 15 + Tailwind v4 frontend, static export to frontend/out/.
- Gemini provider fixed to use GenerateContentConfig(system_instruction=…);
  the dict-shape 'contents=[{system},{user}]' was rejected with 400.
- Settings prefix switched to AGENT_* so the existing .env works.
- Playwright e2e suite under tests/e2e/ (run via npm + chromium).
- README + .env.example updated to reflect AGENT_* names.
- gemini.py: use GenerateContentConfig(system_instruction='...'); the
  dict-shape contents=[{role:system},{role:user}] was 400. Verified live:
  Gemini returned proper SQL, mock parser handled
  SELECT COUNT(fir_id) AS fir_count, executor returned rows=[[11]].
- tools/mock_mirror.py: parser recognises any aggregate FN(...)[AS alias].
  Previously only COUNT(*) was recognised; COUNT(col) AS alias was projected
  raw and produced null columns. Now aggregate dispatch returns the
  correct scalar with the aliased column name.
- tests/e2e/playwright.config.ts: use testDir='.' + testMatch so the
  suite can be run via 'npm test' from tests/e2e/.
- Playwright e2e (chromium) passes: page loads, primary input fires,
  real Gemini output renders, Show-SQL toggle works.
- All 31 existing unit + integration tests still green.
@singhalvivek
singhalvivek force-pushed the feature/cctns-analyst-v0.1 branch from fdfc9a3 to d792c9c Compare July 16, 2026 15:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant