Skip to content

Instrument PDF generation and make fields optional#513

Merged
stefan-burke merged 5 commits into
mainfrom
pdf-performance-optional-fields
Jul 15, 2026
Merged

Instrument PDF generation and make fields optional#513
stefan-burke merged 5 commits into
mainfrom
pdf-performance-optional-fields

Conversation

@stefan-burke

@stefan-burke stefan-burke commented Jul 15, 2026

Copy link
Copy Markdown
Member

Summary

  • add stage-level PDF performance timing for record loading, cache operations, document generation, layout, images, access tracking, and response handling
  • avoid duplicate image downloads, reuse the rendered footer-photo height, eagerly load unit inspection history, and prevent PDF access timestamps from invalidating caches
  • make manufacturer, user-height counts, vertical walls, step/ramp size, trough depth, and adjacent panel width optional where appropriate
  • remove the obsolete (manufacturer, serial) unique index while retaining per-user serial uniqueness
  • pass explicit unit-form partial locals and internationalise its dimensions display

Testing

  • full RSpec suite: 2,928 examples, 0 failures
  • StandardRB on all hand-maintained changed Ruby files
  • ERB lint on all changed templates
  • Sorbet changed-code check
  • git diff whitespace check

Summary by CodeRabbit

  • New Features
    • Expanded assessment completion to treat additional configured fields as optional, enabling completion when those items are blank.
    • Unit forms now better support optional manufacturer details and display unit size using a clearer meter-based format.
  • Bug Fixes
    • Unit/inspection PDF caching is no longer refreshed when only “last accessed” timestamps change.
    • Unit PDF headers/details now consistently use the most recently completed inspection.
  • Tests
    • Updated and added specs for optional completion behavior and improved PDF generation/caching and logging coverage.

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@stefan-burke, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 2 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9a247efc-a602-44d7-84db-07e9987aa8bd

📥 Commits

Reviewing files that changed from the base of the PR and between 51eeb4f and c38400f.

📒 Files selected for processing (1)
  • spec/services/pdf_generator_service_spec.rb
📝 Walkthrough

Walkthrough

The change adds structured PDF performance instrumentation across controllers, caching, document generation, and image processing. It also makes selected assessment fields optional for completion and updates unit validation, form locals, display formatting, and associated tests.

Changes

PDF performance instrumentation

