Skip to content
MedCase.

Engineering challenges

Problems, decisions and what each one costs.

Each entry comes from the code. Where the project does not record why something was chosen, the entry says so instead of inventing a reason.

  1. 01

    Multi-case PDFs

    Problem
    Teaching material often bundles several cases in one PDF. A single prompt that splits and extracts at once tends to merge or skip cases.
    Approach
    Detect case boundaries first, then extract each segment in its own call. Non-admin input is capped at 15,000 characters.
    Trade-off
    More model calls per document, in exchange for predictable results and bounded cost.
  2. 02

    Who may touch this case?

    Problem
    Role checks cannot express ownership, shared editing, or soft-deleted records.
    Approach
    A declarative annotation with four access levels, enforced by an aspect that resolves the case before the method runs.
    Trade-off
    Spring AOP only intercepts proxied calls. The limitation is documented on the annotation and covered by aspect tests.
  3. 03

    Hiding the answer

    Problem
    Students must not see the diagnosis before attempting a case, but must see it afterwards.
    Approach
    A reveal policy checks for an assignment submission or graded practice attempt on that case. Embeddings are stripped for everyone who is not staff.
    Trade-off
    The rule lives in one service, so every read path has to go through it. Unit tests cover the policy.
  4. 04

    AI scores teachers can trust

    Problem
    Model output is a draft, not a grade.
    Approach
    A three-state lifecycle (submitted, AI evaluated, teacher evaluated), per-question rubric scores, and teacher overrides that recompute the total.
    Trade-off
    The confidence value is a heuristic over rubric scores and context availability. It is not a calibrated probability.
  5. 05

    One gateway for AI calls

    Problem
    Three services each called the Anthropic API in their own way.
    Approach
    A shared client with prompt caching on the system block, token and cache logging, retry with exponential backoff, and one failure type mapped to 502.
    Trade-off
    Cache hits depend on prefix length and timing. The logs expose them; no measurements are published here.
  6. 06

    Local embeddings

    Problem
    Retrieval should not require a second paid API.
    Approach
    Ollama serves nomic-embed-text locally, with Compose profiles for CPU, NVIDIA and AMD. Ranking is cosine similarity in memory over one case's chunks.
    Trade-off
    Simple and dependency-light, but unsuited to cross-corpus search. The project notes give no formal reason beyond local generation.
  7. 07

    Moving to Keycloak

    Problem
    The project began with its own tokens and later adopted Keycloak.
    Approach
    The decoder tries the backend's own signing key first and falls back to the Keycloak issuer.
    Trade-off
    Two trust paths enlarge the attack surface. Removing the legacy path is a tracked follow-up.
  8. 08

    Notifications off the request path

    Problem
    Sending push messages inline would slow requests and couple domain code to a third party.
    Approach
    Services publish events; async listeners send in batches of 100; a scheduled job reconciles receipts and prunes unregistered device tokens.
    Trade-off
    Events live in process memory, so a crash can lose sends that were not yet accepted by the push service.
  9. 09

    Grades that do not depend on a model

    Problem
    Tumor grades should not rest on a language model's arithmetic.
    Approach
    Gleason/ISUP and WHO grades come from pure, unit-tested calculators. AI only suggests patterns, and each grading records its source.
    Trade-off
    More code than prompting the model, in return for reproducible results.