You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
PlanForceBot consults the state-less ForcePlanBlockers overload: it cannot see apc_owns_it / forcing_failed_on_this_plan / already_forced before an automatic force #3654
#3652 taught the force-plan verdict to read the store's forcing and automatic-plan-correction state at read time: FactRemediation.ForcePlanBlockers(ForcePlanTarget, ForcePlanTargetState?) adds apc_owns_it, already_forced, forcing_failed_on_this_plan, apc_withdrew_it and apc_resolved_differently, and both SKUs' MCP surfaces pass a per-target ForcePlanTargetState read by ForcePlanTargetStateReader (Lite, DuckDB) / DarlingForcePlanTargetStateReader (Darling, Postgres).
PlanForceBot (Darling/PerformanceMonitor.Darling.Service/PlanForceBot.cs ~157) still calls the ORIGINAL one-argument overload — the two #2138 blockers only — and hands that list to ForcePlanBotPolicy.Evaluate. So the automatic bot's gate has exactly the gap #3652 closed on the advisory surface: it would judge a plan APC is mid-verification on, a plan whose force_failure_count is already climbing, or a plan already forced by hand, as unblocked. The bot is dry-run-gated today (write-gate 2, V107), which is why this is a follow-up rather than part of #3652; it must not go live without this.
Fix shape
PlanForceBot reads the state for its candidate targets through DarlingForcePlanTargetStateReader.ReadAsync (it has the NpgsqlDataSource) and calls the two-argument overload; the journal row records the blocker names AND the evidence strings (ForcePlanBlocker.Evidence), so a Blocked decision is auditable against the snapshot it was made on.
When the state read fails, the bot treats it as a blocker of its own (state_unavailable) — the advisory surface can say "unknown" and let a human decide; an automatic actor cannot.
ForcePlanBotPolicy stays pure; it already takes the blocker list as data.
Activity
The automatic force-plan bot judged through the state-less gate and c…
erikdarlingdata commentedon Sep 18, 2026
Closed by the merge of #3663 (its body names this issue with a closing keyword; keywords do not fire against dev, so the watcher closes it).