Skip to content

Bug: generated court report is bloated by unanswered topic sections (and its guidance text), and interviewee rows have no stable order #7103

Description

@compwron

Re-filed from #6128 (this comment) with enough detail to act on. Reported again by Voices for Children Montgomery in the 2026-08-07 stakeholder sync. Related: #6601, closed by #7006.

Stakeholder's words, from the sync:

when people generate court reports … all the categories are out of order, so it feels kind of like an overwhelming document … even if somebody was not entering information into the category, it was still including that as extra data in the document … it just makes the court report super, super long.

A real example .docx was emailed to Brandon and is being forwarded; it will be attached here when it arrives. You do not need it to start — the repro below reproduces both halves.

Impacted User Types

  • volunteers (they generate the report)
  • supervisors and admins (they read/submit it)

Environment

prod. Word .docx generated by CaseCourtReportsController#generateCaseCourtReportContextCaseCourtReport (Sablon).


Problem 1 — every topic section is printed even when nobody answered it, and each one drags its full guidance text along

CaseCourtReportContext#court_topics builds a section for every active, non-excluded contact topic in the org, whether or not there is an answer in the selected date range:

  • app/models/case_court_report_context.rb:108court_topics does answers: answers_by_topic_id.fetch(topic.id, []), so an unanswered topic gets a section with an empty answer list.
  • app/models/case_court_report_context.rb:122report_topics returns all ContactTopics for the org where exclude_from_court_report: false and (active OR answered).

The template then renders that section anyway. In app/documents/templates/default_report_template.docx:

«case_topics:each(topic)»«=topic.topic»: «=topic.details»
  «topic.answers:each(answer)»«=answer.medium» («=answer.date»): «=answer.value»«topic.answers:endEach»
«case_topics:endEach»

With no answers, the answers loop emits nothing but the heading and topic.details still print. And details is authoring guidance for the volunteer, not report content. See db/seeds/default_contact_topics.yml — the details for "Background information" alone is four multi-line prompts:

a) When did the family first come into contact with the Department of Social Services … b) Tell the history of their involvement … c) Discuss the child's history … d) If child has been placed previously …

Six default topics × that much prose is exactly the "super, super long" / "overwhelming" document the stakeholder is describing — and it is going into a document a judge reads.

Expected behavior

  1. topic.details (the a)/b)/c)/d) prompt text) should not be rendered into the generated report. Its job is to prompt the volunteer on the case-contact form, and it already does that there. Drop it unconditionally — nobody asked for volunteer-facing guidance prose in a court filing, and it's the bulk of the bloat.
  2. A topic with no answers in the selected date range should be omitted from the report — no heading, no guidance, no blank space. Make this controllable rather than a hard flip: add a checkbox to the "Download court report" dialog (app/views/casa_cases/_court_report_modal.html.erb) — "Include sections with no entries"defaulted off. That gives this reporter the short report they asked for while leaving the scaffold-headings behavior from Bug: should show all court report sections in order, and also all sections even if there are not case contacts in them #6601 / fix: show all court report topic sections in creation order (#6601) #7006 available to volunteers who want it.

Spec that encodes the current behavior and will need updating

spec/models/case_court_report_context_spec.rb:272"includes every topic, with an empty answer list for unanswered ones" (and the two "does not include unanswered topics …" examples below it).


Problem 2 — the "Persons Interviewed" table rows come out in whatever order Postgres feels like

There is no ORDER BY anywhere in that path:

  • app/models/case_court_report_context.rb:60filtered_interviewees is a bare CaseContactContactType.joins(...).where(...) with no ordering.
  • app/services/case_contacts_contact_dates.rb:7 — the section order is derived straight from that unordered result set, and the sort is commented out:
contact_type_names = @case_contact_contact_types.map(&:contact_type).map(&:name).uniq # .sort # TODO sort after refactor

That # .sort # TODO has been there since c64e783 (Sep 2021). Consequence: the same case can produce differently-ordered tables on two consecutive generations, and there is no rule a volunteer can predict.

