Skip to content

Add stop_reason field to plan_status (Proposal 114-I1)#244

Merged
neoneye merged 19 commits intomainfrom
feature/114-I1-stop-reason
Mar 11, 2026
Merged

Add stop_reason field to plan_status (Proposal 114-I1)#244
neoneye merged 19 commits intomainfrom
feature/114-I1-stop-reason

Conversation

@neoneye
Copy link
Member

@neoneye neoneye commented Mar 11, 2026

Summary

  • Adds stop_reason field to plan_status response so agents can distinguish user-initiated stops ("user_requested") from actual failures (null)
  • Computed from existing stop_requested DB column — no migration needed, non-breaking (new optional field)
  • Updates tool descriptions in both mcp_cloud and mcp_local to document the new field
  • Frontend shows "stopped" (orange) instead of "failed" (red) for user-initiated stops across all views

Changes

File What
mcp_cloud/tool_models.py stop_reason field on PlanStatusSuccess and PlanStatusOutput
mcp_cloud/handlers.py Compute stop_reason from state + stop_requested
mcp_cloud/schemas.py Tool description guidance for stop_reason
mcp_local/planexe_mcp_local.py Schema + description updates for local proxy
mcp_cloud/tests/test_plan_status_tool.py 3 new tests (user stop, actual failure, non-failed state)
frontend_multi_user/src/app.py /plan/meta includes stop_reason; plan list + dashboard show "stopped"
frontend_multi_user/templates/plan_iframe.html Status bar shows "stopped" (initial render + JS poll)
frontend_multi_user/templates/plan_list.html Orange "stopped" chip for user-stopped plans
frontend_multi_user/templates/index.html Dashboard dot + label show "Stopped" with orange color
docs/proposals/114-...md Mark I1 as implemented

Test plan

  • Verify test file parses: python -c "import ast; ast.parse(open('mcp_cloud/tests/test_plan_status_tool.py').read())"
  • Run tests in Docker/CI: cd mcp_cloud && python -m pytest tests/test_plan_status_tool.py -v
  • Confirm plan_status returns stop_reason: "user_requested" after plan_stop
  • Confirm plan_status returns stop_reason: null for actual failures and non-failed states
  • Verify plan list shows orange "stopped" chip for user-stopped plans
  • Verify plan detail shows "stopped" in status bar after user stop
  • Verify dashboard shows "Stopped" with orange dot for user-stopped plans

🤖 Generated with Claude Code

neoneye and others added 19 commits March 11, 2026 17:07
Agents can now distinguish user-initiated stops from actual failures:
stop_reason is "user_requested" when plan_stop was called, null for
real errors. Computed from existing stop_requested DB column — no
migration needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The frontend now uses stop_reason to distinguish user-initiated stops
from actual failures across all views:
- /plan/meta endpoint includes stop_reason in response
- Plan detail page shows "stopped" in status bar (initial + polled)
- Plan list shows orange "stopped" chip instead of red "failed"
- Dashboard recent tasks show "Stopped" label with orange dot

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document what was actually implemented vs proposed: minimal stop_reason
vocabulary (user_requested vs null), no DB changes needed, frontend
coverage beyond original MCP-only scope. Note I2 as prerequisite for
richer stop_reason values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a plan is stopped by the user, the status bar previously showed
"stopped · 42% · Stop requested by user." — the progress message is
redundant since "stopped" already communicates user intent. Now shows
just "stopped · 42%".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The PlanItem admin list view now displays "stopped" (orange) instead of
"failed" when stop_requested is true, matching the frontend behavior.
The DB filter still operates on the raw state column.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace computed stop_reason/display_state_name logic with proper state
semantics: plan_stop now transitions to PlanState.stopped instead of
PlanState.failed, and the stop_reason field is removed from API responses.
plan_retry and plan_resume accept both failed and stopped states. Includes
DB migration to add 'stopped' to PostgreSQL planstate enum across all three
startup paths (mcp_cloud, worker, frontend).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update cross-reference table, priority table, I2/I3/I8 descriptions to
reflect Option A (PlanState.stopped) instead of the superseded Option B
(stop_reason field).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The PostgreSQL enum type is named `taskstate` (from the original
`TaskState` Python class), not `planstate` (the renamed class).
The migration silently failed, so `'stopped'` was never added to
the enum, causing Internal Server Error on plan stop.

Try both type names to support existing and fresh databases.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The worker's post-pipeline logic always set PlanState.failed for
non-completed plans, even when the user requested the stop. Now
checks stop_requested and uses PlanState.stopped for user stops.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The run_via_database.html progress poller only knew about pending,
processing, completed, and failed. The new stopped state fell through
to the unhandled-status error path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Jinja indentation caused extra whitespace between "Status:" and the
state name. Use {%- whitespace control to produce clean single-space
output like "Status: stopped · 23%".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Inline all Jinja tags on one line to avoid whitespace-stripping
eating the space after "Status:".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
inline-flex collapses whitespace between text nodes. Wrap "Status:"
in its own span and add gap: 0.3em to the flex container.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- planexe_mcp_interface.md: add stopped to state list, transitions,
  terminal states, caller contract, error codes, and recovery guidance
- autonomous_agent_guide.md: add stopped to state monitoring section
- proposal 87: update deferred stopped-state notes as implemented

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Note taskstate vs planstate enum type name issue
- Note worker post-pipeline finalization fix
- Add all affected files including docs and run_via_database.html
- Update proposal 87 overlap reference

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Update context: two sessions (12 plans total), not just one
- Add I10: silent partial failures in completed plans
- Enhance I2 with recoverable boolean suggestion
- Add agent perception section (8.5/10 rating, strengths, trust gaps)
- Add evolution table across sessions
- Update cross-reference and priority tables

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New issue from v2 agent perception feedback: completed plans may have
empty or stub-quality sections with no quality_summary signal. Also
updated I2 description to mention the recoverable field.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@neoneye neoneye merged commit db3ff8d into main Mar 11, 2026
3 checks passed
@neoneye neoneye deleted the feature/114-I1-stop-reason branch March 11, 2026 20:01
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