07 — Make report and resolution generation retry-safe outbox effects
## Objective Case/meeting closure reliably generates existing reports and resolutions without duplicate resolutions or overwriting newer/manual state on delayed retry. ## Evidence and locations app/models/case.rb: voting_engine_end_integrations!, generate_reports, create_resolution. Report errors are swallowed outside development; create_resolution creates a fresh Resolution each invocation. Existing Reporting::ProceedingsBuilder and Reporting::VotingBuilder must be reused. Call sites: Secretary::CasesController, MeetingsController, EndMeetingsJob and API::CloudRouterCallbacksController. Proposed report consumer under app/services/voting_engine/outbox/. ## Changes - Plan report/resolution work as a distinct effect, separate from router/streaming and UI delivery. - Remove report generation from engine post-command controller/job continuation after the consumer is wired. Preserve existing public-case, resolution-enabled and auto-publish rules. - Reuse builders, surface failures and use strict persistence in the durable path. Atomically persist generated case fields, resolution/link creation and delivery completion in one local transaction; rollback leaves work retryable. - Deduplicate by event/effect identity, not only broad case identity: repeat delivery of the same closure cannot create another resolution. Preserve legitimate later case lifecycles. - Capture sufficient lifecycle/optimistic context to detect reset, newer closure and intervening manual protocol edits. Do not overwrite newer/manual reports. Record explicit obsolete/blocked outcome for operator review instead of pretending a send succeeded or blindly re-running current-state builders against the wrong lifecycle. - Ensure model callbacks from report persistence do not introduce an untracked delivery chain. Route required resulting UI refresh through the shared presentation plan, with durable ownership. ## Acceptance and tests Proposed spec/services/voting_engine/outbox/report_consumer_spec.rb plus existing spec/services/reporting suites and closure entrypoint specs. Cover successful report+resolution once, repeated job/receipt replay, failure between report/resolution/link/completion writes, retries, disabled/private cases, end_meeting nested closure, reset/restart before delivery, later manual edits, and no report generation on command rollback. Run bundle exec rspec spec/services/voting_engine/outbox/report_consumer_spec.rb spec/services/reporting spec/jobs/end_meetings_job_spec.rb; RuboCop changed Ruby. ## Depends on https://task.matda.me/tasks/tsk_2qravp6n9b — effect identity/context. https://task.matda.me/tasks/tsk_beu5nmfqfj — worker/ledger. https://task.matda.me/tasks/tsk_5fdrm4pptn — callback boundaries. ## Questions No blocking product question under the conservative rule that newer/manual report state is never overwritten. If automatic regeneration after a manual-edit conflict is requested, obtain an explicit policy instead of implementing it implicitly.
Checklist
0 of 0 completeNo checklist items.
- Area
- Kaukus
- Kind
- Feature
- Priority
- Medium
- Task ID
tsk_43ubu6a7pr- Updated