Skip to content

fix: resolve 5 critical architectural issues (race condition, name-based PDF fill, AppError handler, OLLAMA_MODEL env var)#193

Open
Gopisokk wants to merge 2 commits intofireform-core:mainfrom
Gopisokk:fix/critical-arch-fixes
Open

fix: resolve 5 critical architectural issues (race condition, name-based PDF fill, AppError handler, OLLAMA_MODEL env var)#193
Gopisokk wants to merge 2 commits intofireform-core:mainfrom
Gopisokk:fix/critical-arch-fixes

Conversation

@Gopisokk
Copy link

@Gopisokk Gopisokk commented Mar 5, 2026

Summary

Resolves 5 architectural issues identified by auditing the full codebase.


Changes

fix(filler) — Replace fragile index-based PDF filling with name-based matching

  • Previously: annot.V = answers_list[i] — matched purely by position/index
  • Now: reads annot.T (the PDF field label), decodes the PDF string, looks up value directly in the LLM answers dict (case-insensitive)
  • None → writes "" (not the string "None"), list values → joined with "; ", unmatched fields → warning log instead of silent wrong fill

fix(file_manipulator) — Eliminate race condition from shared mutable LLM state

  • Previously: one LLM() instance in self.llm was mutated per-request — a data corruption race condition under concurrent requests
  • Now: a fresh LLM(transcript_text=..., target_fields=...) is created inside fill_form(), scoped to each request
  • Also converts the silent return None on missing PDF to a proper FileNotFoundError

fix(forms) — Remove duplicate get_template() DB call

  • get_template() was called twice per request — doubled DB round-trips for every fill
  • Now fetched once, stored, reused
  • FileNotFoundError is caught and surfaced as a 422 response

fix(main) — Register AppError exception handler

  • register_exception_handlers(app) was defined in api/errors/handlers.py but never called in api/main.py
  • Every AppError raise (e.g. 404 Template not found) produced an unhandled 500 crash instead of a proper JSON error

fix(llm) — Make Ollama model configurable via OLLAMA_MODEL env var

  • Model name was hardcoded to "mistral" — operators had to edit source code to change it
  • Now reads os.getenv("OLLAMA_MODEL", "mistral") — backward compatible, defaults to "mistral"
  • Moved host/model resolution outside the per-field loop (was being re-evaluated on every iteration)

Relates to: #44

Gopisokk added 2 commits March 5, 2026 23:07
- fix(filler): replace fragile index-based PDF filling with name-based matching
  Field names from annot.T are now decoded and looked up directly in the LLM
  answers dict (case-insensitive). Plural list values are joined with '; '.
  Unmatched fields are logged as warnings instead of silently filling wrong fields.

- fix(file_manipulator): eliminate race condition from shared mutable LLM state
  Removed the shared self.llm instance. A fresh LLM(transcript_text, target_fields)
  is now created per-request inside fill_form() to guarantee full isolation under
  concurrent requests. Also replaced silent 'return None' with FileNotFoundError.

- fix(forms): remove duplicate get_template() DB call (N+1)
  The template was fetched twice per request; now fetched once, stored, and reused.
  FileNotFoundError from FileManipulator is caught and converted to 422 AppError.

- fix(main): register AppError exception handler
  register_exception_handlers(app) was defined but never called, causing AppError
  raises (e.g. 404 Template not found) to produce unhandled 500 crashes instead
  of clean JSON error responses.
The model name was hardcoded to 'mistral' on line 57, meaning any operator
who wanted to use llama3, phi3, or another model had to edit source code.

Changes:
- Read model from os.getenv('OLLAMA_MODEL', 'mistral') — backward compatible,
  defaults to 'mistral' when env var is not set
- Move ollama_host, ollama_url, and ollama_model resolution outside the per-field
  loop — they are constant for the whole request and were being re-evaluated on
  every iteration unnecessarily
- Remove stale commented-out dead code (old hardcoded URL line)
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