Files
music_library/backlog/docs/doc-12 - Research-Mute-and-Resolve-Production-Errors-Implementation-Routes.md
2026-05-05 13:43:18 +01:00

9.4 KiB

id, title, type, created_date
id title type created_date
doc-12 Research: Mute and Resolve Production Errors Implementation Routes specification 2026-05-05 11:24

Research: Mute and Resolve Production Errors Implementation Routes

Task: ML-165 — Mute and resolve production errors from pi Date: 2026-05-05

Current State

Backend (Elixir/Phoenix)

Component File Status
Error schema deps/error_tracker/lib/error_tracker/schemas/error.ex Has status (:resolved/:unresolved) and muted (boolean) fields
Error context lib/music_library/errors.ex Read-only: list_errors/1, get_error/1 — no update functions
Error controller lib/music_library_web/controllers/error_controller.ex GET /api/v1/errors (index), GET /api/v1/errors/:id (show)
Error JSON views lib/music_library_web/controllers/error_json.ex Renders error/occurrence data
Router lib/music_library_web/router.ex /api/v1/errors routes in API scope (Bearer token auth)
Auth lib/music_library_web/auth.ex require_api_token/2 plug — Bearer token comparison

Pi Extension (TypeScript)

Component File Status
prod-errors extension .pi/extensions/prod-errors/index.ts Tools: fetch_production_errors, fetch_production_error; Command: /prod-errors (TUI browser)
TUI ErrorBrowser Same file, ErrorBrowser class List view (no mute/resolve actions), Detail view (no mute/resolve actions)

Gap Analysis

  1. No mutation endpoints — The API has no way to update an error's muted or status fields.
  2. No context functionsMusicLibrary.Errors has no mute_error/1 or resolve_error/1 (or generic update_error/2).
  3. No pi tools — No mute_production_error or resolve_production_error tool registered.
  4. No TUI actions — The /prod-errors ErrorBrowser TUI has no keybindings to mute or resolve errors.

Implementation Routes

Route A: Dedicated POST Endpoints Per Action (Recommended)

Add two new routes, each handling a single action:

POST /api/v1/errors/:id/mute    → sets muted = true
POST /api/v1/errors/:id/resolve → sets status = :resolved

Elixir changes:

  • MusicLibrary.Errors: Add mute_error/1, resolve_error/1 (or a shared private helper)
  • MusicLibraryWeb.ErrorController: Add mute/2 and resolve/2 actions
  • MusicLibraryWeb.ErrorJSON: Add mute/1, resolve/1 render functions
  • MusicLibraryWeb.Router: Add two POST routes in the API scope

Pi extension changes:

  • Register mute_production_error tool → POSTs to /api/v1/errors/:id/mute
  • Register resolve_production_error tool → POSTs to /api/v1/errors/:id/resolve
  • Add keybindings to /prod-errors TUI:
    • M (shift-m) in list view → mute selected error
    • R (shift-r) in detail view → resolve selected error
    • Or use single keys: x for mute, d for resolve (avoiding conflict with existing m/r filter toggles)

Pros:

  • Simplest approach — each endpoint does exactly one thing
  • RESTful resource/action pattern used elsewhere in the app (e.g., /collection/latest)
  • Easy to extend with unmute/unresolve later as additional endpoints
  • Clean tool-to-endpoint mapping in pi
  • Easy to test independently

Cons:

  • Two new routes instead of one
  • If many more error actions are added, route count could grow

Route B: Single PATCH Endpoint

Add one generic mutation endpoint:

PATCH /api/v1/errors/:id   body: {"muted": true} or {"status": "resolved"}

Pros:

  • Single route for all error mutations
  • Follows REST convention for partial updates
  • Easily extensible to other fields

Cons:

  • Parameter validation is more complex (must reject unknown fields, validate combinations)
  • Tool semantics are less clear — the pi tool would need to construct the PATCH body
  • PATCH semantics imply partial update; if both fields are sent, behavior must be defined
  • Less explicit — the URL doesn't convey the action being performed
  • Not aligned with existing project patterns (no other PATCH routes in the API)

Route C: Single Action Endpoint

POST /api/v1/errors/:id/actions   body: {"action": "mute"} or {"action": "resolve"}

Pros:

  • Single route for all actions
  • Easy to add new action types
  • Clean separation between action specification and execution
  • Tool semantics map cleanly (tool name = action)

Cons:

  • Less standard REST pattern
  • Requires action validation/dispatch layer
  • No existing precedent in the codebase

Recommendation: Route A

Route A is the best fit for this project because:

  1. Convention alignment — The project uses clear, descriptive route names for specific operations (e.g., /collection/latest, /collection/random, /collection/on_this_day). POST /errors/:id/mute and POST /errors/:id/resolve follow this pattern.

  2. Simplicity — Each endpoint has a single responsibility. The controller actions, context functions, JSON views, and pi tools are all trivial to implement and test independently.

  3. Extensibility — If unmute/unresolve are needed later, they can be added as POST /errors/:id/unmute and POST /errors/:id/unresolve without touching the existing endpoints.

  4. Pi tool mapping — Each endpoint maps 1:1 to a pi tool (mute_production_errorPOST /errors/:id/mute, resolve_production_errorPOST /errors/:id/resolve). This makes the prompt guidelines simple and the tool behavior predictable.

  5. HTTP semantics — POST is appropriate here because these are non-idempotent actions that change server state. POST on a sub-resource path is a well-established REST pattern.

Architecture Impact

Component Impact
MusicLibrary.Errors Add mute_error/1, resolve_error/1 context functions
MusicLibraryWeb.ErrorController Add mute/2, resolve/2 actions
MusicLibraryWeb.ErrorJSON Add render functions for success/error responses
MusicLibraryWeb.Router Add two POST routes
.pi/extensions/prod-errors/index.ts Add two tools, add TUI keybindings
test/music_library_web/controllers/error_controller_test.exs Add tests for new endpoints
test/music_library/errors_test.exs Add tests for new context functions (if separate test file exists)
docs/architecture.md Update Routes section if it lists API routes

No changes needed to: supervision tree, PubSub, schemas, migrations, Oban workers, LiveViews, external APIs.

Performance Profile

  • Database: Single-row UPDATE by primary key — O(1). SQLite handles this efficiently.
  • No N+1 risk: These are simple UPDATE operations, no joins or preloads.
  • HTTP latency: Sub-millisecond for the DB update + minimal JSON encoding.
  • Concurrency: SQLite serializes writes — moot for low-frequency admin actions like mute/resolve.
  • No paid API calls — these are entirely local operations.

Cost Profile

Zero incremental cost. No external API calls, no additional compute, no additional storage.

Production Infrastructure Steps

No production infrastructure changes needed. The new endpoints are served by the existing Phoenix app. No new environment variables, no DNS changes, no firewall rules.

Documentation Updates

File Change
docs/architecture.md Update Routes section if API routes are enumerated there
README (if applicable) N/A — API is internal tooling
.pi/extensions/prod-errors/index.ts Self-documenting through tool descriptions and prompt snippets

Testing

  • Controller tests: Test auth (401 without token), test mute sets muted=true, test resolve sets status=resolved, test 404 for non-existent error, test idempotency (calling mute on already-muted error returns success with no change).
  • Context tests: Test mute_error/1 returns updated error, test resolve_error/1 returns updated error, test error on non-existent ID.