# Token-reachable write surface — pinned inventory (#2772).
#
# Every route in this file accepts POST/PUT/PATCH/DELETE from a personal access
# token carrying the `legacy:full` scope, which is the DEFAULT scope for a newly
# minted token (apps/projects/models.py, _default_api_token_scopes). The scope
# taxonomy that would let a write be withheld is 0.6 work (#2661); until then,
# "has a token" means "can write here".
#
# READ THIS BEFORE TRUSTING THE FILE'S HISTORY (#2877/#2878). Until 0.4 the walker
# that generates it decided reachability from class-level `permission_classes`, and
# `TokenReadOnlyMethods` is contributed at *runtime* by `McpReadableViewMixin`. So
# the ~50 unsafe routes on the eight MCP-wrapped viewsets (tasks/, projects/,
# risks/, labels/, sprints/, programs/, backlog-items/, board-config/) were listed
# here while they actually 403'd every token. #2877 made them genuinely writable and
# produced NO diff in this file — the tripwire could not see the widening it exists
# to report. Those lines became true in 0.4; they were aspirational before it.
#
# Seven routes left the set in the same change: the six `api-tokens/` ones plus
# `me/credentials/<provider>/`. Credential management is session/JWT-only since
# #2878 (`IsNotTokenAuthenticated`), so a leaked token can no longer mint sibling
# tokens, revoke the owner's live ones, or overwrite the owner's connected-account
# credential. Note what did NOT leave: `me/connections/<source>/` and its `/sync/`
# are a different viewset and stay token-writable.
#
# Three more left the set in #3551: the SSO provider admin routes
# (`workspace/sso/providers/` and its item + `test-connection/`). Provider config is
# session/JWT-only for the same reason — an admin's leaked token could set
# `auto_create_members` with an ADMIN `default_role`, widen `allowed_email_domains`,
# or rotate the IdP secret, and one SSO login at the widened domain then mints a
# durable ADMIN session that revoking the token does not touch.
#
# None of these routes writes an AgentAction row (#2749). A machine-authored
# write is attributed to the token's human owner via historicaltask.history_user.
# That is the gap 0.5 (#2745, #2749) closes — this file is its checklist.
#
# Generated from get_resolver() and asserted by
# tests/apps/access/test_route_table_invariants.py. Do not hand-sort: the test
# compares sets, but a stable sorted order keeps the review diff readable.
# DRF format-suffix duplicates (.json) are excluded — same view, same surface.
#
# A route ADDED here in an MR means a new endpoint is writable by any token.
# Say so in the MR description; do not add the line silently to make CI pass.
api/v1/^acceptance-criteria/$
api/v1/^acceptance-criteria/(?P<pk>[^/.]+)/$
api/v1/^admin/failed-tasks/(?P<pk>[^/.]+)/drop/$
api/v1/^admin/failed-tasks/(?P<pk>[^/.]+)/requeue/$
api/v1/^admin/failed-tasks/drop-all/$
api/v1/^admin/failed-tasks/requeue-all/$
api/v1/^calendars/$
api/v1/^calendars/(?P<pk>[^/.]+)/$
api/v1/^cascade-classification-operations/(?P<pk>[^/.]+)/undo/$
api/v1/^dependencies/$
api/v1/^dependencies/(?P<pk>[^/.]+)/$
api/v1/^dependencies/(?P<pk>[^/.]+)/accept/$
api/v1/^dependencies/(?P<pk>[^/.]+)/reject/$
api/v1/^paste-many-operations/(?P<pk>[^/.]+)/undo/$
api/v1/^programs/$
api/v1/^programs/(?P<pk>[^/.]+)/$
api/v1/^programs/(?P<pk>[^/.]+)/bulk-project-fields/$
api/v1/^programs/(?P<pk>[^/.]+)/close/$
api/v1/^programs/(?P<pk>[^/.]+)/export/$
api/v1/^programs/(?P<pk>[^/.]+)/pin/$
api/v1/^programs/(?P<pk>[^/.]+)/remove-sample/$
api/v1/^programs/(?P<pk>[^/.]+)/shift-sample-dates/$
api/v1/^programs/(?P<pk>[^/.]+)/reopen/$
api/v1/^programs/(?P<pk>[^/.]+)/risk-policy/$
api/v1/^programs/(?P<pk>[^/.]+)/rollup-config/$
api/v1/^programs/(?P<pk>[^/.]+)/split/$
api/v1/^programs/(?P<pk>[^/.]+)/transfer-sponsorship/$
api/v1/^programs/(?P<program_pk>[^/.]+)/webhooks/$
api/v1/^programs/(?P<program_pk>[^/.]+)/webhooks/(?P<pk>[^/.]+)/$
api/v1/^programs/(?P<program_pk>[^/.]+)/webhooks/(?P<pk>[^/.]+)/test/$
api/v1/^programs/bulk-fields/$
api/v1/^programs/import/$
api/v1/^programs/import/validate/$
api/v1/^programs/load-sample/$
api/v1/^project-resources/$
api/v1/^project-resources/(?P<pk>[^/.]+)/$
api/v1/^project-templates/(?P<pk>[^/.]+)/apply/$
api/v1/^project-templates/publish/$
api/v1/^projects/$
api/v1/^projects/(?P<pk>[^/.]+)/$
api/v1/^projects/(?P<pk>[^/.]+)/archive/$
api/v1/^projects/(?P<pk>[^/.]+)/calendars/$
api/v1/^projects/(?P<pk>[^/.]+)/export/$
api/v1/^projects/(?P<pk>[^/.]+)/pin/$
api/v1/^projects/(?P<pk>[^/.]+)/product-backlog/auto-rank/$
api/v1/^projects/(?P<pk>[^/.]+)/product-backlog/reorder/$
api/v1/^projects/(?P<pk>[^/.]+)/queue/reorder/$
api/v1/^projects/(?P<pk>[^/.]+)/restore/$
api/v1/^projects/(?P<pk>[^/.]+)/transfer/$
api/v1/^projects/(?P<pk>[^/.]+)/unarchive/$
api/v1/^projects/(?P<pk>[^/.]+)/visit/$
api/v1/^projects/(?P<project_pk>[^/.]+)/webhooks/$
api/v1/^projects/(?P<project_pk>[^/.]+)/webhooks/(?P<pk>[^/.]+)/$
api/v1/^projects/(?P<project_pk>[^/.]+)/webhooks/(?P<pk>[^/.]+)/test/$
api/v1/^recurrence-rules/$
api/v1/^recurrence-rules/(?P<pk>[^/.]+)/$
api/v1/^resource-skills/$
api/v1/^resource-skills/(?P<pk>[^/.]+)/$
api/v1/^resources/$
api/v1/^resources/(?P<pk>[^/.]+)/$
api/v1/^resources/(?P<pk>[^/.]+)/restore/$
api/v1/^skills/$
api/v1/^skills/(?P<pk>[^/.]+)/$
api/v1/^slip-conflicts/(?P<pk>[^/.]+)/acknowledge/$
api/v1/^structural-operations/(?P<pk>[^/.]+)/undo/$
api/v1/^task-relations/$
api/v1/^task-relations/(?P<pk>[^/.]+)/$
api/v1/^task-resources/$
api/v1/^task-resources/(?P<pk>[^/.]+)/$
api/v1/^task-skill-requirements/$
api/v1/^task-skill-requirements/(?P<pk>[^/.]+)/$
api/v1/^tasks/$
api/v1/^tasks/(?P<pk>[^/.]+)/$
api/v1/^tasks/(?P<pk>[^/.]+)/approve-estimates/$
api/v1/^tasks/(?P<pk>[^/.]+)/reorder/$
api/v1/^tasks/(?P<pk>[^/.]+)/restore/$
api/v1/^tasks/(?P<pk>[^/.]+)/split/$
api/v1/^tasks/delete-untouched-seeded/$
api/v1/^template-applications/(?P<pk>[^/.]+)/undo/$
api/v1/^velocity-suggestions/(?P<pk>[^/.]+)/accept/$
api/v1/^velocity-suggestions/(?P<pk>[^/.]+)/dismiss/$
api/v1/auth/me/profile/
api/v1/calendars/<calendar_pk>/exceptions/
api/v1/calendars/<calendar_pk>/exceptions/<pk>/
api/v1/health/retention/
api/v1/health/retention/runs/
api/v1/health/telemetry/test/
api/v1/integrations/projects/<uuid:project_pk>/git-automation/
api/v1/me/connections/<slug:source>/
api/v1/me/connections/<slug:source>/sync/
api/v1/me/notification-preferences/<int:pk>/
api/v1/me/notification-preferences/apply-preset/
api/v1/me/notification-settings/
api/v1/me/notifications/<uuid:pk>/
api/v1/me/notifications/<uuid:pk>/snooze/
api/v1/me/notifications/mark-all-read/
api/v1/me/time-entries/<uuid:pk>/
api/v1/me/timer/start
api/v1/me/timer/stop
api/v1/me/timesheets/<str:week_start>/submit
api/v1/poker/<pk>/cancel/
api/v1/poker/<pk>/commit/
api/v1/poker/<pk>/reopen/
api/v1/poker/<pk>/reveal/
api/v1/poker/<pk>/vote/
api/v1/programs/<program_pk>/backlog-items/
api/v1/programs/<program_pk>/backlog-items/<pk>/
api/v1/programs/<program_pk>/backlog-items/<pk>/pull/
api/v1/programs/<program_pk>/ceremonies/
api/v1/programs/<program_pk>/ceremonies/<pk>/
api/v1/programs/<program_pk>/phase-gate-config/
api/v1/programs/<uuid:program_pk>/external-stakeholders/
api/v1/programs/<uuid:program_pk>/external-stakeholders/<uuid:pk>/
api/v1/programs/<uuid:program_pk>/members/
api/v1/programs/<uuid:program_pk>/members/<uuid:pk>/
api/v1/programs/<uuid:program_pk>/mention-groups/
api/v1/programs/<uuid:program_pk>/mention-groups/<uuid:pk>/
api/v1/programs/<uuid:program_pk>/mention-groups/<uuid:pk>/add-member/
api/v1/programs/<uuid:program_pk>/mention-groups/<uuid:pk>/mute/
api/v1/programs/<uuid:program_pk>/mention-groups/<uuid:pk>/remove-member/
api/v1/programs/<uuid:program_pk>/mention-groups/<uuid:pk>/unmute/
api/v1/projects/<pk>/board-config/
api/v1/projects/<pk>/board-views/
api/v1/projects/<pk>/board-views/<view_pk>/
api/v1/projects/<pk>/commit/
api/v1/projects/<pk>/phases/reorder/
api/v1/projects/<pk>/tasks/<task_id>/indent/
api/v1/projects/<pk>/tasks/<task_id>/outdent/
api/v1/projects/<pk>/tasks/<task_id>/reparent/
api/v1/projects/<pk>/tasks/bulk/
api/v1/projects/<pk>/tasks/classification/
api/v1/projects/<pk>/tasks/group/
api/v1/projects/<pk>/tasks/reorder/
api/v1/projects/<pk>/tasks/ungroup/
api/v1/projects/<project_pk>/baselines/
api/v1/projects/<project_pk>/baselines/<baseline_pk>/activate/
api/v1/projects/<project_pk>/baselines/<pk>/
api/v1/projects/<project_pk>/decisions-policy/
api/v1/projects/<project_pk>/fields/
api/v1/projects/<project_pk>/fields/<pk>/
api/v1/projects/<project_pk>/guardrail-policy/
api/v1/projects/<project_pk>/import/csv/
api/v1/projects/<project_pk>/import/csv/<pk>/undo/
api/v1/projects/<project_pk>/import/csv/preview/
api/v1/projects/<project_pk>/import/jira/
api/v1/projects/<project_pk>/import/msproject/
api/v1/projects/<project_pk>/labels/
api/v1/projects/<project_pk>/labels/<pk>/
api/v1/projects/<project_pk>/phases/
api/v1/projects/<project_pk>/phases/<pk>/
api/v1/projects/<project_pk>/risks/
api/v1/projects/<project_pk>/risks/<pk>/
api/v1/projects/<project_pk>/risks/<risk_pk>/comments/
api/v1/projects/<project_pk>/risks/import/
api/v1/projects/<project_pk>/share-links/
api/v1/projects/<project_pk>/share-links/<link_id>/revoke/
api/v1/projects/<project_pk>/signal-privacy/
api/v1/projects/<project_pk>/signal-privacy/ceiling-proposals/<proposal_pk>/vote/
api/v1/projects/<project_pk>/signal-privacy/ceiling-proposals/<proposal_pk>/withdraw/
api/v1/projects/<project_pk>/signal-privacy/raise-ceiling/
api/v1/projects/<project_pk>/signal-privacy/ratchet-down/
api/v1/projects/<project_pk>/sprints/
api/v1/projects/<project_pk>/sprints/generate/
api/v1/projects/<project_pk>/task-runs/<pk>/cancel/
api/v1/projects/<project_pk>/tasks/<task_pk>/attachments/
api/v1/projects/<project_pk>/tasks/<task_pk>/attachments/<pk>/
api/v1/projects/<project_pk>/tasks/<task_pk>/comments/
api/v1/projects/<project_pk>/tasks/<task_pk>/comments/<comment_pk>/reactions/
api/v1/projects/<project_pk>/tasks/<task_pk>/comments/<comment_pk>/reactions/<pk>/
api/v1/projects/<project_pk>/tasks/<task_pk>/comments/<pk>/
api/v1/projects/<project_pk>/tasks/<task_pk>/comments/<pk>/acknowledge/
api/v1/projects/<project_pk>/tasks/<task_pk>/field-values/<field_id>/
api/v1/projects/<project_pk>/tasks/<task_pk>/labels/
api/v1/projects/<project_pk>/tasks/<task_pk>/labels/<label_id>/
api/v1/projects/<project_pk>/tasks/<task_pk>/links/
api/v1/projects/<project_pk>/tasks/<task_pk>/links/<pk>/
api/v1/projects/<project_pk>/tasks/<task_pk>/links/<pk>/refresh/
api/v1/projects/<project_pk>/tasks/<task_pk>/notes/
api/v1/projects/<project_pk>/tasks/<task_pk>/notes/<pk>/
api/v1/projects/<project_pk>/tasks/<task_pk>/notes/<pk>/decision/
api/v1/projects/<project_pk>/tasks/<task_pk>/notes/<pk>/pin/
api/v1/projects/<str:pk>/monte-carlo/
api/v1/projects/<str:pk>/schedule/
api/v1/projects/<uuid:pk>/notification-preferences/
api/v1/projects/<uuid:pk>/sync/
api/v1/projects/<uuid:project_pk>/members/
api/v1/projects/<uuid:project_pk>/members/<uuid:pk>/
api/v1/projects/<uuid:project_pk>/mention-groups/
api/v1/projects/<uuid:project_pk>/mention-groups/<uuid:pk>/
api/v1/projects/<uuid:project_pk>/mention-groups/<uuid:pk>/add-member/
api/v1/projects/<uuid:project_pk>/mention-groups/<uuid:pk>/mute/
api/v1/projects/<uuid:project_pk>/mention-groups/<uuid:pk>/remove-member/
api/v1/projects/<uuid:project_pk>/mention-groups/<uuid:pk>/unmute/
api/v1/projects/import/msproject/
api/v1/retro-items/<pk>/
api/v1/retro-items/<pk>/convert-to-action/
api/v1/scope-changes/<pk>/accept/
api/v1/scope-changes/<pk>/reject/
api/v1/sprint-task-outcomes/<pk>/flag-for-backlog/
api/v1/sprint-task-outcomes/<pk>/set-note/
api/v1/sprint-task-outcomes/<pk>/set-presenter/
api/v1/sprint-task-outcomes/<pk>/toggle-demo/
api/v1/sprints/<pk>/
api/v1/sprints/<pk>/activate/
api/v1/sprints/<pk>/cancel/
api/v1/sprints/<pk>/close/
api/v1/sprints/<pk>/demo-list/reorder/
api/v1/sprints/<pk>/promote-to-milestone/
api/v1/sprints/<pk>/pulse/
api/v1/sprints/<pk>/reorder/
api/v1/sprints/<pk>/retro-board/
api/v1/sprints/<pk>/retro/
api/v1/sprints/<pk>/retrospective/action-items/<uuid:item_pk>/promote/
api/v1/sprints/<pk>/retrospective/action-items/<uuid:item_pk>/pull-to-sprint/
api/v1/sprints/<pk>/scope-changes/accept/
api/v1/sprints/<pk>/scope-changes/reject/
api/v1/sprints/<pk>/unbind-milestone/
api/v1/sprints/<sprint_pk>/poker/
api/v1/tasks/<pk>/suggestions/<uuid:suggestion_pk>/accept/
api/v1/tasks/<pk>/suggestions/<uuid:suggestion_pk>/decline/
api/v1/tasks/<pk>/suggestions/<uuid:suggestion_pk>/revoke/
api/v1/tasks/<uuid:task_pk>/time-entries/
api/v1/teams/<uuid:team_pk>/members/<uuid:pk>/
api/v1/workspace/
api/v1/workspace/email-settings/
api/v1/workspace/email-settings/send-test/
api/v1/workspace/export/
api/v1/workspace/groups/
api/v1/workspace/groups/<uuid:group_id>/
api/v1/workspace/groups/<uuid:group_id>/members/
api/v1/workspace/groups/<uuid:group_id>/members/<int:user_id>/
api/v1/workspace/groups/<uuid:group_id>/projects/
api/v1/workspace/groups/<uuid:group_id>/projects/<uuid:project_id>/
api/v1/workspace/invites/
api/v1/workspace/invites/<uuid:invite_id>/
api/v1/workspace/invites/<uuid:invite_id>/resend/
api/v1/workspace/invites/resend-all/
api/v1/workspace/logo/
api/v1/workspace/members/<int:user_id>/
api/v1/workspace/transfer-ownership/
api/v1/ws/ticket/