Expected behavior

Deterministic, sensible order. Note the default template's own column header is "Names of persons involved, starting with the child's name", so straight alphabetical isn't quite the intent either. Recommended: order by contact type group name, then contact type name — matching what the case-contact form already does (app/controllers/case_contacts/form_controller.rb:135, .order("contact_type_group.name ASC", :name)) — and float the youth/child contact type to the top if it can be identified. A stable alphabetical order is an acceptable minimum.


Problem 3 — topic section order is DB-id order, and three parts of the app disagree with each other

Where Order used
Court report sections .order(:id) — creation order (app/models/case_court_report_context.rb:127)
Case contact form topic checklist .order(:question) — alphabetical (app/controllers/case_contacts/form_controller.rb:149)
Org settings → Contact topics list no order at all (app/controllers/casa_org_controller.rb:94)

So an admin cannot make the report's section order match the order their court expects, and the order they see while configuring topics is not the order that comes out of the report. A topic that gets deleted and re-added, or added later, silently lands at the bottom of the report.

contact_topics has no position column (db/schema.rb:271).

Expected behavior

Add an explicit position integer to contact_topics, order all three places by it, and let admins reorder topics on the org settings page. Smaller acceptable first step: use one consistent order in all three places.

Note: half of the "out of order" complaint may already be fixed on main

The stakeholder's "sorted by most recently entered" description matches the pre-#7006 code exactly — the old topic query was .order(:occurred_at, :value), i.e. sections were literally ordered by when the volunteer entered data. #7006 changed that to .order(:id) on 2026-06-29. The example doc was generated before that, so first verify what current prod actually produces before assuming the topic-section ordering is still broken. Problems 1, 2 and the three-way inconsistency in Problem 3 are all still present on main as of fb8e868cb.


How to Replicate

  1. Sign in as casa_admin1@example.com / 12345678. Go to org settings → Contact topics. Note there are ~6 topics, each with a long "details" block.
  2. Sign in as volunteer1@example.com / 12345678. Create one case contact on a case, and in the Notes checklist check exactly one topic and type an answer. Save.
  3. Open that case → Generate court report, with a date range that covers the contact.
  4. Open the downloaded .docx:
    • Problem 1: all ~6 topic headings appear, each followed by its full a)/b)/c)/d) guidance paragraph. Five of them have no volunteer content at all.
    • Problem 2: generate a second time on a case with several contact types and compare the "Persons Interviewed" table row order.

Suggested files to touch

  • app/models/case_court_report_context.rbcourt_topics, report_topics, filtered_interviewees
  • app/services/case_contacts_contact_dates.rb — the commented-out sort
  • app/documents/templates/default_report_template.docx — drop «=topic.details» if we go the template route instead of the context route (prefer the context route; org templates are uploaded per-org and we can't edit those)
  • spec/models/case_court_report_context_spec.rb, spec/models/case_court_report_spec.rb
  • Problem 3: migration for contact_topics.position + app/controllers/casa_org_controller.rb, app/controllers/case_contacts/form_controller.rb, app/views/casa_org/_contact_topics.html.erb

Testing notes

Orgs upload their own .docx templates, so the default template is not representative. The real prod templates that show the problem are attached in #6601's comments (prince_george_report_template.docx, montgomery_report_template.docx) — test against those too. Prefer fixing this in CaseCourtReportContext (the data we hand Sablon) rather than in a template, since we cannot edit the templates orgs have uploaded.

Please add a spec that renders a real .docx and asserts an unanswered topic's heading and guidance text are absent from the output.

How to access the QA site

Login Details:
Link to QA site

Login Emails:

password for all users: 12345678

Questions? Join Slack!

We highly recommend that you join us in slack #casa channel to ask questions quickly. And discord for office hours (currently Tuesday 5-7pm Pacific), stakeholder news, and upcoming new issues.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Help WantedLooking for contributorsStakeholder-FeatureFeature requested by stakeholdersType: BugDefect or regression📊 ReportsReports pulled by admins and supervisors

    Type

    No type

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions