Fix silent readiness_score drop when workplan_score flag is disabled

What does this MR do and why?

Follow-up to !252152 (merged), addressing reviewer feedback in !252152 (comment 3766370586) (by @jessieay).

Problem: readiness_score writes to the AgentPlan callback were silently dropped when the workplan_score feature flag was disabled. readiness_score_param? returned false when the flag was off, so the early return in handle_agent_plan_change skipped persistence entirely — no error was raised, and the mutation reported success. With content + readiness_score together, content was applied and the score was dropped just as quietly.

The workplan_score flag is type: wip, default_enabled: false, so this was the default state for every namespace in 19.4.

Why it matters: MR !252152 (merged) made the MCP save_work_item tool a writer of this field. An MCP client told to "set the readiness score to 80" received isError: false and no score field — a silent no-op reported as success.

Fix: In handle_agent_plan_change in ee/app/services/work_items/callbacks/agent_plan.rb, distinguish "not provided" from "provided but feature-flag-gated". When params.key?(:readiness_score) is true but the flag is off, call raise_error with a clear message. This raises Issuable::Callbacks::Base::Error, which the create/update services already convert into a mutation error, surfacing correctly through both GraphQL and MCP (Response.error). One change point fixes both consumers.

Explicitly not fixed in the MCP tool layer — as the reviewer noted, that would require re-resolving namespace.root_ancestor just to evaluate the flag, add a third flag enforcement site to unwind at flag cleanup, and the alternative of echoing readinessScore in the save response would require EE variants of both GraphQL mutation documents.

References

Screenshots or screen recordings

Not applicable — backend-only change.

How to set up and validate locally

  1. Disable the feature flag: Feature.disable(:workplan_score)
  2. Via GraphQL, call workItemUpdate with agentPlanWidget: { readinessScore: 80 } — expect a mutation error containing "workplan_score".
  3. Via MCP save_work_item with readiness_score: 80 — expect isError: true with the same message.
  4. Enable the flag: Feature.enable(:workplan_score) — both paths should succeed as before.
  5. With the flag disabled, passing only content (no readiness_score) should still work.

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.

Merge request reports

Loading
Loading