Layer / File(s) Summary
Performance contract and PDF entrypoints
app/services/pdf_performance.rb, app/controllers/inspections_controller.rb, app/controllers/units_controller.rb
Adds structured timing logs and instruments PDF record loading, generation, response handling, and access tracking.
PDF cache, document, and image measurements
app/services/pdf_cache_service.rb, app/services/pdf_generator_service.rb, app/services/pdf_generator_service/...
Measures cache operations, document sections, rendering, image processing, and attachment downloads while centralizing image download handling.
PDF cache and timing validation
app/models/inspection.rb, spec/features/pdfs/*, spec/services/pdf_*, spec/models/inspection_spec.rb, spec/requests/inspections/inspections_spec.rb
Skips unit-cache invalidation for access-only changes and adds coverage for timing events, cache behavior, image processing, and PDF output.

Assessment completion and unit forms

Layer / File(s) Summary
Optional assessment completion fields
app/models/assessment_schema.rb, app/models/concerns/assessment_completion.rb, config/forms/*assessment.yml, spec/models/..., spec/features/inspections/*
Marks configured fields optional, expands composite field names, excludes them from incomplete fields, and updates related tests and form-attribute validation.
Unit validation and form flow
app/models/unit.rb, app/views/units/*, db/migrate/*, db/schema.rb, config/locales/units.en.yml, spec/features/units/*, spec/models/unit_spec.rb
Makes manufacturer optional, removes the manufacturer/serial index, passes explicit form locals, updates validation messages, revises size formatting, and expands form validation scenarios.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant UnitsController
  participant PdfCacheService
  participant PdfGeneratorService
  participant PdfPerformance
  Client->>UnitsController: request unit PDF
  UnitsController->>PdfPerformance: measure record_load and total
  UnitsController->>PdfCacheService: fetch_or_generate_unit_pdf
  PdfCacheService->>PdfPerformance: measure cache lookup
  PdfCacheService->>PdfGeneratorService: generate unit report
  PdfGeneratorService->>PdfPerformance: measure report sections and rendering
  PdfPerformance-->>Client: structured PDF timing logs
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the two main changes: PDF performance instrumentation and making form fields optional.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pdf-performance-optional-fields

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/models/unit.rb`:
- Line 70: Resolve the mismatch between the model validation and the unique
`(manufacturer, serial)` index around the Unit validations: normalize blank
manufacturer values to NULL before persistence, or revise the index to enforce
the intended per-user serial uniqueness. Add a regression spec covering
identical serials submitted by different users with blank manufacturer, ensuring
the expected validation behavior rather than RecordNotUnique.

In `@app/services/pdf_generator_service.rb`:
- Around line 95-107: Update generate_unit_details_with_inspection to pass the
already loaded last_inspection into HeaderGenerator and TableBuilder, and modify
those helpers to use the provided inspection instead of calling
unit.last_inspection. Preserve the existing behavior when no inspection is
available.

In `@app/services/pdf_generator_service/image_processor.rb`:
- Around line 56-66: Extract the duplicated
PdfPerformance.measure(:image_transcode, **context) block into a shared private
helper, such as transcode_to_png(image, context), and update both
process_image_with_orientation and render_processed_image to call it. Preserve
the existing PNG output and performance context behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c779df99-0cf1-4824-88f1-cfead253ec58

📥 Commits

Reviewing files that changed from the base of the PR and between 3f86352 and b0989cf.

📒 Files selected for processing (30)
  • app/controllers/inspections_controller.rb
  • app/controllers/units_controller.rb
  • app/models/assessment_schema.rb
  • app/models/concerns/assessment_completion.rb
  • app/models/inspection.rb
  • app/models/unit.rb
  • app/services/pdf_cache_service.rb
  • app/services/pdf_generator_service.rb
  • app/services/pdf_generator_service/image_processor.rb
  • app/services/pdf_generator_service/photos_renderer.rb
  • app/services/pdf_performance.rb
  • app/views/units/_form.html.erb
  • app/views/units/edit.html.erb
  • app/views/units/new.html.erb
  • app/views/units/new_from_inspection.html.erb
  • config/forms/structure_assessment.yml
  • config/forms/user_height_assessment.yml
  • config/locales/units.en.yml
  • spec/features/assessment_forms/structure_assessment_trough_fields_spec.rb
  • spec/features/inspections/inspection_incomplete_fields_spec.rb
  • spec/features/pdfs/pdf_integration_spec.rb
  • spec/features/units/units_form_spec.rb
  • spec/models/assessment_schema_spec.rb
  • spec/models/concerns/assessment_completion_spec.rb
  • spec/models/inspection_spec.rb
  • spec/models/unit_spec.rb
  • spec/requests/inspections/inspections_spec.rb
  • spec/services/pdf_generator_service/image_processor_spec.rb
  • spec/services/pdf_generator_service/photos_renderer_spec.rb
  • spec/services/pdf_performance_spec.rb
💤 Files with no reviewable changes (2)
  • app/services/pdf_generator_service/photos_renderer.rb
  • config/locales/units.en.yml

Comment thread app/models/unit.rb
Comment thread app/services/pdf_generator_service.rb
Comment thread app/services/pdf_generator_service/image_processor.rb

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@spec/features/details_links_spec.rb`:
- Line 34: Move the containing_wall_height mutation in the details links setup
before the page navigation, or reload the page after updating it, so the
rendered incomplete-fields links reflect the nil value. Keep the existing
inspection setup and assertions unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5c5510ff-3f9e-46e9-89e3-26e26b4f49d6

📥 Commits

Reviewing files that changed from the base of the PR and between b0989cf and d586a87.

📒 Files selected for processing (5)
  • spec/features/details_links_spec.rb
  • spec/features/inspections/turbo_incomplete_fields_spec.rb
  • spec/lib/form_yaml_database_schema_spec.rb
  • spec/support/test_translations.en.yml
  • spec/support/test_translations.rb

Comment thread spec/features/details_links_spec.rb
@stefan-burke

Copy link
Copy Markdown
Member Author

Addressed all four actionable review threads in 34a0382f:

  • removed the obsolete (manufacturer, serial) unique index and added cross-user blank-manufacturer coverage
  • reused the preloaded inspection throughout unit PDF header/table generation
  • extracted shared image transcoding
  • refreshed the details-link fixture after its database mutation

Verification: 119 focused examples and the full 2,927-example suite pass. StandardRB, Sorbet changed-code checks, and whitespace checks pass.

No change was made for the automated docstring-coverage warning because this repository does not use a docstring requirement and its comments policy discourages boilerplate comments; the changed typed code passes the Sorbet signature check.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/services/pdf_generator_service.rb (1)

95-107: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Order completed_inspections by complete_date

inspection_date can differ from complete_date, so this can pick a different “last” inspection than Unit#last_inspection and make the PDF header/details inconsistent with the rest of the app. Use complete_date: :desc here to keep the same inspection throughout.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/services/pdf_generator_service.rb` around lines 95 - 107, Update the
inspection history query in the PdfPerformance.measure block to order completed
inspections by complete_date descending instead of inspection_date, ensuring
completed_inspections.first matches Unit#last_inspection and keeps the PDF data
consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@app/services/pdf_generator_service.rb`:
- Around line 95-107: Update the inspection history query in the
PdfPerformance.measure block to order completed inspections by complete_date
descending instead of inspection_date, ensuring completed_inspections.first
matches Unit#last_inspection and keeps the PDF data consistent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4abd8edd-5f4d-4e66-bc36-83e3d42f7892

📥 Commits

Reviewing files that changed from the base of the PR and between d586a87 and 34a0382.

📒 Files selected for processing (13)
  • app/models/unit.rb
  • app/services/pdf_generator_service.rb
  • app/services/pdf_generator_service/header_generator.rb
  • app/services/pdf_generator_service/image_processor.rb
  • app/services/pdf_generator_service/table_builder.rb
  • db/migrate/20260715120000_remove_manufacturer_serial_index_from_units.rb
  • db/schema.rb
  • spec/factories/units.rb
  • spec/features/details_links_spec.rb
  • spec/models/unit_spec.rb
  • spec/seeds/seeds_spec.rb
  • spec/services/pdf_generator_service/table_builder_spec.rb
  • spec/services/pdf_generator_service_spec.rb
💤 Files with no reviewable changes (2)
  • spec/factories/units.rb
  • app/models/unit.rb

@stefan-burke

Copy link
Copy Markdown
Member Author

Addressed the follow-up outside-diff ordering comment in 51eeb4f1. completed_inspections now orders by complete_date: :desc, matching Unit#last_inspection, and the regression deliberately reverses inspection-date and completion-date order to verify the most recently completed inspection reaches the unit PDF header/details. The full suite passes: 2,928 examples, 0 failures.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@spec/services/pdf_generator_service_spec.rb`:
- Around line 168-186: Extend the “uses the most recently completed inspection
for unit details” example to also verify the inspection passed into
generate_unit_details_with_inspection or TableBuilder, or assert distinctive
rendered details content from passed_inspection. Keep the existing
HeaderGenerator expectation and ensure the assertion confirms passed_inspection
is used for both the header and unit details.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 30ecea00-2380-40a1-8ac4-b0a6a10fcbb2

📥 Commits

Reviewing files that changed from the base of the PR and between 34a0382 and 51eeb4f.

📒 Files selected for processing (2)
  • app/services/pdf_generator_service.rb
  • spec/services/pdf_generator_service_spec.rb

Comment thread spec/services/pdf_generator_service_spec.rb
@stefan-burke
stefan-burke added this pull request to the merge queue Jul 15, 2026
Merged via the queue into main with commit 6832466 Jul 15, 2026
21 checks passed
@stefan-burke
stefan-burke deleted the pdf-performance-optional-fields branch July 15, 2026 12:59
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