Skip to content

Manual incidents with MCP write access; drop manual conditions#385

Open
passcod wants to merge 6 commits into
mainfrom
claude/canopy-manual-incidents-qqmc2m
Open

Manual incidents with MCP write access; drop manual conditions#385
passcod wants to merge 6 commits into
mainfrom
claude/canopy-manual-incidents-qqmc2m

Conversation

@passcod

@passcod passcod commented Jul 21, 2026

Copy link
Copy Markdown
Member

What

Adds manual incidents: support-recorded incident records, written after the fact rather than derived from check state — title, markdown description, start/end times (no end = ongoing), the affected group (mandatory), and author attribution. They can be created, edited, and deleted both in the operator UI and over the MCP interface, and are displayed alongside automatic incidents.

Deletes the never-used manual conditions feature (operator-raised checks under the manual source) end to end — endpoint, UI, source plumbing, spec — freeing the "manual" name. canopy is now the only reserved source.

Manual incidents

  • Every manual incident names exactly one server group (NOT NULL + ON DELETE RESTRICT: the record is history, so a group with manual incidents on record can't be removed). The group can be changed on update.
  • UI: read/write — a "Record incident" dialog on /incidents, edit/delete on the detail view at /incidents/manual/:id. Writes go through new /api/manual_incidents/{create,update,delete} endpoints, attributed to the tailnet user.

MCP write access

The MCP interface is no longer strictly read-only; manual incidents are its one write surface:

  • New tools: find_manual_incidents, get_manual_incident, record_manual_incident, update_manual_incident, delete_manual_incident.
  • Each mount's auth gate inserts an McpIdentity (tailnet login or token name + write permission) into the request extensions; rmcp carries the HTTP parts into the tool context, where write tools authorise and attribute the write (created_by).
  • Bearer tokens gain a mint-time, immutable write_access scope, default read-only — existing tokens keep their current access. Any tailnet user may write on the operator mount. The mint form/API and token list expose the scope.
  • Writes go to the primary pool; reads stay on the replica.

Also

  • New manual_incidents table + model; mcp_tokens.write_access column (two migrations).
  • Specs updated first per workflow: INC gains "Manual incidents", MCP's "Read-only" section rewritten as "Reads and writes" (+ token scope), CHK's "Manual conditions" removed.
  • Tests: database/private/public-server integration tests (incl. token-scope enforcement, write attribution over both mounts, and UI-endpoint validation) and Playwright e2e for the list section, detail page, create/edit/delete flows, and token scope chips.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BWJTpUsXDp2Z6Ck7rnt8JL


Generated by Claude Code

claude added 4 commits July 21, 2026 04:15
Manual incidents are support-recorded incident records, written after the
fact rather than derived from check state: title, markdown description,
start/end times, optional group, and author attribution. They are created,
edited, and deleted over the MCP interface (record/update/delete tools) and
displayed read-only in the operator UI alongside automatic incidents.

The MCP interface is no longer strictly read-only: each mount's auth gate
now threads an McpIdentity (tailnet login or token name, plus write
permission) into the request extensions, which the write tools use to
authorise and attribute writes. Bearer tokens gain a mint-time, immutable
write_access scope, default read-only, so existing tokens keep their
current access; any tailnet user may write on the operator mount. Writes
go to the primary pool while reads stay on the replica.

The never-used manual conditions feature (operator-raised checks under the
`manual` source) is deleted end to end — endpoint, UI, source plumbing, and
spec — freeing the "manual" name; `canopy` is now the only reserved source.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BWJTpUsXDp2Z6Ck7rnt8JL
Covers the model CRUD, the read endpoints, the operator-mount write
round-trip with tailnet attribution, and the token-scope enforcement on
the internet-facing mount (read-only tokens refused, write tokens
attributed by name).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BWJTpUsXDp2Z6Ck7rnt8JL
@passcod
passcod force-pushed the claude/canopy-manual-incidents-qqmc2m branch from a5d2f58 to a9759ab Compare July 21, 2026 04:22
claude added 2 commits July 21, 2026 04:48
The tightened file_check debug_assert broke main's new liveness tests,
which legitimately file server-scoped checks under reporter sources;
only group- and canopy-wide filings are canopy's own. Also give the
manual_incidents endpoints the description paragraphs the OpenAPI spec
test requires.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BWJTpUsXDp2Z6Ck7rnt8JL
Every manual incident now names exactly one server group (NOT NULL +
ON DELETE RESTRICT: the record is history), and the group can be
changed on update. The operator UI gains the same write capabilities
as MCP: create/update/delete endpoints attributed to the tailnet
user, a record dialog on /incidents, and edit/delete on the detail
page.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BWJTpUsXDp2Z6Ck7rnt8JL
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.

2 participants