Schema docs (docs/schema) cover tool mapping, input/output contracts and endpoint coverage for all 31 MCP tools; megaplan M1 phases 01-03 applied (namespace rename to read_*/write_*, input schema rectification). Go module provides config loading, Ombi client, and tool registry skeleton for implementation.
32 KiB
Phase 03 — Input Schema Defect Rectification
Objective
Apply all input-schema fixes to 03-input-schemas.md. Below is the complete replacement JSON for every modified tool; unmodified tools carry over verbatim (rename only, Phase 01). Order of ## sections is unchanged.
Prerequisites
- Phase 01 complete (all
##section headers already carry the newread_*/write_*names). - Phase 04 consulted for the string↔int enum maps referenced by
request_type,status,agent,notification_type(the maps themselves are owned by Phase 04; this phase changes the schemas to strings). - Source document to mutate:
docs/schema/03-input-schemas.md.
Specification
3.1 read_media — fix by_request enum
Only change vs. current doc: by_request.media.enum ["movie","tv","artist"] → ["movie","tv","album"]. Adapter maps album→GET /api/v2/Search/artist/request/{requestId} (route segment literally artist, but the ID namespace is album requests — keep the Verify note; response ArtistInformation projects into media_page).
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"oneOf": [
{
"type": "object",
"properties": {
"action": { "const": "details" },
"target": { "$ref": "#/$defs/external" }
},
"required": ["action", "target"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "by_request" },
"media": { "type": "string", "enum": ["movie", "tv", "album"] },
"request_id": { "type": "integer", "minimum": 1 }
},
"required": ["action", "media", "request_id"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "movie_localized" },
"tmdb_id": { "type": "integer", "minimum": 1 },
"language": { "type": "string", "minLength": 1, "maxLength": 20 }
},
"required": ["action", "tmdb_id", "language"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "ratings" },
"media": { "type": "string", "enum": ["movie", "tv"] },
"name": { "type": "string", "minLength": 1, "maxLength": 300 },
"year": { "type": "integer", "minimum": 1870, "maximum": 9999 }
},
"required": ["action", "media", "name", "year"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "streaming" },
"media": { "type": "string", "enum": ["movie", "tv"] },
"tmdb_id": { "type": "integer", "minimum": 1 }
},
"required": ["action", "media", "tmdb_id"],
"additionalProperties": false
}
],
"$defs": {
"external": {
"oneOf": [
{
"type": "object",
"properties": {
"media": { "const": "movie" },
"provider": { "const": "tmdb" },
"id": { "type": "integer", "minimum": 1 }
},
"required": ["media", "provider", "id"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"media": { "const": "movie" },
"provider": { "const": "imdb" },
"id": { "type": "string", "minLength": 1, "maxLength": 32, "pattern": "^tt[0-9]+$" }
},
"required": ["media", "provider", "id"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"media": { "const": "tv" },
"provider": { "type": "string", "enum": ["tmdb", "tvdb"] },
"id": { "type": "integer", "minimum": 1 }
},
"required": ["media", "provider", "id"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"media": { "type": "string", "enum": ["artist", "album"] },
"provider": { "const": "musicbrainz" },
"id": { "type": "string", "minLength": 1, "maxLength": 100 }
},
"required": ["media", "provider", "id"],
"additionalProperties": false
}
]
}
}
}
3.2 read_requests — optional status (default all), sort → sort_direction
statusleavesrequired; gains"default": "all"(documentation — adapter applies it).sortobject removed; flat optionalsort_directionenum["asc","desc"],"default": "desc". Wire:sort=requestDate,sortOrder=asc|descpath segments —request_dateremains the only published sort field.$defs/sortdeleted;$defs/pageunchanged.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"oneOf": [
{
"type": "object",
"properties": {
"action": { "const": "list" },
"media": { "type": "string", "enum": ["movie", "tv"] },
"status": {
"type": "string",
"enum": ["all", "pending", "processing", "available", "denied", "unavailable"],
"default": "all"
},
"sort_direction": { "type": "string", "enum": ["asc", "desc"], "default": "desc" },
"page": { "$ref": "#/$defs/page" }
},
"required": ["action", "media"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "list" },
"media": { "const": "album" },
"status": {
"type": "string",
"enum": ["all", "pending", "processing", "available", "denied"],
"default": "all"
},
"sort_direction": { "type": "string", "enum": ["asc", "desc"], "default": "desc" },
"page": { "$ref": "#/$defs/page" }
},
"required": ["action", "media"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "get" },
"target": {
"type": "object",
"properties": {
"kind": { "type": "string", "enum": ["movie", "tv_parent"] },
"id": { "type": "integer", "minimum": 1 }
},
"required": ["kind", "id"],
"additionalProperties": false
}
},
"required": ["action", "target"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "children" },
"parent_request_id": { "type": "integer", "minimum": 1 },
"page": { "$ref": "#/$defs/page" }
},
"required": ["action", "parent_request_id"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "search" },
"media": { "type": "string", "enum": ["movie", "tv", "album"] },
"query": { "type": "string", "minLength": 1, "maxLength": 200 },
"page": { "$ref": "#/$defs/page" }
},
"required": ["action", "media", "query"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "recent" },
"page": { "$ref": "#/$defs/page" }
},
"required": ["action"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "retry_queue" },
"page": { "$ref": "#/$defs/page" }
},
"required": ["action"],
"additionalProperties": false
}
],
"$defs": {
"page": {
"type": "object",
"properties": {
"offset": { "type": "integer", "minimum": 0, "default": 0 },
"limit": { "type": "integer", "minimum": 1, "maximum": 100, "default": 25 }
},
"required": [],
"additionalProperties": false
}
}
}
3.3 write_request_create — is_4k optional + season selection mode
- Movie branch:
is_4kremoved fromrequired("default": falsedocuments intent; adapter defaults false →is4kRequest:false— note: omittingis4kRequestentirely is also acceptable wire-wise since the field is optional upstream; the adapter MUST emitfalseexplicitly for deterministic diffs). selectiongains a third oneOf branch:mode:"season"+season_numbersarray.- Wire construction for
seasonmode (Design): for eachseason_numbersentry the adapter resolves the show's season/episode list via the same upstream call used byread_media.details(TV, same provider namespace), then emitsseasons:[{seasonNumber:n, episodes:[{episodeNumber:e},…]}]with every listed episode;requestAll/firstSeason/latestSeasonallfalse. If episode metadata yields zero episodes for a requested season →INVALID_ARGUMENTwithfield:"season_numbers". Sendingepisodes:[]as a whole-season shortcut remains Verify-gated and is not the default. overrideskeys alreadyroot_folder_id/quality_profile_id(unchanged — they are the canonical names other tools now align to).
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"oneOf": [
{
"type": "object",
"properties": {
"action": { "const": "movie" },
"tmdb_id": { "type": "integer", "minimum": 1 },
"is_4k": { "type": "boolean", "default": false },
"language": { "type": "string", "minLength": 1, "maxLength": 20 },
"on_behalf_user_id": { "type": "string", "minLength": 1, "maxLength": 200 },
"overrides": { "$ref": "#/$defs/overrides" }
},
"required": ["action", "tmdb_id"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "tv" },
"provider": { "const": "tmdb" },
"id": { "type": "integer", "minimum": 1 },
"selection": { "$ref": "#/$defs/selection" },
"language": { "type": "string", "minLength": 1, "maxLength": 20 },
"language_profile_id": { "type": "integer", "minimum": 1 },
"on_behalf_user_id": { "type": "string", "minLength": 1, "maxLength": 200 },
"overrides": { "$ref": "#/$defs/overrides" }
},
"required": ["action", "provider", "id", "selection"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "tv" },
"provider": { "const": "tvdb" },
"id": { "type": "integer", "minimum": 1 },
"selection": { "$ref": "#/$defs/selection" },
"language_profile_id": { "type": "integer", "minimum": 1 },
"on_behalf_user_id": { "type": "string", "minLength": 1, "maxLength": 200 },
"overrides": { "$ref": "#/$defs/overrides" }
},
"required": ["action", "provider", "id", "selection"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "album" },
"musicbrainz_id": { "type": "string", "minLength": 1, "maxLength": 100 },
"requested_by_alias": { "type": "string", "minLength": 1, "maxLength": 200 }
},
"required": ["action", "musicbrainz_id"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "collection" },
"collection_id": { "type": "integer", "minimum": 1 }
},
"required": ["action", "collection_id"],
"additionalProperties": false
}
],
"$defs": {
"overrides": {
"type": "object",
"properties": {
"root_folder_id": { "type": "integer", "minimum": 1 },
"quality_profile_id": { "type": "integer", "minimum": 1 }
},
"required": [],
"additionalProperties": false,
"minProperties": 1
},
"selection": {
"oneOf": [
{
"type": "object",
"properties": {
"mode": { "type": "string", "enum": ["all", "first_season", "latest_season"] }
},
"required": ["mode"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"mode": { "const": "season" },
"season_numbers": {
"type": "array",
"items": { "type": "integer", "minimum": 0 },
"minItems": 1,
"maxItems": 200,
"uniqueItems": true
}
},
"required": ["mode", "season_numbers"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"mode": { "const": "episodes" },
"seasons": {
"type": "array",
"items": {
"type": "object",
"properties": {
"season_number": { "type": "integer", "minimum": 0 },
"episodes": {
"type": "array",
"items": { "type": "integer", "minimum": 1 },
"minItems": 1,
"maxItems": 1000,
"uniqueItems": true
}
},
"required": ["season_number", "episodes"],
"additionalProperties": false
},
"minItems": 1,
"maxItems": 200,
"uniqueItems": true
}
},
"required": ["mode", "seasons"],
"additionalProperties": false
}
]
}
}
}
3.4 write_request_moderate — is_4k optional in all four movie branches
All four media:"movie" branches (approve, deny, mark_available, mark_unavailable) drop is_4k from required; the property stays with "default": false. Adapter emits is4K:false when omitted. TV/album branches unchanged.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"oneOf": [
{
"type": "object",
"properties": {
"action": { "const": "approve" },
"media": { "const": "movie" },
"request_id": { "type": "integer", "minimum": 1 },
"is_4k": { "type": "boolean", "default": false }
},
"required": ["action", "media", "request_id"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "deny" },
"media": { "const": "movie" },
"request_id": { "type": "integer", "minimum": 1 },
"is_4k": { "type": "boolean", "default": false },
"reason": { "type": "string", "minLength": 1, "maxLength": 2000 }
},
"required": ["action", "media", "request_id", "reason"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "mark_available" },
"media": { "const": "movie" },
"request_id": { "type": "integer", "minimum": 1 },
"is_4k": { "type": "boolean", "default": false }
},
"required": ["action", "media", "request_id"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "mark_unavailable" },
"media": { "const": "movie" },
"request_id": { "type": "integer", "minimum": 1 },
"is_4k": { "type": "boolean", "default": false }
},
"required": ["action", "media", "request_id"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "approve" },
"media": { "type": "string", "enum": ["tv", "album"] },
"request_id": { "type": "integer", "minimum": 1 }
},
"required": ["action", "media", "request_id"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "deny" },
"media": { "type": "string", "enum": ["tv", "album"] },
"request_id": { "type": "integer", "minimum": 1 },
"reason": { "type": "string", "minLength": 1, "maxLength": 2000 }
},
"required": ["action", "media", "request_id", "reason"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "mark_available" },
"media": { "type": "string", "enum": ["tv", "album"] },
"request_id": { "type": "integer", "minimum": 1 }
},
"required": ["action", "media", "request_id"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "mark_unavailable" },
"media": { "type": "string", "enum": ["tv", "album"] },
"request_id": { "type": "integer", "minimum": 1 }
},
"required": ["action", "media", "request_id"],
"additionalProperties": false
}
]
}
3.5 write_request_options — unified override keys
advanced.options properties renamed to the canonical root_folder_id/quality_profile_id (was root_path_override/quality_override); language_profile_id unchanged. Wire mapping: root_folder_id→rootPathOverride, quality_profile_id→qualityOverride, language_profile_id→languageProfile. tv_root/tv_quality branches already use the canonical names — unchanged.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"oneOf": [
{
"type": "object",
"properties": {
"action": { "const": "advanced" },
"media": { "type": "string", "enum": ["movie", "tv"] },
"request_id": { "type": "integer", "minimum": 1 },
"options": {
"type": "object",
"properties": {
"root_folder_id": { "type": "integer", "minimum": 1 },
"quality_profile_id": { "type": "integer", "minimum": 1 },
"language_profile_id": { "type": "integer", "minimum": 1 }
},
"required": [],
"additionalProperties": false,
"minProperties": 1
}
},
"required": ["action", "media", "request_id", "options"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "tv_root" },
"parent_request_id": { "type": "integer", "minimum": 1 },
"root_folder_id": { "type": "integer", "minimum": 1 }
},
"required": ["action", "parent_request_id", "root_folder_id"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "tv_quality" },
"parent_request_id": { "type": "integer", "minimum": 1 },
"quality_profile_id": { "type": "integer", "minimum": 1 }
},
"required": ["action", "parent_request_id", "quality_profile_id"],
"additionalProperties": false
}
]
}
3.6 write_request_reprocess — string request_type, optional is_4k, unwrap
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"request_type": { "type": "string", "enum": ["movie", "tv", "album"] },
"request_id": { "type": "integer", "minimum": 1 },
"is_4k": { "type": "boolean", "default": false }
},
"required": ["request_type", "request_id"],
"additionalProperties": false
}
Wire: POST /api/v2/Requests/reprocess/{type}/{requestId}/{is4K} with type = Phase 04 RequestType int (tv→0, movie→1, album→2) and is4K defaulting false.
3.7 write_issue_create — request_type string enum + unwrap
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"title": { "type": "string", "minLength": 1, "maxLength": 300 },
"subject": { "type": "string", "minLength": 1, "maxLength": 300 },
"description": { "type": "string", "minLength": 1, "maxLength": 10000 },
"category_id": { "type": "integer", "minimum": 1 },
"request_type": { "type": "string", "enum": ["movie", "tv", "album"] },
"request_id": { "type": "integer", "minimum": 1 },
"provider_id": { "type": "string", "minLength": 1, "maxLength": 200 }
},
"required": ["title", "description", "category_id", "request_type"],
"additionalProperties": false,
"anyOf": [
{ "required": ["request_id"] },
{ "required": ["provider_id"] }
]
}
3.8 read_issues — status string enum replaces status_code
list and summary branches: status stays required (upstream path needs a status) as enum ["pending","in_progress","resolved","closed"]. $defs/status_code deleted; $defs/page unchanged.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"oneOf": [
{
"type": "object",
"properties": {
"action": { "const": "list" },
"status": { "type": "string", "enum": ["pending", "in_progress", "resolved", "closed"] },
"page": { "$ref": "#/$defs/page" }
},
"required": ["action", "status"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "summary" },
"status": { "type": "string", "enum": ["pending", "in_progress", "resolved", "closed"] },
"page": { "$ref": "#/$defs/page" }
},
"required": ["action", "status"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "get" },
"issue_id": { "type": "integer", "minimum": 1 }
},
"required": ["action", "issue_id"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "by_request" },
"request_id": { "type": "integer", "minimum": 1 }
},
"required": ["action", "request_id"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "by_provider" },
"provider_id": { "type": "string", "minLength": 1, "maxLength": 200 }
},
"required": ["action", "provider_id"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "provider_summary" },
"provider_id": { "type": "string", "minLength": 1, "maxLength": 200 }
},
"required": ["action", "provider_id"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "comments" },
"issue_id": { "type": "integer", "minimum": 1 },
"page": { "$ref": "#/$defs/page" }
},
"required": ["action", "issue_id"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "counts" }
},
"required": ["action"],
"additionalProperties": false
}
],
"$defs": {
"page": {
"type": "object",
"properties": {
"offset": { "type": "integer", "minimum": 0, "default": 0 },
"limit": { "type": "integer", "minimum": 1, "maximum": 100, "default": 25 }
},
"required": [],
"additionalProperties": false
}
}
}
3.9 write_issue_manage — status string enum
set_status branch: status required, enum ["pending","in_progress","resolved","closed"]; $defs/status_code deleted. Wire body {issueId, status:<int>}.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"oneOf": [
{
"type": "object",
"properties": {
"action": { "const": "set_status" },
"issue_id": { "type": "integer", "minimum": 1 },
"status": { "type": "string", "enum": ["pending", "in_progress", "resolved", "closed"] }
},
"required": ["action", "issue_id", "status"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "delete" },
"issue_id": { "type": "integer", "minimum": 1 }
},
"required": ["action", "issue_id"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "delete_comment" },
"comment_id": { "type": "integer", "minimum": 1 }
},
"required": ["action", "comment_id"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "create_category" },
"value": { "type": "string", "minLength": 1, "maxLength": 200 }
},
"required": ["action", "value"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"action": { "const": "delete_category" },
"category_id": { "type": "integer", "minimum": 1 }
},
"required": ["action", "category_id"],
"additionalProperties": false
}
]
}
3.10 write_settings_patch — string enums in NotificationTemplates
Replace the Ombi_Store_Entities_NotificationTemplates $def only; every section branch and all other $defs carry over byte-identical. Patch keys notification_type/agent translate to wire notificationType/agent with int values via Phase 04 before merging.
"Ombi_Store_Entities_NotificationTemplates": {
"type": "object",
"properties": {
"notification_type": {
"type": "string",
"enum": [
"new_request",
"issue",
"request_available",
"request_approved",
"admin_note",
"test",
"request_declined",
"item_added_to_fault_queue",
"welcome_email",
"issue_resolved",
"issue_comment",
"newsletter",
"partially_available",
"plex_watchlist_token_expired",
"request_deleted",
"issue_in_progress",
"issue_deleted"
]
},
"agent": {
"type": "string",
"enum": [
"email",
"discord",
"pushbullet",
"pushover",
"telegram",
"slack",
"mattermost",
"mobile",
"gotify",
"webhook",
"whatsapp",
"ntfy"
]
},
"subject": { "type": "string" },
"message": { "type": "string" },
"enabled": { "type": "boolean" }
},
"required": [],
"additionalProperties": false
}
3.11 Single-element oneOf unwraps (9 tools)
Mechanical rule: delete the oneOf wrapper; promote the sole branch's type/properties/required/additionalProperties/anyOf to the schema root; $defs unchanged. Complete results:
write_issue_comment:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"issue_id": { "type": "integer", "minimum": 1 },
"comment": { "type": "string", "minLength": 1, "maxLength": 10000 }
},
"required": ["issue_id", "comment"],
"additionalProperties": false
}
write_vote:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"media": { "type": "string", "enum": ["movie", "tv", "album"] },
"request_id": { "type": "integer", "minimum": 1 },
"direction": { "type": "string", "enum": ["up", "down"] }
},
"required": ["media", "request_id", "direction"],
"additionalProperties": false
}
write_request_delete:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"target": { "$ref": "#/$defs/target" }
},
"required": ["target"],
"additionalProperties": false,
"$defs": {
"target": {
"oneOf": [
{
"type": "object",
"properties": {
"kind": { "type": "string", "enum": ["movie", "tv_parent", "tv_child", "album"] },
"id": { "type": "integer", "minimum": 1 }
},
"required": ["kind", "id"],
"additionalProperties": false
}
]
}
}
}
read_settings:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"section": {
"type": "string",
"enum": [
"custom_page", "ombi", "base_url", "plex", "client_id", "emby",
"jellyfin", "landingpage", "customization", "default_language",
"themes", "sonarr", "radarr", "lidarr", "lidarrenabled",
"authentication", "update", "user_management", "couchpotato",
"dognzb", "sickrage", "jobs", "issues", "issuesenabled", "vote",
"voteenabled", "themoviedb", "notifications.email",
"notifications.email.enabled", "notifications.discord",
"notifications.telegram", "notifications.pushbullet",
"notifications.pushover", "notifications.slack",
"notifications.mattermost", "notifications.twilio",
"notifications.mobile", "notifications.gotify",
"notifications.ntfy", "notifications.webhook",
"notifications.newsletter"
]
}
},
"required": ["section"],
"additionalProperties": false
}
write_integration_test:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"service": {
"type": "string",
"enum": [
"discord", "pushbullet", "pushover", "gotify", "ntfy", "webhook",
"mattermost", "slack", "email", "plex", "emby", "jellyfin",
"radarr", "sonarr", "couchpotato", "telegram", "sickrage",
"newsletter", "mobile", "lidarr", "whatsapp"
]
},
"profile_id": { "type": "string", "minLength": 1, "maxLength": 200 }
},
"required": ["service", "profile_id"],
"additionalProperties": false
}
write_notification_send:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"subject": { "type": "string", "minLength": 1, "maxLength": 300 },
"body": { "type": "string", "minLength": 1, "maxLength": 20000 },
"bcc": { "type": "boolean" },
"user_ids": {
"type": "array",
"items": { "type": "string", "minLength": 1, "maxLength": 200 },
"minItems": 1,
"maxItems": 100,
"uniqueItems": true
}
},
"required": ["subject", "body", "bcc", "user_ids"],
"additionalProperties": false
}
write_retry_remove:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"queue_id": { "type": "integer", "minimum": 1 }
},
"required": ["queue_id"],
"additionalProperties": false
}
(Phase 3.7 write_issue_create above is also an unwrap — already printed.)
3.12 Untouched tools — carry over verbatim (rename only)
read_search, read_discover, read_reference, read_request_stats, read_votes, read_users, read_library, read_server, read_integration, write_request_subscribe, write_user_preferences, write_user_manage, write_job_run, read_logs. These keep byte-identical schema bodies; only the ## heading renames.
Target artefacts
docs/schema/03-input-schemas.md— every schema block replaced or unwrapped per §§3.1–3.11; the 14 tools in §3.12 carry over byte-identical (heading already renamed by Phase 01). Section order unchanged.
Verification gates
is_4kappears in norequiredarray anywhere in the file.request_type_code/status_code/sortobject/root_path_override/quality_overrideabsent.season_numberspresent withminItems:1,uniqueItems:true,minimum:0.by_requestenum is exactly["movie","tv","album"].- No
oneOfwrapper has exactly one element. - All JSON blocks validate under
Draft202012Validator; each tool accepts its minimal valid object and rejects{}where any field is required. read_requestsaccepts{"action":"list","media":"movie"}(status/sort_direction defaults adapter-side).
Evidence labels
- Documented — wire mappings cited for
sort/sortOrder,rootPathOverride/qualityOverride/languageProfile,is4K/is4kRequest,reprocesspath ints. - Design —
season_numbersarray semantics and adapter episode expansion (D6); canonicalroot_folder_id/quality_profile_idnaming; adapter-emittedis4kRequest:falsefor deterministic diffs. - Verify —
album→artist/requestroute-segment asymmetry note;episodes:[]whole-season shortcut remains Verify-gated.