Skip to content

Fix upload contention, copy filing codes from the EFSP database, and add guided code search - #282

Merged
nonprofittechy merged 5 commits into
mainfrom
fix/upload-and-filing-code-search
Oct 7, 2026
Merged

nonprofittechy merged 5 commits into
mainfrom
fix/upload-and-filing-code-search

Conversation

@nonprofittechy

@nonprofittechy nonprofittechy commented Oct 4, 2026 •

Copy link
Copy Markdown
Member

Uploads could fail with a SQLite write-lock error while a background worker was active, and filing-code discovery made filers work through repeated county codes and near-identical case types. This change fixes local upload contention, copies filing codes from the EFSP's own database on a schedule, and replaces the code lookup with a three-step search that ends in a validated court/category/case-type/filing-type path.

Changes

Upload contention

  • Reserve SQLite writes at transaction start and retry transient extraction-worker lock failures.

Filing codes from the EFSP database

  • Copy codes straight from the EFSP proxy's Postgres codes database (FILING_CODE_SYNC_MODE=database). The queries match the proxy's own filing-catalog export. The court list and every court's tables are read in one READ ONLY, REPEATABLE READ snapshot. Each court is saved as a local copy (FilingCodeCourtCatalog), and the search index is built from those copies.
  • Connect as litefile_codes_reader, a role created for LITEFile on the test EFSP database. It has SELECT on the five code tables only, because the proxy keeps user data in the same database. It is read only at the server through a role setting, which holds even through Supabase's pooler; that pooler ignores connection-level options. LITEFile holds no write credentials.
  • Re-read only courts whose EFSP revision changed. Keep the old copy when a filing court is half updated or suddenly has no filing types. Skip Tyler-internal rows such as Illinois' "System".
  • Run the code index worker daily at FILING_CODE_SYNC_TIME (FILING_CODE_SYNC_TIMEZONE), after the proxy's own Tyler update: 21:30 Eastern on staging, whose test EFSP updates at 19:35. Failed states retry every 15 minutes, and the worker syncs immediately when any jurisdiction has no current index.
  • Add a superuser-only Filing codes page to the staff tools. It shows copy and index status, recent runs, and two buttons: Resync codes and Rebuild code search indexes (from the local copy, without contacting the EFSP). The buttons queue FilingCodeJobs that the worker runs, and each request is audited.
  • Keep the proxy's HTTP bulk export (bulk) and the full crawler (legacy) as fallbacks. Bulk imports still use PostgreSQL COPY and indexed court replacements.

