Add readiness_score_feedback as externally stored markdown field on WorkItems::AgentPlan
What does this MR do and why?
Adds readiness_score_feedback as an externally stored markdown field on WorkItems::AgentPlan, sharing the same object-storage blob as the existing content field.
Part of #617982 (closed) — MR 1 of 3 (model and persistence). MR 2 (GraphQL read) and MR 3 (GraphQL write) are stacked on this branch and target it; they will be retargeted to master once this merges.
What changes
ee/app/models/work_items/agent_plan.rb: addscache_markdown_field :readiness_score_feedback, storage: :external, issuable_reference_expansion_enabled: truebeside the existingcontentline, and a length validation reusingCONTENT_LENGTH_MAX.ee/app/models/work_items/widgets/agent_plan.rb: delegates:readiness_score_feedbackand:readiness_score_feedback_htmlthrough the widget, mirroringcontentandcontent_html. The_htmldelegation is what makes the cached rendering reachable from GraphQL; MR 2 exposes it as amarkdown_field.ee/app/services/work_items/data_sync/widgets/agent_plan.rb: adds a secondMarkdownContentRewriterServicecall for:readiness_score_feedbackon work-item move. The service rewrites one field per call, so the new field needs its own call.
How it works (no migration needed)
cache_markdown_field :x, storage: :external registers both x and x_html as virtual ActiveRecord attributes via externally_stored_field. build_external_payload serializes all registered fields into one JSON blob whose filename is deterministic (#{work_item_id}.json). A second field therefore reuses the same blob and the existing file_store column. Existing blobs that predate this field read back as nil (the loader does payload[field.to_s], so a missing key is nil).
Risk note
The external storage mechanism may shift underneath this work (see #616229 (comment 3694614696) and !249644 (merged)). This MR should be coordinated with that work before landing.
Concurrent-write note
persist_external_payload does an unlocked read-merge-write. With two externally stored markdown fields, concurrent refresh_markdown_cache! calls touching different fields on the same record could clobber each other. This is only reachable from refresh_markdown_cache! and is a pre-existing concern for content + content_html; adding a second field makes it slightly more likely. Flagging for awareness — not a blocker for this MR.
References
- Issue: #617982 (closed)
- Precedent MRs: !249416 (merged) and !249498 (merged)
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.