tts-tax-app

●live active dev

Professional tax preparation software for small/mid accounting firms

README

No README.

STATUS

# TTS Tax App — Status

## Last updated
2026-06-03

## Currently in progress
- (none — seed-collision fix pushed to origin/main 2026-06-03.)

## Last session recap (2026-06-03 #2) — test_dependents seed-collision fix

Fixed the FormDefinition seed-collision that threw `UniqueViolation` and
triggered the 17h pooler hang. Test-infrastructure only — no compute,
renderer, or form logic touched.

- **Root cause:** module-scoped `django_db_blocker.unblock()` + `seed_1040`
  fixtures commit a `(1040, 2025)` FormDefinition that leaks across the
  pytest session; raw `FormDefinition.objects.create(code="1040",
  tax_year_applicable=2025)` in 4 files then collided on
  `unique_together (code, tax_year_applicable)`.
- **Fix:** `get_or_create` at the 4 colliding sites (`test_dependents`,
  `test_w2_employer_learning`, `test_employers_api`,
  `test_import_lacerte_clients_cmd`) + made
  `test_missing_form_definition` arrange its own "no 1040 form"
  precondition.
- **Verified:** RED reproduced (UniqueViolation, no hang); fix → 13/13
  isolation, 63/0 on the polluted collision-order set, and the live full
  run's 22% cluster (was `EEEEEEF`) now clean. Full pooler run (~5h) left
  running as background confirmation; committed on the proven evidence
  per the same gate-waiver rationale as Part III.
- See "Known issues / blockers → ✅ RESOLVED" for full detail, including
  the still-present root pollution (folded into the test-DB task).

## Last session recap (2026-06-03) — Part III push closeout (back on D: machine)

Finished the close-out for the Part III work that was committed+merged to
**local** main on the borrowed V: machine but never pushed.

### What happened
- **Rebuilt the broken venv.** The `server\.venv` built on the V: machine
  was pinned to `C:\Users\Ken\...\Python313\python.exe` (user "Ken"),
  which doesn't exist on this machine (user "Ken2"). Deleted it. Poetry's
  own cached env (`...\virtualenvs\tts-tax-server-oXVY_DSk-py3.13`,
  Python 3.13.7) is valid here and i

…(truncated for upload size)

DECISIONS

# TTS Tax App — Architecture Decisions & Standards

## Tech Stack (Locked)
- Backend: Django 5.2 LTS + Django REST Framework
- Frontend: Vite + React 19 + TypeScript (SPA)
- Styling: Tailwind Plus (no hardcoded colors)
- Database: Supabase Postgres 17.6 (session pooler, IPv4)
- Hosting: Render.com (Virginia)
- Serving: Django + WhiteNoise (same origin)
- Dependencies: Poetry (Python 3.13), npm (client)
- PDF: ReportLab + pypdf + pymupdf
- AI: Gemini (IRS-grounded RAG)
- Grid: Hand-rolled Tailwind tables (no third-party grid library)
- Web-only. No Electron. No Docker. No SQLite in production.

## Architecture Decisions
Do not change without discussing with Ken first.

### 2026-06-02 — Schedule 1-A Part III overtime: premium-only, placeholder-sourced, no attestation boolean

**Decision:** Part III (No Tax on Overtime, OBBBA §70202) is computed in
`apps.returns.compute_sch_1a._compute_part_iii_overtime`, mirroring the
Part II tips structure with three deliberate differences.

**1. "Qualified overtime compensation" is the FLSA premium portion only.**
Per OBBBA §70202 / IRC §225, the qualified amount is the half-time
premium paid in EXCESS of the regular rate — NOT gross overtime pay. The
form face (line 14a) says "qualified overtime compensation included in
Form W-2, box 1" and defers the definition to the instructions. Because
Box 1 holds gross wages (the premium is included but not separable), we
do NOT derive 14a from any modeled W-2 field. Line 14a (and 14b for
1099 sources) are **preparer-entered placeholders** holding the
employer-reported qualified amount, split per filer. This sidesteps the
gross-vs-premium trap entirely (entering gross OT would badly overstate
the deduction).