Three-step filing code search

  1. What are you filing? A plain-language search beside a case ZIP. Short chip questions appear when they help:
    • what you want to do (start, respond, ask the court, settle or end, …), with counts
    • kind of case and case category (Cook's divisions), each collapsed to its most used choices
    • claim amount, in any area, labeling small-claims ranges
    • case-specific details, with "Something else" where configured
      Filing-name matches come first, and case-type-only matches sit behind "Show N more". Codes split only by jury, government-filer, or fee qualifiers appear once. Shared name prefixes are muted. A link points to matches in the other case stage ("10 results in 'existing case' filings").
  2. Court and case type. Courts appear as cards (a dropdown above six), with the form's court first. Then the case types, asking only the jury, lawyer, amount, and government questions that court's case types differ on.
  3. Check your choices. The full path, with links back. Applying it revalidates the path with the court.
  • Narrow by ZIP in every state. Massachusetts and Vermont ask MACourts and VTCourts. Other states use a Census ZIP-to-county table (zip_counties.json.gz, rebuilt by scripts/build_zip_counties.py). Courts nothing can place stay visible.
  • Offer the filer's own ZIP and their three most recent case ZIPs as one-click shortcuts, never prefilled.
  • Explain court terms (subrogation, dram shop, tort, …) from a per-state glossary (legal_glossary.yaml).
  • Add sealing synonyms and fix personal-injury, malpractice, and fee waiver classification. A test now rejects duplicate keys in the YAML data files.
  • Keep: grouping repeated filing types and synonyms across courts, contextual facets for 20 civil case families, case-type descriptions, and clearing dependent document, party, and fee choices when the saved classification changes.

Deployment and limits

  • Apply migrations 0033–0037.
  • EFSP_CODES_DATABASE_URL (the read-only role) is staged on litefile-staging and takes effect with this deploy. Production's EFSP database needs the same role; the SQL is in the deployment guide. Production's sync time should be about 04:30 Eastern.
  • The search-rules version changes, so code search shows "not available" until the worker's first full sync of all three states.
  • Locally on SQLite, that first sync took 41.5 minutes and peaked at 532 MB for Illinois (11.6M search paths), 1.5 minutes / 188 MB for Massachusetts, and 2.5 minutes / 193 MB for Vermont. Later runs re-index only changed courts. Postgres saves with COPY, which should be faster, but this path is unmeasured there. Consider 2 GB for the code_index_worker machine.
  • If a proxy schema migration ever recreates one of the five code tables, SELECT must be granted on it again. Postgres lets every role create session-private temporary tables. Those can't touch shared data, and the role's read-only default refuses them.
  • Facets, definitions, and the glossary are discovery aids based on labels and curated sources, not legal determinations. The glossary text needs review before launch.

Validation

  • Full backend suite: 1,638 passed, 2 skipped.
  • Confirm-case browser suite: 45 passed, with Axe audits at zero violations across search states, desktop and mobile. Covers chip questions and their keyboard use, collapsed choice rows, case categories, the glossary, court cards and the dropdown, court-step questions, the other-stage link, ZIP shortcuts, and unavailable paths.
  • General accessibility suite: 21 passed, with zero WCAG A/AA findings.
  • JavaScript unit suite: 72 passed.
  • Ruff, ty, djlint, ESLint (SonarJS), Stylelint, Bandit, and migration checks passed. The documentation production build passed.
  • Live copy and index from the test EFSP database through litefile_codes_reader for Illinois, Massachusetts, and Vermont. The role reads only the five code tables and is refused for DELETE, UPDATE, and CREATE TABLE even with read-only switched off. "Seal eviction" (existing case, ZIP 60603) now finds four sealing and redaction filings. The earlier bulk-import checks on PostgreSQL still stand; the database copy path has run on SQLite only.

🤖 Generated with Claude Code

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Unresolved critical and moderate correctness, data consistency, and deployment issues remain.

Review effort: Lite
Findings: 1 High severity · 1 Medium severity

Open (2)
What changed in this PR

This pull request adds indexed filing-code discovery, guided path selection, and improved SQLite contention handling.

Changes:

  • Adds resumable catalog indexing, grouped search, facets, and path validation.
  • Integrates accessible filing-code search into case confirmation.
  • Adds migrations, workers, deployment documentation, and expanded tests.

Review findings:

  • Critical, 1 vote: filing_code_search.py can raise KeyError due to missing jurisdiction fallback.
  • Moderate: unresolved retry coverage, stale checkpoints, misleading guidance sources, stale classification fields, incomplete search explanations, and Fly worker provisioning.
  • Nit: jurisdiction documentation does not match the current fallback UI.
File Description
testing/​README.md Documents local index-worker usage
fly.toml Adds the production index-worker process
efile_app/​uv.lock Locks the Snowball dependency
efile_app/​tests/​confirm-case-editing.spec.js Adds browser and accessibility coverage
efile_app/​pytest.ini Enables migrations during tests
efile_app/​pyproject.toml Updates dependencies and test configuration
efile_app/​efile/​views/​extraction_review.py Applies classification resets
efile_app/​efile/​tests/​test_sqlite_transactions.py Tests SQLite contention handling
efile_app/​efile/​tests/​test_filing_code_search.py Tests indexing and search
efile_app/​efile/​tests/​test_case_type_guidance.py Tests guidance and facets
efile_app/​efile/​templates/​efile/​extraction_review.html Integrates search assets
efile_app/​efile/​templates/​efile/​components/​filing_code_search.html Adds search dialog markup
efile_app/​efile/​static/​js/​filing-code-search.js Implements guided search interactions
efile_app/​efile/​static/​js/​extraction-review.js Applies validated paths
efile_app/​efile/​static/​js/​court-selector.js Handles court selection
efile_app/​efile/​static/​css/​components/​filing-code-search.css Styles the search interface
efile_app/​efile/​settings_dev.py Configures SQLite transactions
efile_app/​efile/​services/​filing_path.py Resets changed-path dependencies
efile_app/​efile/​services/​filing_code_search.py Builds, indexes, searches, and validates catalogs
efile_app/​efile/​services/​case_type_guidance.py Provides contextual guidance
efile_app/​efile/​models.py Adds catalog and path models
efile_app/​efile/​migrations/​0034_sqlite_filing_search_index.py Adds SQLite FTS5 support
efile_app/​efile/​migrations/​0033_filing_code_search.py Adds catalog schema and PostgreSQL indexes
efile_app/​efile/​management/​commands/​refresh_filing_code_index.py Runs catalog refreshes
efile_app/​efile/​management/​commands/​process_document_extractions.py Retries SQLite lock failures
efile_app/​efile/​data/​filing_concept_definitions.yaml Defines searchable explanations
efile_app/​efile/​data/​filing_code_search.yaml Defines search terms and rules
efile_app/​efile/​data/​filing_code_facets.yaml Defines filing facets
efile_app/​efile/​data/​case_type_guidance.yaml Defines case-family guidance
efile_app/​efile/​api/​urls.py Registers the search endpoint
efile_app/​efile/​api/​filing_code_search.py Implements search and validation APIs
efile_app/​efile/​api/​dropdown_views.py Supports new/existing case timing
docs/​docs/​partners-courts/​jurisdiction-config.md Documents search configuration
docs/​docs/​admin/​deployment.md Documents deployment and workers
compose.yml Adds the local index worker
.github/​workflows/​accessibility.yml Runs expanded accessibility checks

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

config, _ = rules()
phrases = []
for name, concept in config["concepts"].items():
if jurisdiction not in concept.get("jurisdictions", config["jurisdictions"]):
draft.previous_case_id = ""
draft.case_title = ""
draft.optional_services = []
invalidate_fee_quote(draft, save=False)
nonprofittechy and others added 2 commits October 6, 2026 15:13
Stage and validate per-court bulk exports, then replace only changed paths using PostgreSQL COPY or bounded SQLite batches. Recheck the manifest before downloads or removals are published, preserving the previous index on failure.

Add dry runs, forced court imports, and an index for court-scoped replacements. Keep Fly on the existing crawler until the proxy rollout, and start the code index worker from the local launcher.
Filing code search becomes three steps: what you're filing, court and case
type, then a check of the full path. Step 1 pairs the search with a case ZIP
and short chip questions (what you want to do, kind of case, case category,
claim amount, case details), shows strong name matches first, collapses
jury/government/fee code variants, mutes shared name prefixes, explains court
terms from a per-state glossary, and links to matches in the other case
stage. Step 2 asks only the jury, lawyer, amount, and government questions a
court's case types differ on.

ZIP narrowing works in every state: MACourts and VTCourts where configured,
otherwise a Census ZIP-to-county table, keeping courts nothing can place.
Shortcuts offer the filer's own ZIP and their three most recent case ZIPs.
Search rules add sealing synonyms and fix personal-injury, malpractice, and
fee waiver classification.

Filing codes are now copied from the EFSP proxy's codes database over a
read-only role (litefile_codes_reader: SELECT on five code tables, read only
at the server), in one READ ONLY, REPEATABLE READ snapshot, into per-court
copies the index is built from. The code index worker syncs daily after the
proxy's Tyler update (21:30 Eastern on staging), and superusers can queue
"Resync codes" and "Rebuild code search indexes" from the staff tools.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@nonprofittechy nonprofittechy changed the title Fix upload contention and add guided filing code search Fix upload contention, copy filing codes from the EFSP database, and add guided code search Oct 7, 2026
@nonprofittechy
nonprofittechy merged commit f14b30b into main Oct 7, 2026
8 checks passed
@nonprofittechy
nonprofittechy deleted the fix/upload-and-filing-code-search branch October 7, 2026 23:57
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.

2 participants