**2. No occupation/SSTB attestation boolean.** Unlike tips (which gate
on `tips_eligible_for_deduction` for the tipped-occupation + non-SSTB
rule), Part III's only preconditions are a valid SSN (taxpayer and/or
spouse) and MFJ-if-married. So migration 0044 adds only amount fields —
`qual

…(truncated for upload size)

MEMORY

# TTS Tax App - Project Memory

## 2026-06-03 #2 — test_dependents FormDefinition seed-collision fixed

Fixed the test-ordering / seed-collision bug that produced `UniqueViolation`
and triggered the 17h pooler hang. Test-infrastructure only.

### Standing facts established this session

- **The seed-collision root cause: module-scoped `unblock()` seed fixtures
  commit and leak.** The sch_1a / sch_8812 / f1040-audit test files use
  `@pytest.fixture(scope="module") def seeded_forms(django_db_setup,
  django_db_blocker)` with `django_db_blocker.unblock()` +
  `call_command("seed_1040")`. Because `unblock()` runs OUTSIDE the per-test
  transaction, the `(code="1040", tax_year_applicable=2025)` FormDefinition
  is **committed** and persists for the whole pytest session. `seed_1040`
  is idempotent (update_or_create) so the seed fixtures coexist — but any
  **raw** `FormDefinition.objects.create(code="1040", tax_year_applicable=2025)`
  collides on `unique_together (code, tax_year_applicable)`.
- **Fix applied: `get_or_create` at the 4 colliding raw-create sites** —
  `test_dependents.py:35`, `test_w2_employer_learning.py:47`,
  `test_employers_api.py:173`, `test_import_lacerte_clients_cmd.py:25`.
  Sites with unique codes (`1040_box`, `1040_w2exp`, `1040_int`,
  `1040_other`, `1120-S-link/clear`) were never at risk.
- **The "12 test_w2_employer_learning errors" the Session K baseline blamed
  on pooler stickiness were actually THIS collision** — `test_f1040_audit`
  (alphabetically before `test_w2_*`) commits `(1040,2025)`, then
  `test_w2_employer_learning`'s raw create collided. Now fixed.
- **Second symptom: absence-assertions also break under the pollution.**
  `test_import_lacerte_clients_cmd::TestErrors::test_missing_form_definition`
  asserts the 1040 form is absent → expects `CommandError`; the committed
  pollution made it present (`DID NOT RAISE`). Fixed by arranging the
  precondition in-test (`FormDefinition.objects.filter(code="1040").delete()`,
  rolled b

…(truncated for upload size)

CLAUDE.md

# TTS Tax App — Project Instructions
*Last updated: 2026-04-24*

## Owner
Ken — CPA, The Tax Shelter, Athens, Georgia. ~3,000 clients/year, ~9 preparers.
Building a unified tax practice platform (Sherpa) to replace fragmented SaaS tools
and potentially sell to other firms by ~2027.

## This Repo
`tts-tax-app` — The income tax preparation module. This is the **primary
development focus** of the entire Sherpa platform.

Local path: `D:\dev\tts-tax-app`

## Current Stack (What Actually Exists — Do Not Change Without Discussion)
| Layer | Technology |
|-------|-----------|
| Server | Django 5.2 LTS + Django REST Framework |
| Database | Supabase Postgres 17.6 |
| Web Client | Vite + React + TypeScript (SPA served by Django) |
| Styling | Tailwind UI / Tailwind Plus |
| Hosting | Render.com (Django + WhiteNoise serves SPA) |
| Dependency Mgmt | Poetry (Python 3.13) |
| AI Help | Gemini (IRS-grounded RAG + broad search) |
| PDF Rendering | ReportLab + pypdf + pymupdf over official IRS templates |

## Project Rules (enforced)
- **No PII in committed code** — never put real SSNs, names, addresses, or other
  client PII into source files, test fixtures, migrations, seed data, or git
  history. Use synthetic/fake values for anything checked in.
- **Dev environment shares the production DB.** `server/.env` points Django at the
  Supabase project `tmqypsbmswishqkngbrl`, which is shared with the sherpa-1099
  production app and already contains ~700 real clients (as of 2026-04-21). Treat
  any DB write as a production operation. When importing new test data, prefer
  sanitization (fake SSNs/names, real dollar amounts) over raw imports to limit
  blast radius from dev-time mistakes. See Cowork memory `project_tts_dev_points_at_prod.md`
  for full context.
- **No secrets in repo** — all credentials via `.env` (which is gitignored).
- **Migrations required** — every model change needs a migration.
- **Tests required** — every ticket must include tests; tests must pass before merge.

…(truncated for upload size)

Diary mentions

No recent diary mentions for this app.

Render