@withpica/mcp-server 2.56.0 → 2.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/README.md +9 -9
  3. package/dist/lib/changelog.generated.d.ts +2 -2
  4. package/dist/lib/changelog.generated.d.ts.map +1 -1
  5. package/dist/lib/changelog.generated.js +2 -2
  6. package/dist/lib/changelog.generated.js.map +1 -1
  7. package/dist/prompts/index.js +1 -1
  8. package/dist/prompts/index.js.map +1 -1
  9. package/dist/resources/index.d.ts.map +1 -1
  10. package/dist/resources/index.js +5 -0
  11. package/dist/resources/index.js.map +1 -1
  12. package/dist/resources/required-schemas.generated.d.ts +13 -1
  13. package/dist/resources/required-schemas.generated.d.ts.map +1 -1
  14. package/dist/resources/required-schemas.generated.js +23 -1
  15. package/dist/resources/required-schemas.generated.js.map +1 -1
  16. package/dist/resources/required-schemas.source.d.ts.map +1 -1
  17. package/dist/resources/required-schemas.source.js +17 -1
  18. package/dist/resources/required-schemas.source.js.map +1 -1
  19. package/dist/server-instructions.d.ts +4 -3
  20. package/dist/server-instructions.d.ts.map +1 -1
  21. package/dist/server-instructions.js +4 -1
  22. package/dist/server-instructions.js.map +1 -1
  23. package/dist/server.js +2 -2
  24. package/dist/skills/skills.generated.d.ts.map +1 -1
  25. package/dist/skills/skills.generated.js +11 -2
  26. package/dist/skills/skills.generated.js.map +1 -1
  27. package/dist/tools/agreement-types.d.ts.map +1 -1
  28. package/dist/tools/agreement-types.js +5 -1
  29. package/dist/tools/agreement-types.js.map +1 -1
  30. package/dist/tools/analytics.d.ts.map +1 -1
  31. package/dist/tools/analytics.js +6 -7
  32. package/dist/tools/analytics.js.map +1 -1
  33. package/dist/tools/assets.d.ts.map +1 -1
  34. package/dist/tools/assets.js +34 -2
  35. package/dist/tools/assets.js.map +1 -1
  36. package/dist/tools/collaborations.d.ts +19 -0
  37. package/dist/tools/collaborations.d.ts.map +1 -0
  38. package/dist/tools/collaborations.js +45 -0
  39. package/dist/tools/collaborations.js.map +1 -0
  40. package/dist/tools/collaborators.d.ts +8 -0
  41. package/dist/tools/collaborators.d.ts.map +1 -1
  42. package/dist/tools/collaborators.js +345 -8
  43. package/dist/tools/collaborators.js.map +1 -1
  44. package/dist/tools/credits.d.ts +1 -0
  45. package/dist/tools/credits.d.ts.map +1 -1
  46. package/dist/tools/credits.js +110 -1
  47. package/dist/tools/credits.js.map +1 -1
  48. package/dist/tools/dashboard.d.ts.map +1 -1
  49. package/dist/tools/dashboard.js +59 -7
  50. package/dist/tools/dashboard.js.map +1 -1
  51. package/dist/tools/discovery.d.ts.map +1 -1
  52. package/dist/tools/discovery.js +26 -1
  53. package/dist/tools/discovery.js.map +1 -1
  54. package/dist/tools/explainability.d.ts.map +1 -1
  55. package/dist/tools/explainability.js +43 -15
  56. package/dist/tools/explainability.js.map +1 -1
  57. package/dist/tools/exports.d.ts.map +1 -1
  58. package/dist/tools/exports.js +14 -4
  59. package/dist/tools/exports.js.map +1 -1
  60. package/dist/tools/feedback.d.ts.map +1 -1
  61. package/dist/tools/feedback.js +70 -26
  62. package/dist/tools/feedback.js.map +1 -1
  63. package/dist/tools/index.d.ts.map +1 -1
  64. package/dist/tools/index.js +46 -2
  65. package/dist/tools/index.js.map +1 -1
  66. package/dist/tools/metadata.d.ts.map +1 -1
  67. package/dist/tools/metadata.js +115 -0
  68. package/dist/tools/metadata.js.map +1 -1
  69. package/dist/tools/onboarding.js +2 -2
  70. package/dist/tools/onboarding.js.map +1 -1
  71. package/dist/tools/recovery-hints.d.ts.map +1 -1
  72. package/dist/tools/recovery-hints.js +164 -0
  73. package/dist/tools/recovery-hints.js.map +1 -1
  74. package/dist/tools/report-issue.d.ts.map +1 -1
  75. package/dist/tools/report-issue.js +1 -0
  76. package/dist/tools/report-issue.js.map +1 -1
  77. package/dist/tools/settings.js +3 -3
  78. package/dist/tools/settings.js.map +1 -1
  79. package/dist/tools/split-sheets.d.ts.map +1 -1
  80. package/dist/tools/split-sheets.js +19 -2
  81. package/dist/tools/split-sheets.js.map +1 -1
  82. package/dist/tools/telegram.js +1 -1
  83. package/dist/tools/telegram.js.map +1 -1
  84. package/dist/tools/users.d.ts +38 -0
  85. package/dist/tools/users.d.ts.map +1 -0
  86. package/dist/tools/users.js +192 -0
  87. package/dist/tools/users.js.map +1 -0
  88. package/dist/tools/works.d.ts +6 -0
  89. package/dist/tools/works.d.ts.map +1 -1
  90. package/dist/tools/works.js +112 -5
  91. package/dist/tools/works.js.map +1 -1
  92. package/package.json +8 -5
  93. package/server.json +2 -2
@@ -1,6 +1,6 @@
1
1
  // Copyright (c) 2024-2026 Withpica Ltd. All rights reserved.
2
2
  // Generated by scripts/build-changelog.ts — do not edit.
3
- export const CHANGELOG_MD = "# Changelog\n\nAll notable changes to `@withpica/mcp-server` will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n> **Rule of the road:** every version bump to this package MUST land with a\n> matching entry here in the same commit. See the project's \"npm publish\n> discipline\" memory entry for the enforcement rationale.\n\n## [Unreleased]\n\n## [2.56.0] - 2026-05-14\n\n### Added\n\n- **`conflict_strategy` arg on `pica_import_execute` (PR #427, promoted to main via PR #428 on 2026-05-13).**\n New optional input on the import executor MCP tool. Enum `[\"error\", \"skip\"]`,\n defaults to `\"error\"` to preserve current bulk-batch behavior. `\"skip\"` falls\n back to per-row insert on Postgres 23505 unique-constraint collisions\n (duplicate `tunecode`/`iswc`), so a single duplicate no longer kills the\n entire batch — duplicates surface as warnings and the rest of the rows still\n land. Backward-compatible (existing callers without `conflict_strategy` get\n the default `\"error\"` behavior). Pairs with the underlying server-side\n satellite-write fix that also shipped in PR #427 (PRO-registration fields\n routed to `work_registrations` per ADR-125 WS5).\n\n## [2.55.0] - 2026-05-13\n\n### Added\n\n- **`pica_release_notes` tool + `release-notes://withpica/mcp-server/latest` Resource (PR #412, merged to develop 2026-05-13, promoted to main via PR #417).**\n Agent-facing surface for platform release notes. Reads `CHANGELOG.md`\n embedded at build time via `scripts/build-changelog.ts`. Returns the\n last 3 versions by default with optional `since_version` and `sections`\n filters. Resource counterpart serves the full CHANGELOG for\n Resource-native clients (SEP-2640 bridge pattern, consistent with\n ADR-140 Phase 2b). Disambiguated from catalog \"what's new\" phrasing\n by tool name (`release_notes` ≠ \"what's new\") + NOT-FOR disclaimer\n in description pointing catalog phrasing at `pica_dashboard_briefing` /\n `pica_works_query`.\n\n## [2.54.0] - 2026-05-13\n\n> Skipped `2.53.0` — that version was claimed by a parallel publish on\n> 2026-05-12 before this branch's publish chain ran. Sister of the\n> sdk's `1.26.0 → 1.27.0` skip in the same chain. See the\n> `feedback_npm_publish_chain_order` memory entry for the pattern.\n\n### Added\n\n- **`pica_import_analyze` / `pica_import_validate` / `pica_import_execute` accept `file_id` as an alternative to `file_content` (PR #415 → develop `2e74411bc`, PR #416 → main `3849c98e4`).**\n Closes the upload-then-import loop. After `pica_upload` →\n `pica_upload_complete`, agents can pass the resulting `documents.id`\n as `file_id` instead of pasting raw CSV content into a tool argument.\n Server resolves the bytes via a short-lived signed URL — org-scoped,\n CSV MIME-validated, 20 MB cap, UTF-8 validated. Requires\n `@withpica/mcp-sdk@^1.27.0` for the matching `ImportFileSource`\n type. Backwards-compatible: existing `file_content` callers\n unchanged.\n\n### Fixed\n\n- **Stale analyze-route assertions in `app/api/admin/import/__tests__/` flipped 500 → 400 (PR #396 era cleanup, bundled with the bridge).**\n Tests had been asserting the pre-PR-#396 500 status for parseCSV\n throws; route correctly returns 400 (caller-supplied bad input) since\n that fix. Loosened 4 `\"fileContent is required\"` exact-match\n assertions to `/fileContent or fileId/i` to match the new mutually-\n exclusive contract.\n\n## [2.52.2] - 2026-05-13\n\n### Changed\n\n- **Server-instructions polish — workspace deeplink hint after writes + paragraph trims (commits `5a2bca4a1`, `7a3e2c226`).**\n Added a one-line coaching that agents share `https://withpica.com/workspace?type=<entity>&id=<id>` after every write tool so users get a clickable receipt back to the workspace — the cheapest version of the \"chat ↔ workspace\" tie-in (ADR-234), no per-tool sweep, agents construct the URL from the entity ID already in every write response. Two trims funded the addition: the `pica_execute` collision disclaimer compressed to one sentence (~120 chars saved) and the peer-MCP paragraph dropped its inline URI-scheme inventory (`gmail://` etc.) in favour of pointing at `docs/mcp-source-uri-conventions.md`, while gaining a load-bearing sentence that citations persist verbatim and propagate to applied entities (ADR-178 — `field_proposals.sources` jsonb + on-apply propagation to `recordings.field_sources`). Token budget restored 2400 → 2300, final length 2192/2300, headroom 108 chars.\n\n## [2.52.1] - 2026-05-13\n\n### Fixed\n\n- **`pica_import_analyze` TypeError (`parsed.rows` → `parsed.preview`) (PR #408, shipped 2026-05-13).**\n Every successful analyze call returned `CSV analyze failed: Cannot read\nproperties of undefined (reading 'slice')`. Three-layer contract drift:\n the route returns `parsed: { headers, preview, totalRows, delimiter }`,\n the SDK type declared `parsed: { headers, rows, totalRows }` (wrong\n field, missing `delimiter`), and the MCP executor read `parsed.rows\n.slice(0, 3)`. The SDK's `request<T>()` JSON.parse-cast with no runtime\n validation let TypeScript compile the lie. Aligned executor to read\n `parsed.preview`; SDK type aligned in `@withpica/mcp-sdk@1.25.1`.\n\n## [2.52.0] - 2026-05-12\n\nCloses out the accumulated Unreleased buffer (some entries below shipped in\n2.49.0–2.51.0 but were never moved out of Unreleased; the `lint-changelog`\nscript that lands in the next bump prevents this drift going forward).\n\n### Added\n\n- **File-delivery tools `pica_file_deliver` + `pica_file_revoke_delivery` (PR #385, shipped 2026-05-12 in `@withpica/mcp-server@2.52.0`).**\n Agent-facing counterpart to the upload tools — symmetric with `pica_upload` /\n `pica_upload_file`. Wraps the first-class `/admin/files/deliver` surface\n (token + recipient_email + expiry + revocation) so agents can share files\n out of PICA with audit-trail accountability and a kill switch. Default\n expiry 48 hours; max 168 (one week). Registered in `discovery.uploads`\n (now bidirectional), `metadata.ts`, `recovery-hints.ts` (deliver →\n `rich_response`, revoke → `terminal`), and `lib/billing/tool-cost-model.data.ts`\n (deliver → export/EXPORT, revoke → admin/ADMIN). Backed by new\n `FilesResource` on `@withpica/mcp-sdk@1.25.0`.\n\n- **ADR-214 follow-up: cross-transport resource parity lint (`scripts/lint-resource-coverage.ts`).**\n Asserts that `ResourceRegistry.listResources()` (stdio) and `UI_RESOURCE_DEFS` / the\n anonymous-lobby handler (HTTP, `app/api/mcp/route.ts`) expose the same resource URIs.\n Catches the W2 drift class — resources added to one transport only — before publish.\n Four assertions: stdio-lobby ⊆ HTTP-lobby, HTTP-lobby ⊆ stdio-lobby,\n stdio-authenticated \\ ADR-152-carve-out ⊆ HTTP-authenticated, and the inverse\n HTTP-authenticated ⊆ stdio-authenticated. Wired into `prepublishOnly` (after\n `lint:agent-guide`) and `.github/workflows/mcp-tool-lint.yml`.\n\n **Pre-existing drift detected:** `pica://schemas/sync-placement-required` is present\n in `UI_RESOURCE_DEFS` (added in 2.47.0 per CHANGELOG) but absent from\n `ResourceRegistry.listResources()`. The lint correctly flags this; see the PR for\n the fix path.\n\n### Changed\n\n- **`metadata.test.ts` invariants tightened + counts re-baselined (PR #385).**\n Four long-standing failures resolved as part of the file-delivery sweep:\n (1) stale total-count assertion (175 → 242) reframed as a documented\n tripwire — drift means a tool was added without a `TOOL_METADATA` entry;\n (2) stale destructive-count assertion (12 → 17) — same shape, security-\n relevant because the destructive-tool dispatcher routes on `risk`;\n (3) `display_name` lowercase rule was over-strict — relaxed to \"first\n character lowercase\" so legitimate acronyms (S3, GDPR, ISNI, PICA, Azure,\n OAuth) pass per `.claude/rules/ui-components.md`'s proper-noun convention;\n (4) `pica_storage_disconnect` had `risk: \"destructive\"` + `retry_safe: true`\n in violation of the destructive-tool invariant — flipped `retry_safe` to\n `false`. Two-step confirmation token remains the actual safety mechanism;\n the tool's data-level idempotence claim stays true.\n\n- **Tool registry catch path now forwards `error_message` to the audit log (PR #308).**\n When a tool throws, the registry calls `formatError()` and now passes the\n parsed `message` through to `logToolExecution` as `error_message`. Pre-fix,\n every error row in `mcp_audit_log` landed with `error_message=null` because\n the wire shape stripped the field — even when the wrapper held the\n underlying cause. Net effect for diagnostics: rows like the 116 silent\n `pica_merge_duplicates` failures on 2026-04-09 (which couldn't be\n attributed to any specific cause) will now carry the message going forward.\n Sister change in `@withpica/mcp-utils` adds the field to `McpAuditEntry`.\n\n- **`pica_integrations_status` advertisement updated to current tools (PR #308).**\n ADR-179 (commit `dc1bfca72`, 2026-04-21) folded the six per-source\n `pica_enrich_*` tools into `pica_resolve_work` / `pica_resolve_person` /\n `pica_resolve_recording` with a `sources:[...]` parameter, then removed\n them. But `mcp-server/src/tools/integrations.ts` continued to advertise\n the removed names in the `platformReads` list, the tool description, and\n the summary prose. Agents reading the advertisement called names that no\n longer existed → UNKNOWN*ERROR loops on every catalog-enrichment ask\n routed through MLC/Spotify/MusicBrainz/YouTube/Discogs/ISNI. Now points\n at the surviving tools with the correct source value. Two regression\n tests in `integrations.test.ts` lock down that no removed\n `pica_enrich*\\*`tool name appears in the advertised`use_via` strings.\n\n## [2.48.0] - 2026-05-03\n\n### Changed\n\n- **Tool description scrub (PR #188).** Stripped internal-only ADR pointers and\n email-vendor names from user-visible tool descriptions across batch A\n (agreement-types, agreements, bulk, collaborators, credits), batch B\n (app-tools, feedback, projects, enrichment, recordings), and batch C.\n Replaced ADR-N references with the concept the ADR documented (e.g.\n \"ADR-198 round-trip\" → \"verify the credit persisted\") and removed\n Postmark from collaborator bulk-invite description and elicitation\n warning text. Tool descriptions surface to third-party agents and shouldn't\n reveal internal infrastructure choices.\n\n- **recovery_hints expansion (PR #188).** Annotation fix + additional\n recovery hints for tools that fan out across sections.\n\n- **`pica_releases_show` best-effort catch markers (ADR-224 convention).** Marked\n the two best-effort catches in `releases-rich.show()` (tracks + cover-art\n fallbacks) with `/* best-effort */` to match the ADR-224 Phase 4 lint\n convention. No behaviour change — the catches were already documented inline;\n this just makes the marker greppable so future scope extensions to `_show`\n tools recognise the intent. Surface audit confirmed all 9 `_inspect` tools\n addressed, 22 `_list` tools clean, no swallow patterns elsewhere.\n\n## [2.47.0] - 2026-05-02\n\n### Added\n\n- **ADR-222 W3 — sync placements MCP tool surface (6 tools).**\n - `pica_sync_placements_query` — list placements with filters (work_id, status, verification_status, brand, production_company, person_id, recording_id, source_license_enquiry_id, min_fee, currency).\n - `pica_sync_placements_inspect` — fetch one placement with linked recordings, sources, agreement, and parties.\n - `pica_sync_placements_create` — atomic create (placement + draft sync_license agreement + ≥1 agreement_party + recordings + evidence sources in a single Postgres transaction). Empty `contacts[]` rejects with structured `MISSING_CONTACT` (`next_tool: \"pica_people_query\"`). New people auto-created inline via `person_name` instead of `person_id`.\n - `pica_sync_placements_update` — patch placement fields. Operator-only when `verification_status='operator_verified'|'disputed'` or `confidentiality_level` changes (throws structured `OPERATOR_REQUIRED`); illegal status transitions throw `INVALID_TRANSITION`.\n - `pica_sync_placements_delete` — operator-only hard delete (two-step confirmation token). Customer agents receive structured `OPERATOR_REQUIRED` with `next_tool: \"pica_sync_placements_update\"` pointing at the soft-delete path (`status: 'terminated'`).\n - `pica_sync_placements_cite` — attach an evidence source; auto-recomputes `verification_status` (any non-attestation kind → `evidence_attached`).\n\n All 4 mutating tools wrapped with `withBillingGate`. Stdio path delegates to `pica.syncPlacements.*` (new `@withpica/mcp-sdk` resource). HTTP transport mirrors via the shared `ToolRegistry`. Paired with W4's REST routes at `/api/admin/sync-placements`.\n\n- **`pica://schemas/sync-placement-required` workflow schema resource (ADR-214).** Required + recommended fields for `pica_sync_placements_create` plus 4 companion call entries (inspect / update / cite / delete) and a worked example. Embeds the three `sync_placements` CHECK enums (`status` 5 values, `verification_status` 5 values, `confidentiality_level` 3 values) via the build-time generator + `schema-mirror.json` extension. Lives on both stdio (via the schema generator) and HTTP transport (`UI_RESOURCE_DEFS` in `app/api/mcp/route.ts`).\n\n- **`WorkflowTag` union expanded 15 → 16 values** (added `sync-placement-required`). All 6 sync-placement tools tagged with this workflow; `lint-required-schemas` enforces forward + inverse coverage.\n\n- **`schema-mirror.json` extended with `sync_placements` table** for status / verification_status / confidentiality_level CHECK enum embedding.\n\n- **6 cost-model entries in `lib/billing/tool-cost-model.ts`** (READ for query/inspect, WRITE for create/update/delete/cite). Unblocks ADR-180 lint cost-model coverage check; ADR-215 shadow-metering will record `billable_events` rows on these tools from first call.\n\n- **`sync_placements` discovery category** in `mcp-server/src/tools/discovery.ts` — layered-discovery agents (ChatGPT, Claude.ai connectors with `MCP_LAYERED_DISCOVERY=1`) can find the 6 tools via `pica_discover`.\n\n- **MCP scope mapping** for the 6 tools under existing `read:agreements` (query + inspect) and `write:agreements` (create + update + delete + cite). Bundled under the agreements scope rather than minting a new public scope for one feature — every placement is backed by a sync_license agreement.\n\n- **Four group-membership tools (ADR-223 Phase 5).** Customers can now\n manage group → member relationships on people directly via AI:\n - `pica_group_add_member` — add a person to a group person row.\n Server-side trigger enforces parent.is_group=true and same-org\n constraint; tool surfaces friendly errors at the route layer.\n Defaults: `role='member'`, `receive_notifications=true` (opt-out\n per membership). Wrapped in `withBillingGate`.\n - `pica_group_remove_member` — set `left_at` on the active row.\n Rows are never deleted; member history is preserved.\n - `pica_group_list_members` — active members by default;\n `include_inactive=true` for history.\n - `pica_person_list_groups` — inverse: every group a person is or\n was a member of.\n Role enum: `member`, `founder`, `lead`, `touring_member`,\n `session`, `guest`, `producer_in_residence`. Free-text `role_label`\n for variants outside the enum. Tools route through `mcp-sdk`\n `groups` resource → `/admin/groups/*` and\n `/admin/people/{id}/groups` HTTP routes.\n\n### Changed\n\n- **`@withpica/mcp-sdk` peer bumped to `^1.20.0`.** Required for the\n new `groups` and `syncPlacements` resources; older SDK versions lack\n `PicaClient.groups` and `PicaClient.syncPlacements`.\n\n### Notes\n\n- The 4 mutating sync-placement tools (`_create`, `_update`, `_delete`, `_cite`) need ADR-198 holdout contract specs in the sibling `Good-FM/pica-holdout-tests` repo. Coordinator follow-up — Path A from W3 Stage 1 audit §11.E.\n- The brief's references to a `mcp-server/src/__tests__/contract-baseline.json` file and a `lint:contract-baseline` script are out of date; both were removed in ADR-180 Phase 3 (the lint chain is now fully strict by default — `scripts/lint-mcp-tools.ts` runs as part of `prepublishOnly`). W3 reinterpreted Stage 4 as ADR-180 metadata + cost-model + taxonomy entries (all added) plus ADR-198 holdout contracts (sibling repo, follow-up).\n\n## [2.46.0] - 2026-05-02\n\n### Changed\n\n- **`pica_update_my_identity` now accepts `full_name`.** Customers can\n update the name on their PICA account via AI (e.g., fix typos from\n signup). Routes to `user_profiles.full_name`; rolls back via\n `revertMyIdentity` if the agent-action stamp insert fails. Tool\n description rewritten to lead with name capture. Closes the\n edit-symmetry gap surfaced during the SEV-1 sprint: previously the\n user could AI-rename their org but not their own name.\n\n- **`pica_update_organisation_profile` now accepts `name`.** Customers can\n rename their organisation via AI (e.g., fix signup typos, replace the\n default \"My Organization\" placeholder). Updates `organisations.name`\n directly; non-empty TRIM validation matches the DB-layer SEV-1 guard\n shipped earlier on 2026-05-01. Tool description updated to mention the\n typo-fix use case. Closes the placeholder-name lock-in trap surfaced\n during the SEV-1 onboarding-stuck-state cleanup.\n\n## [2.45.0] - 2026-05-01\n\n### Added\n\n- **ADR-214 Phase 3a — 3 new workflow schema resources.**\n - `pica://schemas/session-required` (studio session logging — `pica_sessions_create` primary; `pica_sessions_types` companion for session_type_id lookup; `pica_sessions_get` / `_list` for read).\n - `pica://schemas/split-sheet-required` (publishing royalty splits on works — `pica_split_sheet_generate` primary; `pica_split_sheet_send` / `_get` / `_list` companions).\n - `pica://schemas/recording-splits-required` (master ownership splits on recordings — `pica_recording_splits_create` primary with ADR-200 form-confirmation gate; `pica_recording_splits_verify` / `_list` companions).\n\n Each derives required + recommended fields from live tool input schemas at build time; `recording-splits-required` embeds the `split_type` and `role` CHECK enums (4 + 8 values respectively) from a hand-edited `schema-mirror.json` entry verified against prod project `fwgcmjhlwevdnxgqmkmh`.\n\n- **WorkflowTag union expanded 12 → 15 values** (added `session-required`, `split-sheet-required`, `recording-splits-required`). 11 tools migrated from `\"infrastructure\"` to their P3a workflow tag (4 sessions + 4 split-sheet + 3 recording-splits).\n\n- **Agent-guide expanded 6 → 14 sections** for authenticated mode:\n - 3 new write workflow sections (sessions, split-sheet, recording-splits) with canonical tool sequences and schema-URI footers.\n - 1 new identifier-assign narrative section explaining the inline-update pattern (`pica_*_update` accepts identifiers as inline fields including satellite-routed person identifiers — `isni`, `musicbrainz_id`, `wikidata_id`, `discogs_artist_id`, `deezer_artist_id` route to `person_enrichment` automatically; the surface is uniform).\n - 4 new read-workflow sections covering find-duplicates → merge, query → inspect → resolve gap-finding chain, lookup-person by industry identifier, and audit catalog completeness via dashboard tools.\n\n Authenticated guide now ~12,750 B (lobby variant unchanged ~855 B).\n\n- **`schema-mirror.json` extended with `recording_splits` table** for `split_type` + `role` CHECK enum embedding. `sessions.status` and `split_sheets.status` documented inline in schema `summary` fields rather than `enum_tables` because they are not DB-CHECK-enforced.\n\n- **2 new MCP prompts.**\n - `log-a-session` — guided studio session logging with optional `work_id` argument.\n - `set-recording-splits` — guided master ownership split assignment with ADR-200 propose-and-confirm + verify flow; takes optional `recording_id`.\n\n- **`_meta.schemas` dispatcher emit on workflow-tagged tool results.** New `attachSchemaHints` private method on `ToolRegistry` mirrors the existing `attachSessionState` pattern verbatim — same merge semantics, null-safe handling, fail-open behavior. Every tool whose `workflows` field references one or more schema URIs auto-emits `_meta.schemas: [\"pica://schemas/<workflow>-required\", ...]` on successful results. 47 workflow-tagged tools across 13 files automatically tagged via the dispatcher hook (no per-executor edits). `ToolResult._meta` interface widened to `{ session_state?: SessionState; schemas?: string[]; [key: string]: unknown }`. Cross-transport survival verified — both HTTP (`app/api/mcp/route.ts`) and stdio (`mcp-server/src/server.ts`) preserve `_meta` end-to-end.\n\n- **Cost-model entries for ADR-217 + ADR-218 tools** (`pica_notifications_recent` → READ, `pica_notification_acknowledge` → WRITE, `pica_storage_configure_start` + `pica_storage_disconnect` → ADMIN). Unblocks ADR-180 lint cost-model coverage check; ADR-215 shadow-metering now records `billable_events` rows for these tools.\n\n### Changed\n\n- **11 existing prompts updated to reference ADR-214 schema URIs** where the workflow shape is implicated: `analyze-catalog`, `find-duplicates`, `enrich-metadata`, `verify-works`, `assess-catalog-health`, `audit-credits`, `new-catalog-setup`, `close-the-loop`, `register-my-works`, `prepare-for-sync`, `workspace-autopilot`. Agents invoking a refreshed prompt pick up the relevant `pica://schemas/<workflow>-required` (and `pica://docs/agent-guide` where orientation helps) on first read.\n\n- **`pica_merge_duplicates.entity_type` now accepts both forms.** Previously the enum was singular (`\"work\" | \"person\"`) while `pica_find_duplicates` was plural (`\"works\" | \"people\"`) — a real footgun documented in ADR-214 P3a Stage 1 R4. Tool now accepts all four (`works` / `people` / `work` / `person`); canonical plural form (`works` / `people`) matches the rest of the catalog tools. Internally coerces to plural for the success message and to singular for the SDK call. Backwards-compatible — no existing caller breaks. Success message no longer renders the broken `work(s)` / `person(s)` artifact when callers pass the plural form. The R4 confirm-branch (two-step ADR-200 confirmation flow) also uses canonical coercion with a try/catch fallback to \"entities\" so unknown entity_types don't break the confirm UX.\n\n### Fixed\n\n- **`pica_recordings_by_work` drift cleanup.** Removed tool was still referenced in:\n - `mcp-server/src/prompts/index.ts` `verify-works` prompt body — swapped to `pica_recordings_query` with `work_id` filter (single-line drift fix).\n - `mcp-server/src/tools/recovery-hints.ts` `next_tool` annotation — swapped to `pica_recordings_query`.\n - `mcp-server/README.md` Recordings Management section — section refreshed to current 5 tools (`_query`, `_inspect`, `_create`, `_update`, `_delete`); count corrected 6 → 5. Larger README drift in works/people/etc. sections flagged as separate cleanup.\n - `@withpica/mcp-utils` `recovery-hints.ts` DUPLICATE_ISRC `next_tool` — same swap (mcp-utils@1.15.1).\n\n- **Source ↔ dist invariant restored** for `prompts/index.{js,d.ts,*.map}` (PR #173 source landed without committed dist regen — develop's dist had been missing `log-a-session` + `set-recording-splits`) and `tools/recovery-hints.{js,*.map}` (source was correct; dist was stale). No semantic change beyond what was already on develop; clears phantom local-tsc errors per `feedback_root_tsc_stale_mcp_dist`.\n\n### Dependencies\n\n- `@withpica/mcp-utils` `^1.14.0` → `^1.15.1` (recovery-hints `next_tool` fix).\n\n## [2.44.0] - 2026-04-30\n\n### Added\n\n- **ADR-214 Phase 2 — 6 new workflow schema resources.**\n - `pica://schemas/audio-upload-required` (3-step chain: presigned →\n complete → analyze + poll)\n - `pica://schemas/enrichment-resolve-required` (resolve fan-out →\n proposals_list → proposal_apply / reject)\n - `pica://schemas/agreement-required`\n - `pica://schemas/multimedia-required`\n - `pica://schemas/export-required`\n - `pica://schemas/claim-required`\n\n Each derives required + recommended fields from the live tool input\n schemas at build time and embeds CHECK enums from `schema-mirror.json`.\n Agent-guide expanded with 6 workflow sections (4 net-new, 2 rewrites\n with schema-URI footers); intro bumps \"five core\" → \"eleven core\" and\n \"~227 tools\" → \"~231 tools\".\n\n- **WorkflowTag union expanded to 12 values** (5 Phase 1 + 6 Phase 2 +\n `infrastructure`). 28 tools migrated from `\"infrastructure\"` to their\n Phase 2 workflow tag (4 audio-upload, 6 enrichment-resolve, 4\n agreement, 4 multimedia, 5 export, 5 claim).\n- **`schema-mirror.json` extended with 6 new tables** for Phase 2\n CHECK-constraint enum resolution (agreements, discovered_artists,\n discovered_credits, discovered_custody, enrichment_proposals,\n multimedia_items). Verified live against prod project\n `fwgcmjhlwevdnxgqmkmh`.\n- **HTTP transport coverage** — `app/api/mcp/route.ts` `UI_RESOURCE_DEFS`\n - `UI_RESOURCE_BODIES` extended with the 6 new schema URIs (matches\n the Phase 1 pattern from PR #152). Per\n `feedback_cross_transport_resource_coverage`.\n\n## [2.42.0] - 2026-04-30\n\n### Added\n\n- **ADR-218 Primitive B — `pica_notifications_recent` tool.** New read-only\n MCP tool (`risk: \"safe\"`, `retry_safe: true`) returning the cross-transport\n `discovery_events` feed for the calling org, ordered by `created_at` DESC\n with optional `unread_only: boolean` filter (per-surface dedup against\n `seen_in`). Default limit 20, max 100. Distinct from `pica_notifications_list`\n which targets the person-scoped `pica.notifications` system; this reads the\n org-wide ledger that web bell + telegram dispatcher also share.\n- **ADR-218 Primitive C — `pica_notification_acknowledge` tool.** New\n mutating tool (`risk: \"mutating\"`, `retry_safe: true`) that appends `'mcp'`\n to each event's `seen_in` array. Idempotent — re-acknowledging is a no-op.\n Org-scoped server-side: out-of-org ids are silently skipped. Empty\n `event_ids` returns a `VALIDATION_ERROR` without hitting the API.\n- \\*\\*Both tools registered in the existing `notifications` taxonomy bucket\n - TOOL*METADATA (`category: \"comms\"`)\\*\\* + tagged `workflows: \"infrastructure\"`\n per ADR-214 W4. Ride alongside the legacy `pica_notifications*_`and`pica*notify*_` families — the agent disambiguates from the descriptions.\n\n### Changed\n\n- **ADR-218 Primitive D — telegram dispatch dedup.** `telegramNotificationService.notifyEvent`\n now consults `discovery_events` for an existing undismissed row matching\n `(organisation_id, event_type, entity_id)` where `'mcp' = ANY(seen_in)`.\n When found, suppresses the entire dispatch — closes the re-nag loop for\n `until_resolved`-strategy alerts. Fresh `one_shot` events with no prior\n row still fire normally. Lookup is fail-soft: any DB error logs a debug\n and proceeds with dispatch (better an extra ping than a silently-dropped\n alert).\n- **ADR-218 Primitive A — `_meta.session_state` envelope gains optional\n `notifications` field.** `fetchSessionCounts` propagates the cross-transport\n unread summary from the catalog-stats response into the envelope. Missing\n field on older API servers leaves the envelope key off (no fabricated zero).\n\n### Bumped\n\n- `@withpica/mcp-sdk` peer to `^1.18.0` (`DiscoveriesResource.recent` +\n `.acknowledge` methods + `NotificationsSummary` type on `CatalogStats`).\n- `@withpica/mcp-utils` peer to `^1.14.0` (optional `notifications` field on\n `SessionStateCounts` + exported `NotificationsSummary` type).\n\n## [2.41.0] - 2026-04-30\n\n### Added\n\n- **ADR-210 P3 — `getAuthenticatedInstructions(slice)` + `getTrialEndingClause(slice)`\n exports in `src/server-instructions.ts`.** New helpers that optionally append\n a state-conditional trial-ending nudge to the authenticated handshake\n instructions. The clause fires only when `billing_state === 'trial'` AND\n `trial_days_remaining` is non-null AND `<= 3`; in all other cases the\n function returns the unchanged base const. Pass `null` when no slice is\n available — slice-less callers fail safe. Existing\n `SERVER_INSTRUCTIONS_AUTHENTICATED` const is unchanged (parity with\n `lib/mcp/server-instructions.ts` preserved).\n- **New `TrialNudgeSlice` interface export.** Minimal shape consumed by\n the helper: `{ billing_state: string; trial_days_remaining: number | null }`.\n Structurally compatible with the platform's `OrgBillingSlice` type so\n callers can pass either.\n\n### Note on stdio behaviour\n\nThe stdio binary in this release continues to call the equivalent of\n`getAuthenticatedInstructions(null)` at boot (returns the unchanged const) —\ntrial state is not resolvable at boot without a `pica.catalogStats()` round\ntrip. Stdio agents still see live `trial_days_remaining` via\n`_meta.session_state` on every write-tool result. A future phase may add\nboot-time slice resolution; this release ships the helper itself so the\nHTTP transport (`/api/mcp`) can use it immediately on a per-request basis.\n\n## [2.40.0] - 2026-04-30\n\n### Changed\n\n- **ADR-214 W4 — `workflows` field is now required on `ToolDefinition`.**\n Flips the optional `workflows?: WorkflowTag | WorkflowTag[]` field\n introduced in W1 to a required `workflows: WorkflowTag | WorkflowTag[]`.\n TypeScript compilation now enforces that every new tool authored\n declares its workflow membership at the source site — no escape\n hatch except the explicit `\"infrastructure\"` opt-out. Drift\n prevention mechanism #1 from ADR-214 §\"Drift prevention\" is now\n fully load-bearing. `lint-required-schemas.ts` hardened: the\n parallel-window warning for untagged tools becomes a hard error\n (defence-in-depth in case a tool somehow reaches the registry\n without a `workflows` field at runtime).\n\n### Added\n\n- **ADR-214 W2 — agent-guide + required-fields schema resources.**\n Two new resource families on the catalog `mcp-server`:\n - `pica://docs/agent-guide` — workflow narrative for agents. Visible\n in both lobby and authenticated modes; content branches on\n `lobbyMode`. Lobby variant (~865 bytes) covers the signup → magic\n link flow + what unlocks. Authenticated variant (~4.3 KB) lists the\n five core workflows (register a work, add a recording, add audio,\n add recording credits, enrich metadata) with verbatim tool sequences\n and 8 common gotchas — verified against the live tool registry on\n 2026-04-30.\n - `pica://schemas/work-required`, `pica://schemas/recording-required`,\n `pica://schemas/work-credits-required`,\n `pica://schemas/recording-credits-required`,\n `pica://schemas/person-required` — JSON contracts derived at build\n time from each tool's `inputSchema` (in `ToolRegistry`) joined with\n `schema-mirror.json` for live CHECK constraint enums. Authenticated\n mode only.\n- **Build-time generator + schema mirror.**\n - `mcp-server/scripts/build-required-schemas.ts` — runs as part of\n `npm run prebuild` (chained after `bundle-apps.ts`); reads\n `required-schemas.source.ts` + `ToolRegistry` + `schema-mirror.json`\n and emits the deterministic `required-schemas.generated.ts`\n (committed to git so PR diffs surface drift, per\n `feedback_type_regen_cumulative_drift`).\n - `mcp-server/src/resources/schema-mirror.json` — committed snapshot\n of CHECK constraint enums for `works`, `recordings`, `work_credits`,\n `recording_credits`, `audio_files`. Refresh via\n `mcp-server/scripts/refresh-schema-mirror.ts` (humans only; CI never\n auto-regenerates).\n- **Inverse-coverage CI lint (`scripts/lint-required-schemas.ts`).**\n Walks `ToolRegistry` and `REQUIRED_SCHEMAS_SOURCE` from both\n directions: every tool whose `workflows` field tags it for a workflow\n must appear in the source file; every source reference must resolve\n to a real tool. During the parallel-development window (W1 still in\n flight), tools missing the `workflows` field emit a single summary\n warning (per coordinator decision Stage 1 §R2). Once W4 makes the\n field required, the warning becomes an error.\n- **Agent-guide drift lint (`scripts/lint-agent-guide.ts`).** Greps\n every `pica_*` token in `agent-guide.ts` against `ToolRegistry` (in\n both `discoveryMode` settings, so meta-tools like `pica_discover` are\n resolvable). Catches stale references after tool renames.\n- **Meta-tests** for both lints (per `feedback_meta_test_load_bearing`):\n 3 / 3 regressions caught and reverted before ship — see\n `docs/follow-ups/2026-04-30-adr214-w2-meta-test-outcomes.md`.\n\n### Changed\n\n- `mcp-server/package.json` — `prebuild` now chains\n `bundle-apps.ts && build-required-schemas.ts`. New scripts\n `lint:required-schemas` and `lint:agent-guide` added; both wired into\n `prepublishOnly` after the existing checks.\n- `mcp-server/src/resources/index.ts` — registers 6 new URIs across\n `listResources()` (1 in the lobby branch, 5 in the authenticated\n branch) and `readResource()` (1 case for the agent-guide variant\n branch, 5 cases for the schema URIs).\n\n### Dependencies\n\n- `pg` + `@types/pg` added as devDependencies (used only by\n `refresh-schema-mirror.ts` for direct Postgres CHECK-constraint pulls\n against staging).\n\n### Internal\n\n- **ADR-214 W1 — `WorkflowTag` type + optional `workflows` field on tool\n definitions.** Adds a union type\n (`\"work-required\" | \"recording-required\" | \"work-credits-required\"\n| \"recording-credits-required\" | \"person-required\" | \"infrastructure\"`)\n and a `workflows?: WorkflowTag | WorkflowTag[]` field to\n `ToolDefinition` at `mcp-server/src/tools/index.ts`. All 231 tools now\n carry the field — 8 catalog-core tools (`pica_works_create`,\n `pica_works_update`, `pica_recordings_create`,\n `pica_recordings_update`, `pica_people_create`, `pica_people_update`,\n `pica_credits_update`, `pica_recording_credits_update`) reference one\n or more Phase 1 workflows; the remaining 223 carry\n `\"infrastructure\"`. Field is optional in W1 to keep the rollout\n additive; W4 (post-merge of W1 + W2 resource scaffolding) flips it to\n required so every future tool is forced to declare its workflow at\n compile time. No runtime behaviour change in this release.\n\n## [2.39.0] - 2026-04-30\n\n### Added\n\n- **ADR-211 Phase 1 — `pica_signup_start` unauthenticated tool.** New\n agent-discoverable signup verb available without a connection key on\n both stdio (lobby mode) and HTTP `/api/mcp` (anonymous mode). Mints\n nothing locally — every invocation calls\n `POST /api/public/onboarding/signup-start` so the\n `ONBOARDING_TOKEN_SECRET` signing secret stays on the backend, never\n in customer-distributed binaries. Returns a 15-minute JWT-bound\n `/onboard/<token>` URL via `resource_link` (universal floor) +\n capability-gated `elicitation/create url` (mode: \"url\"). Constructor\n takes `{apiUrl, transport, clientId?}` — stdio binary stamps\n `transport: \"stdio\"`, the HTTP carve-out stamps `transport: \"http\"`\n and threads through any DCR `client_id` for OAuth resume.\n\n- **`SERVER_INSTRUCTIONS_UNAUTHENTICATED` lobby variant.** Short\n ~600-char handshake text pointing the agent at the 3 lobby tools\n (`pica_signup_start`, `pica_sign_in`, `pica_sign_out`) instead of the\n full 200+ catalog surface. Selected at boot when `lobbyMode === true`\n (stdio binary without `PICA_API_KEY`) and at handshake when\n `/api/mcp` is invoked without a Bearer token. Catalog-tool guidance\n omitted because no catalog tools are reachable in lobby mode.\n\n- **`SERVER_INSTRUCTIONS_AUTHENTICATED` alias** of the legacy\n `SERVER_INSTRUCTIONS` export — the unaliased symbol stays exported\n unchanged for backward compatibility.\n\n### Changed\n\n- **Lobby surface is now THREE tools** (was two): `pica_signup_start`\n joins the existing `pica_sign_in` + `pica_sign_out` pair. Additive,\n not replacement — Phase 1 evaluates consolidation in Phase 2 once\n the `/onboard/<token>` page is live and the JWT-bound flow is the\n preferred path. ADR-211 § Primitive A editorial amendment 2026-04-30\n reflects this.\n\n### Notes\n\n- **`ONBOARDING_TOKEN_SECRET` env var required** on backend\n environments (preview + prod already provisioned 2026-04-30). The\n `lib/auth/scoped-jwt.ts` substrate gained an additive\n `options.secretEnvVar` parameter so each scoped-JWT consumer\n (upload-token, onboarding-token, future ADR-214 storage-config) can\n rotate its signing secret independently. SUPABASE_JWT_SECRET still\n serves as the local-dev fallback in both modes.\n\n- **No new exports in `@withpica/mcp-utils` or `@withpica/mcp-sdk`** —\n Phase 1 consumes existing exports (`clientSupportsUrlElicitation`,\n `CallerContext`) only. Per\n `feedback_workspace_package_publish_discipline.md`: no bumps needed\n upstream of this release.\n\n## [2.38.0] - 2026-04-30\n\n### Added\n\n- **ADR-208 Phase 3 Primitive D — `pica_release_show` rich-render tool.**\n The catalog's first MCP tool returning `image` + `text` content blocks\n in a single agent turn. Cover art ships as a base64 JPEG ≤512px;\n markdown summary covers title, year, primary artists, label name, UPC,\n catalog number, and tracklist with ISRCs and durations. Read-only\n (`readOnlyHint: true`). Registered in\n `mcp-server/src/tools/discovery.ts` `CATEGORIES.releases.tools` in\n the same commit as the `ToolRegistry` registration per the layered-\n discovery completeness rule.\n- **`_meta.ui.resourceUri = \"ui://pica/release\"`** — MCP Apps clients\n (Claude Desktop, Cursor) render the iframe via the new resource at\n `mcp-server/src/apps/release.ts`. Phase 3 ships the resource stub\n (title + markdown + cover image binding); full interactive iframe\n with track-list expand and inline streaming embeds is queued under\n the ADR-200 Phase 1.x backlog.\n- **`structuredContent`** envelope — `{ title, markdown, cover_base64,\ncover_mime_type, resource_link_uri }`. Apps clients prefer this over\n re-decoding the image content block; non-Apps clients ignore it.\n\n### Notes\n\n- **Universal floor is `image + text` only in Phase 3.** A `resource_link`\n block is intentionally omitted because no release UI page exists in\n the codebase yet (verified — neither `/portal/releases/[id]` nor\n `/admin/releases/[id]`). Building one is queued under\n `docs/follow-ups/2026-04-30-adr208-phase3-5-release-detail-page.md`\n and ADR-208 § Primitive D was editorially amended on develop\n (`30ceefc9d`) to reflect the deferral.\n- **\"Key credits\" deferred from the markdown body.** The existing\n `releasesService.listTracks()` join surfaces work + recording artist\n but not `work_credits`; adding the join widens Phase 3 scope. Will\n land alongside ADR-213 when credit-attribution surfaces consume the\n data cheaply.\n- **Sharp lives in the main Next.js app, not in this stdio binary.**\n Cover-art bytes come from the new `/api/admin/releases/[id]/cover-art-thumbnail`\n endpoint that does the resize + cache server-side, so the\n customer-distributed `@withpica/mcp-server` install stays free of\n sharp's ~50MB platform-specific native binaries.\n\n### Changed\n\n- **Bumps `@withpica/mcp-sdk` peer to ^1.17.0** to consume the new\n `ReleasesResource.getCoverArtThumbnail()` method.\n `@withpica/mcp-utils` stays at ^1.12.0 (T2.4's bump absorbed via the rebase).\n\n## [2.37.0] - 2026-04-30\n\n### Added\n\n- **ADR-210 Phase 2 — `pica_subscription_status` and `pica_subscription_manage`.**\n Two new tools shipping the explicit billing read + action surface\n that complements Phase 1's ambient `_meta.session_state.billing_slice`.\n - `pica_subscription_status` (`readOnlyHint: true`) wraps the\n existing `GET /api/admin/subscription` route and flattens it into\n the 9-field shape ADR-210 § Phase 2 specifies (`billing_state`,\n `trial_days_remaining`, `trial_ends_at`, `current_tier`,\n `capacity_used`, `capacity_limit`, `capacity_pct`,\n `recommended_tier`, `summary`). The `summary` line is a\n server-side template the agent uses verbatim — predictable\n wording, less variance across connectors.\n - `pica_subscription_manage` (`readOnlyHint: false`) is a single-verb\n dispatcher over the existing `POST /api/admin/subscription`\n (subscribe / upgrade) and `POST /api/admin/subscription/portal`\n (manage / cancel) routes. Returns `{url, expires_at, surface}`.\n Subscribe / upgrade without `tier` returns a recoverable error\n with `next_tool: pica_subscription_status` so the agent can\n chain to read `recommended_tier` first rather than auto-pick.\n Universal-floor `resource_link` content block ships on every\n success response per ADR-200 Phase 1; `elicitation/create url`\n fires only when `clientSupportsUrlElicitation(server)` (the\n capability gate is mandatory because `elicitInput` with\n `mode: \"url\"` throws synchronously against non-supporters per\n `feedback_mcp_sdk_capability_gates_elicitation.md`).\n- **`subscription` category in `discovery.ts:CATEGORIES`** (\"view your\n billing state, manage your subscription, and pick a tier\"). Lint\n enforced by `scripts/lint-mcp-tools.ts` per\n `feedback_mcp_taxonomy_completeness.md`.\n\n### Changed\n\n- **Bumps `@withpica/mcp-sdk` peer to ^1.16.0** to consume the new\n `SubscriptionResource`. `@withpica/mcp-utils` stays at ^1.12.0\n (T2.4's bump absorbed via the rebase).\n\n## [2.36.0] - 2026-04-30\n\n### Added\n\n- **ADR-213 Primitive A — `pica_recordings_create` post-create attribution hints.**\n Every successful create call now appends up to three Important-severity\n hints via the new `buildRecordingAttributionHints(recording)` helper\n (`mcp-server/src/tools/recording-attribution-hints.ts`). Mirror of\n `buildCustodyHints` for works:\n - `recording_ownership_unset` — fires when `ownership_percentage IS NULL`.\n Suggests `pica_recordings_update ownership_percentage:N`.\n - `recording_no_credits` — always fires (we never know credits from a\n single fresh row). Suggests the new `pica_recording_credits_update`.\n - `recording_master_unclaimed` — fires when `ownership_percentage IS NULL`.\n Alternative path for multi-party master claims via `pica_custody_claim`.\n NULL-only triggers: `0` is \"explicit zero\", no hint. Negative-path\n covered by jest at `recording-attribution-hints.test.ts` per\n `feedback_meta_test_load_bearing.md`.\n- **ADR-213 Primitive B — `pica_recording_credits_update`.** First-party\n recording-side write tool; closes the work/recording credit-write\n asymmetry. Writes to `recording_credits` (NOT the trade-secret\n enrichment-cascade-fed `credits` table — see `.claude/rules/ip-protection.md`).\n Uses the 16-role `RECORDING_CREDIT_ROLES` enum (`MainArtist`,\n `FeaturedArtist`, `Producer`, `Mixer`, `Engineer`, ... `Other`).\n Songwriting credits (Writer, Composer, Lyricist, Arranger as a publishing\n role) continue to route through `pica_credits_update` on the parent work.\n Registered in `discovery.ts` `CATEGORIES.credits` in the same commit per\n `feedback_mcp_taxonomy_completeness.md`. Listed under `write:catalog` scope\n in `lib/services/mcp-scopes.ts`. `nextSteps` points at\n `pica_recordings_inspect sections:[\"recording_credits\"]` for ADR-198\n round-trip verification.\n- **ADR-213 Primitive A.1 — `pica_recordings_inspect recording_credits`\n section.** Additive (not replacement). The existing `credits` section\n (work-side credits via parent work) keeps its current behaviour. New\n `recording_credits` section reads first-party operator-authored credits\n directly from the `recording_credits` table via the new\n `pica.recordingCredits.list()` SDK method.\n- **`TOOL_METADATA` entry for `pica_recording_credits_update`** in\n `mcp-server/src/tools/metadata.ts` (catalog/mutating/non-retry-safe).\n\n### Changed\n\n- **Bumps `@withpica/mcp-sdk` peer to ^1.15.0** and `@withpica/mcp-utils` to\n ^1.12.0 to consume the new `RecordingCreditsResource` and the metadata\n entry shipped alongside ADR-213.\n- **Tool count moves from 224 → 225** with the addition of\n `pica_recording_credits_update`.\n\n## [2.35.0] - 2026-04-29\n\n### Added\n\n- **ADR-208 Phase 2 — `pica_upload` returns a JWT-bound `/upload/<token>` URL.**\n The executor now calls `pica.uploads.createSession()` for server-side\n mint of a 600s-TTL HS256 JWT scoped to the caller's org / user /\n bucket-key / acceptFilter. Universal floor (`resource_link`) and\n capability-gated `elicitation/create url` shapes unchanged — only the\n URL flips from `${webBase}/workspace` to `${webBase}/upload/<jwt>`.\n Tool description updated; obsolete Phase 1.5 forward-reference removed.\n\n### Changed\n\n- **`session_state.pending_uploads` now reads from\n `organisations.pending_uploads_count`** (atomic +1 on JWT mint via\n `/api/admin/uploads/sessions`, atomic -1 on JWT-path completion via\n `/api/upload/[token]`). Phase 1's stub at `0` is gone. Atomic semantics\n via the `inc_pending_uploads` SECURITY DEFINER RPC; `GREATEST(0, ...)`\n clamp prevents negative drift. Sits alongside T1.2's billing fields on\n the same `_meta.session_state` envelope — no shared edit to\n `mcp-server-shared/mcp-utils/src/session-state.ts`.\n\n### Notes\n\n- Fail-soft: if `createSession()` throws (network blip, route 5xx), the\n executor falls back to the legacy workspace URL and surfaces the error\n in the `text_summary`. The card still works for MCP Apps clients via\n `_meta.ui.resourceUri` regardless.\n\n### Bumped\n\n- `@withpica/mcp-sdk` dependency range bumped to `^1.14.0`\n (`UploadsResource`, `CreateUploadSession*` types,\n `CatalogStats.pending_uploads_count` now consumed).\n- `@withpica/mcp-utils` dependency range bumped to `^1.11.0`\n (T1.2's billing-fields extension on `SessionStateCounts`).\n- `mcp-server/server.json` registry manifest version bumped to `2.35.0`\n in lockstep with the npm package.\n\n## [2.34.0] - 2026-04-29\n\n### Added\n\n- **ADR-210 Phase 1 — billing slice on `_meta.session_state`.** The\n `fetchSessionCounts` private in `ToolRegistry` now resolves the four\n billing fields (`billing_state`, `trial_days_remaining`, `current_tier`,\n `capacity_pct`) from `pica.catalogStats().billing_slice` alongside the\n existing counts. `attachSessionState` flows them onto every successful\n write-tool result through the same `_meta.session_state` envelope (no\n new emission path — extends the existing one) so the agent sees ambient\n billing posture between mutations without a `pica_subscription_status`\n round-trip. Phase 2 will land that explicit read tool; Phase 1 ships\n the substrate the tool reads from.\n- Same fail-soft posture as the existing fetcher: when `this.pica` is\n missing (HTTP-discovery without bearer scope), or when the SDK response\n is missing `billing_slice` (older server pre-Phase-1), the fetcher\n emits a conservative `{ billing_state: \"trial\", trial_days_remaining:\nnull, current_tier: null, capacity_pct: 0 }` rather than fabricating\n \"active\" — the agent never sees misleading \"active\" billing for an\n uninitialized context.\n\n### Bumped\n\n- `@withpica/mcp-sdk` dependency range bumped to `^1.13.0`\n (`CatalogStats.billing_slice` field now consumed).\n- `@withpica/mcp-utils` dependency range bumped to `^1.11.0`\n (`SessionStateCounts` shape extended with `BillingSlice` fields).\n- `mcp-server/server.json` registry manifest version bumped to `2.34.0`\n in lockstep with the npm package.\n\n## [2.33.0] - 2026-04-29\n\n### Added\n\n- **ADR-208 Primitive B — `_meta.session_state` attached to write-tool results.**\n The central `ToolRegistry.executeTool` wrapper now composes the six-key\n session-state envelope (`works_count`, `recordings_count`,\n `completeness_pct`, `mutations_this_session`, `since_last_briefing`,\n `pending_uploads`) for every tool whose risk is `mutating` or\n `destructive` (`readOnlyHint: false`), and attaches it under\n `result._meta.session_state`. Read tools (`risk: safe`) skip this\n entirely so the high-volume read path stays cheap; failed mutations\n (`isError: true`) also skip because catalog state didn't change.\n `pica_dashboard_briefing` running successfully resets the\n `since_last_briefing` counter — handled in the wrapper, not the tool.\n Cache key is org-scoped via `config.picaApiKey` (stdio) or\n `callerContext.callerIdentity` (HTTP); two orgs sharing a worker\n process never share state. Fail-open: any error in session-state\n composition is swallowed and the result returns without `_meta.session_state`.\n See `@withpica/mcp-utils@1.10.0` for the underlying `buildSessionState`\n helper and the load-bearing cross-org isolation regression test.\n\n### Changed\n\n- Bump `@withpica/mcp-utils` dep range to `^1.10.0` to pick up the\n `buildSessionState` / `incrementSessionMutations` /\n `resetSinceLastBriefing` exports that compose Primitive B.\n\n## [2.32.0] - 2026-04-28\n\n### Changed\n\n- Bump `@withpica/mcp-utils` dep range to `^1.9.0`. The previously-pinned `^1.8.0`\n resolved (via the npm registry) to a tarball that pre-dated the addition of\n `clientSupportsUrlElicitation` and `elicitBulkConfirmation` to the source — Vercel\n builds where the lockfile resolved from registry instead of the local workspace\n link failed with `TS2305`. 1.9.0 republishes the same source state with both\n exports present, so registry-pinned lockfiles now build cleanly without needing\n the workspace-link override.\n\n## [2.31.0] - 2026-04-28\n\n### Added\n\n- **ADR-200 Phase 1 — `ToolExecutorContext` plumbed through the registry.**\n `ToolExecutor` now takes an optional second arg `(args, ctx?)` carrying the\n per-request `Server` reference. `server.ts` passes `{ server }` through to\n `executeTool`; the discovery dispatcher (`pica_execute`) forwards it to its\n delegate. Existing executors with the legacy `(args)` signature keep working\n unchanged — only tools that need `server.elicitInput()` opt into the second\n arg. Pre-existing destructive-confirmation gate (two-step token) is\n preserved.\n- **`pica_upload` portable across non-MCP-Apps clients.** Response now ships\n with a `resource_link` content block (universal MCP floor) alongside the\n legacy text envelope and `_meta.ui.resourceUri` — Apps clients render the\n iframe unchanged, ChatGPT / Gemini / Claude Code / curl-style clients see a\n clickable link to the workspace upload page. Clients that advertised\n `capabilities.elicitation.url` additionally receive a server-issued\n `elicitation/create url` consent prompt; the call is gated on the new\n `clientSupportsUrlElicitation` helper from `@withpica/mcp-utils@1.8.0` so\n callers without the capability never see the SDK's synchronous\n \"Client does not support url elicitation\" throw. `elicitationId` is a\n per-call UUID. Universal floor remains usable when the user declines or the\n elicitation times out — the resource_link in the response is the fallback.\n- **`pica_download` ships a `resource_link` for the signed file URL.** Same\n universal-floor improvement on the download surface — text envelope still\n carries the JSON shape ADR-152 cards expect, plus the new resource_link\n exposes the URL/filename/mime to clients that render link blocks.\n- **ADR-200 Phase 1 — form-confirmation gate on the 4 customer-MCP Class D\n bulk tools** (`pica_works_bulk_update`, `pica_people_bulk_update_roles`,\n `pica_recording_splits_create`, `pica_collaborators_invite_bulk`). Each\n now calls `elicitBulkConfirmation` from `@withpica/mcp-utils@1.8.0`\n after the validation + dry_run paths but before persisting. The gate\n fires only when the connected client advertises\n `capabilities.elicitation`, and in that case the destructive write only\n proceeds if the form returns `accept` with `confirm: true`. Universal\n floor: clients without elicitation continue to execute as before\n (existing destructive-token gate, where applicable, remains\n authoritative). 11 new tests cover decline, accept-without-confirm,\n no-caps fallback, and dry_run-skips-elicitation across the four tools.\n `team_comms_send` (5th Class D tool) is gated in\n `@withpica/team-mcp-server@1.3.0`.\n- **`ToolResult.content` widened to permit `resource_link` blocks.** Legacy\n `Array<{ type, text }>` shape kept compatible via a structural union; tools\n that only return text need no changes.\n\n### Changed\n\n- **Tool descriptions for `pica_upload` / `pica_download` updated** to point\n at the ADR-200 fallback ladder rather than the prose \"tell the user to use\n the workspace dashboard\" hint that ADR-152 originally shipped. Behaviour\n for MCP Apps clients is unchanged.\n\n### Removed\n\n- **9 nested `withCreditGate(...)` wrappers unwrapped** across `tools/audio-files.ts` (2), `tools/exports.ts` (3), and `tools/enrichment.ts` (4). Each always ran inside a `withBillingGate(...)`; the inner wrapper was a no-op shim retained since ADR-162 disabled credit gating. Unwrapping leaves the subscription check as the sole gate on these tools, which matches the billing model.\n- **`tests/utils/credit-gate-mpp.test.ts` + `credit-gate-mpp-paths.test.ts` deleted.** Both suites exercised a disabled MPP + pay-per-credit path that no longer has any production call-sites. `tests/tools/metadata.test.ts` also drops its `credit-gated tools should have credits_required set` assertion — redundant now that `credits_required` is gone from the shared `@withpica/mcp-utils` type (companion entry in that package's CHANGELOG). `tests/tools/credits.test.ts` stale `describe(\"pica_credits_balance\")` block (and associated `mockCreditsBalance` setup) removed — that tool was pulled from the surface 2026-04-22 but the tests were missed in that pass.\n- **`src/__mocks__/mppx-server.ts` + `mppx-mcp-sdk-server.ts` deleted** and the matching `moduleNameMapper` entries removed from `jest.config.js`. Both mocks existed only to stub out `mppx` for the now-deleted MPP unit tests. The `testPathIgnorePatterns` entry pointing at `credit-gate-mpp-paths.test.ts` is also removed (ghost reference to the deleted file).\n- **\"credit-gated\" prose stripped from tool descriptions** in `tools/app-tools.ts` (`pica_car_preview` description + carPreview reuse comment) and `tools/documents.ts` (`pica_documents_analyse` description). These strings were advertised in the tool description, telling agents a tool was \"credit-gated (5 credits)\" when it's actually subscription-gated at workspace level.\n- **`mppx` runtime dep still listed in `package.json`** — left in place to avoid lockfile churn; no `src/` consumer remains after this commit. Next publisher should drop it and rerun `npm install` to clean the lockfile.\n\n## [2.30.0] - 2026-04-27\n\n### Added\n\n- **`pica_audio_inspect` basic section surfaces 4 previously-invisible\n columns** — `recording_id`, `stem_label`, `version_label`, and\n `classification`. All four are real columns on `audio_files` written by\n `pica_audio_complete_upload`. The 5th audit-flagged field\n (`content_type`) is mapped to `audio_format` at write time and was\n already surfaced. Closes a Phase 2 gap from the 2026-04-27 read-write\n parity audit. SDK type `AudioFile` extended with the same three\n optional fields (classification was already there).\n- **`pica_organisation_profile` includes `org_type`** — paired read tool's\n underlying `/admin/settings/organisation-profile` SELECT now returns\n the CHECK-enum value that `pica_update_organisation_profile` already\n accepted (publisher / label / pro / sync_library / client / venue /\n distributor / other). Same class as the settings/identity fan-out\n fixed in 2.29.0 — write side accepted, read side truncated.\n- **`pica_physical_assets_inspect` adds a `links` section** — surfaces\n the typed-edge rows that `pica_physical_assets_link_work` and\n `pica_physical_assets_link_recording` write to `work_production_assets`\n and `recording_production_assets`. Pre-fix the link rows were\n write-only from the MCP surface even though both\n `/admin/assets/[id]/{work,recording}-links` GET endpoints already\n existed. SDK gains `assets.listWorkLinks(id)` and\n `assets.listRecordingLinks(id)`.\n- **`dry_run` flag on three more Class D mutating tools** —\n `pica_recording_splits_create`, `pica_collaborators_invite_bulk`,\n and `team_comms_send`. Completes the Class D coverage started in the\n ADR-199 5a part 1 commit (`a10006e5b`). Each tool early-returns\n `{ dry_run: true, would_affect, sample / target_count }` after\n validation and before the mutating SDK call, so agents can preview\n bulk effects and external-comms dispatch before committing. For\n `team_comms_send`, the preview echoes recipient and length-only\n metadata; the message body is not surfaced to keep ops messaging\n off the dry-run trace.\n\n### Fixed\n\n- **`pica_recordings_inspect` no longer hallucinates into the void on 404.**\n ADR-198 verification 2026-04-26 found the inspect tool was returning 200\n with `recording_error: \"API request failed: 404 ...\"` for every missing\n entity / missing route handler. Agents read this as a successful empty\n result and proceeded to call downstream sections (credits, audio) that\n also 404'd silently — no Sentry alert, no audit row, no user-visible\n error. Fix: basic-section catch now re-throws `EntityNotFoundError`\n (new typed export from `@withpica/mcp-sdk` 1.12.0+), so 404 surfaces\n as a hard `isError: true` envelope. Non-404 errors on the basic fetch\n still get absorbed into `recording_error` (preserves the partial-result\n pattern for transient failures).\n\n## [2.29.0] - 2026-04-25\n\n### Fixed\n\n- **94 previously-undiscoverable tools retrofitted into the layered-discovery\n taxonomy.** Same bug class that bit four times in three weeks\n (`pica_upload`/`pica_download` since ADR-152, `pica_submit_feedback` since\n ADR-184, `pica_report_issue`/`pica_my_reported_issues` from ADR-196 Phase 3):\n registered in `ToolRegistry` but absent from `CATEGORIES` in\n `mcp-server/src/tools/discovery.ts`, so layered-discovery agents (default\n for ChatGPT and Claude.ai connectors with `MCP_LAYERED_DISCOVERY=1`) could\n not find them via `pica_discover`. The 2026-04-25 hardening that added\n blocking `checkTaxonomyCompleteness` to `scripts/lint-mcp-tools.ts`\n surfaced 94 grandfathered violators in the baseline. This release retrofits\n every one. Fourteen new categories — `agreements`, `collaborators`,\n `custody`, `physical_assets`, `recording_splits`, `royalties_statements`,\n `share_links`, `split_sheets`, `licensing`, `notifications`, `messaging`,\n `agent_identity`, `telegram`, `labels` — and the tools fold into existing\n ones (`releases`, `analytics`, `enrichment`, `import`, `projects`,\n `profile`) where they belong. `scripts/mcp-tool-lint-baseline.json\n→ missing_taxonomy` is now empty.\n- **`pica_upload` and `pica_download` newly reachable via `pica_discover`** —\n the two generic harness cards (ADR-152) had been silently absent from the\n `CATEGORIES` taxonomy since they shipped. `pica_upload` added to the\n existing `uploads` category alongside the programmatic `pica_upload_file` +\n `pica_upload_complete` pair. `pica_download` added to the `export` category\n since it's the delivery side of any export-tool flow.\n\n### Changed\n\n- **`CATEGORIES` is now exported** from `mcp-server/src/tools/discovery.ts`\n so `scripts/lint-mcp-tools.ts` can read it. Compile-time only; no\n consumer change.\n\n## [2.28.1] - 2026-04-25\n\n### Fixed\n\n- **`pica_report_issue`, `pica_my_reported_issues`, and `pica_submit_feedback`\n were unreachable via `pica_discover`** — the layered-discovery taxonomy\n in `mcp-server/src/tools/discovery.ts` did not list them in any of its\n 26 categories, so agents using the layered flow (default for ChatGPT\n and Claude.ai connectors that need to keep their context window\n manageable) literally couldn't find these tools. Real-world failure\n caught 2026-04-25: a Claude Desktop session dogfooding the issue-\n reporting flow returned \"no feedback or support tool exposed in the\n PICA MCP\" and suggested `pica_notes_create` as the closest match —\n the exact failure mode `pica_report_issue` was designed to catch\n (which it couldn't, because it wasn't discoverable). New `feedback`\n category added to the discovery taxonomy listing all three tools.\n `pica_submit_feedback` had been silently invisible since ADR-184\n shipped — same bug class, same fix.\n\n### Changed\n\n- **`pica_report_issue` description tightened** to instruct the agent\n on WHEN to call: PROACTIVELY without being asked when the agent itself\n hits a workflow gap, AND on-demand when the user says \"this is broken\"\n / \"this didn't work\". Previously the description was descriptive\n (\"file a structured issue when…\") which left agents reading it as a\n passive option rather than a recommended habit. Also adds a\n cross-reference to `pica_my_reported_issues` for the resolution-poll\n side of the closed loop.\n\n## [2.28.0] - 2026-04-24\n\n### Added\n\n- **ADR-196 Phase 4a — `pica_my_reported_issues` tool.** Org-scoped\n customer-side polling tool that closes the loop on `pica_report_issue`.\n Lets the agent answer \"did anyone fix that thing I reported?\" without\n going through the operator surface. Returns the issue, current status,\n resolution_note, and occurrence_count for each issue the calling org\n has reported or been impacted by. Default sort most-recently-touched\n first; optional `status` filter (open / triaged / investigating /\n resolved / wont_fix). Tool metadata: `category=comms`, `risk=safe`,\n `retry_safe=true`. Pairs with `@withpica/mcp-sdk@1.12.0` for the new\n `OpsIssuesResource.listMine()` method.\n\n### Changed\n\n- **`mcp-server/src/config.ts` VERSION constant is now derived from\n `package.json`** via `createRequire(import.meta.url)(\"../package.json\")`,\n not a hardcoded literal. Drift-proof — future bumps no longer require\n manual sync between the two files. The version-sync lint in\n `scripts/lint-mcp-tools.ts` now accepts both forms (literal still\n blocks on drift; derived is always valid). Motivated by two\n consecutive publishes (2.27.0 + 2.28.0) being blocked by the stale\n literal — the trap is now permanently sealed.\n\n### Fixed\n\n- **`mcp-server/src/tools/discovery.ts` no longer references\n `metadata.credits_required`** — the property was removed from\n `ToolMetadata` in the chore/drop-mcp-credit-gating cleanup (per\n ADR-162: PICA is subscription-only) but two stale references in\n `discovery.ts` slipped through, blocking the publish until fixed.\n No tool carries the field anymore so the conditional spread was\n dead code; replaced with a comment recording the history. The\n comment itself is removed in chore/drop-mcp-credit-gating\n (this PR) — credit gating is gone for good.\n\n### Changed\n\n- **ADR-199 Week 1 — `withBillingGate` extended to every write-tool\n surface.** Previously the gate only covered `audio-files.ts`,\n `exports.ts`, and `enrichment.ts` (8 tools). Now wraps 38 write\n executors across 9 tool families: `agreements` (4), `agreement-types`\n (5 — `renderTemplate` deliberately ungated as it's a pure read),\n `custody` (4), `people` (3), `works` (5), `recordings` (3), `credits`\n (1), `assets` (7 — `assetExport` deliberately ungated to match\n `pica_export_catalog_csv`), and `dashboard` claim/review tools (4).\n Read tools (query / list / inspect / history / search / stats /\n pulse / briefing) intentionally not wrapped. Behaviour change for\n agents on hibernated workspaces: write tools that previously executed\n now return the lobby error. Operation labels in the lobby message\n use domain terms (\"agreement creation\", \"physical asset link\",\n \"custody claim\", \"discovery review\", etc.). The gate itself reads\n from `organisations.billing_state` via the new effective-state route\n (see `[Unreleased]` in `@withpica/mcp-utils`); `is_internal=true`\n organisations bypass the gate. Rollback path is the\n `ADR199_READ_BILLING_FROM_ORG` env var on the Vercel app — flipping\n to `false` reverts the read source to `user_profiles.billing_state`\n without an MCP redeploy.\n- **ADR-199 Week 1 language sweep — agent-facing copy moves to domain\n terms.** \"Your organisation\" / \"this organisation\" / \"your org\"\n swept to \"your catalog\" (where the noun is the music data) or \"your\n account\" (where no domain term fits) across `audit`, `collaborators`,\n `custody`, `dashboard`, `directory`, `memory`, `metadata`,\n `my-reported-issues`, `releases`, and `settings` tool descriptions.\n Internal identifiers (`pica_organisation_profile`,\n `pica_update_organisation_profile`, `org_type` parameter, the\n `\"organisation\"` memory-visibility enum value) deliberately\n preserved — those are wire-protocol or schema names, not copy.\n Industry term \"Performing rights organisation\" preserved (it's a\n PRO, not a withPICA org). Display names in `metadata.ts`\n (`view organisation profile` / `update your organisation profile`)\n swept to `view account profile` / `update your account profile`.\n\n## [2.27.0] - 2026-04-24\n\n### Added\n\n- **ADR-196 Phase 3 — `pica_report_issue` tool.** Lets an agent file a\n structured issue when a workflow breaks in a way raw tool failures can't\n capture (`workflow_gap` / `inconsistent_result` / `missing_step` /\n `data_issue` / `ux_confusion`). Auto-dedupes via the v2 signature\n (sha256 of `\"v2|{kind}|{canonicalised_summary}\"`), so two reports of\n the same problem with different wording collapse into one\n `ops_issues` row. Operators triage from the same record. Raw tool\n errors continue to auto-populate `ops_issues` via the `mcp-audit.ts`\n upsert path — agents should NOT call `pica_report_issue` for those\n (it would create a duplicate). Tool metadata: `category=comms`,\n `risk=mutating`, `retry_safe=true`. Pairs with\n `@withpica/mcp-sdk@1.11.0` and `@withpica/mcp-utils@1.7.0` published\n in the same cycle.\n\n### Fixed\n\n- **`config.ts` VERSION constant bumped to 2.27.0** to match the\n `package.json` version. The `version-sync` lint in\n `scripts/lint-mcp-tools.ts` blocked the initial 2.27.0 publish until\n this was corrected — caught a pre-existing trap where the banner\n version is hardcoded in source rather than derived from `package.json`\n at build time. Future bumps must update both files; consider\n auto-deriving in a follow-up.\n- **`pica_report_issue` tool — drop double-unwrap of SDK response.**\n `OpsIssuesResource.reportIssue()` now returns the unwrapped payload\n (mcp-sdk@1.11.0 tightened the return type), so the tool's previous\n `result?.data || result` fallback was dead code that didn't\n typecheck. Now `const data = result;` directly.\n\n## [2.26.0] - 2026-04-22\n\nVersion leapfrogs 2.25.0 (which was published to npm without a matching commit / changelog entry in this repo, discovered during this publish cycle). 2.26.0 ships from a clean main at commit `a3c8ca870` with the full bundle below. Pairs with `@withpica/mcp-sdk@1.10.0` and `@withpica/mcp-utils@1.6.0`, both published the same day.\n\n### Removed\n\n- **Billing-credit tools removed from the MCP surface:** `pica_credits_balance` (credits.ts), `pica_credits_history` (settings.ts), `pica_credits_purchase` (purchases.ts tombstoned to an empty class). See `docs/MCP_REFINEMENT_LOG.md` entry B-001. withPICA is subscription-only at £9.99/mo; surfacing a credit-balance + credit-history + credit-purchase tool trio contradicted the billing model and misled agents (caught 2026-04-22 when an agent transcript opened with \"998,894 credits — plenty. Running the export now.\"). The underlying SDK methods (`creditsBalance.*`, `settings.creditsHistory`) and `lib/services/credits/**` infra remain intact — only the MCP tool surface shrinks. `pica_credits_list` and `pica_credits_update` are **kept**: they're work_credits (songwriter roles + splits on a work), not billing credits.\n- **`CREDIT_INSUFFICIENT` recovery hints pointing at `pica_credits_balance`** removed from `recovery-hints.ts` for `pica_resolve_work`, `pica_export_song_registration`, `pica_export_catalog_asset_report`, `pica_audio_analyze`. Paired tests under `__tests__/tools/recovery-hints.test.ts` + `settings.test.ts` updated to assert the new shape.\n\n### Changed\n\n- **Credit-gating language stripped from tool descriptions** — `pica_audio_identify` (\"Costs 3 pica credits on match…\"), `pica_export_song_registration` (\"Costs 1 pica credit.\"), `pica_export_industry_ready` (same), `pica_export_catalog_asset_report` (\"Costs 5 pica credits…\"), and the 3 `pica_resolve_*` tools in `enrichment.ts` (\"Costs 1 pica credit per call.\"). The `withCreditGate` / `withBillingGate` runtime wrappers are **left in place** — only the agent-facing prompt-gating copy goes. Same B-001 refinement entry.\n- **Server instructions** (`src/server-instructions.ts`, mirrored in `lib/mcp/server-instructions.ts` via the parity test) open with a one-line disambiguation from `@picahq/mcp` (Pica AI / picaos.com) — a different product whose short name collides with ours. Helps agents that have both connectors installed (or users who pasted their withPICA key into the wrong config) recognise which server they're actually talking to. See the picaos name-collision memory rule.\n- **`pica_catalog_diligence` now returns structured JSON** instead of failing with a JSON-parse error on binary ZIP bytes. The fix lives in `@withpica/mcp-sdk`'s `AnalyticsResource.catalogDiligence()` — the SDK now requests `?format=json`. See the mcp-sdk CHANGELOG for detail. MCP refinement log: \"Singleton — `pica_catalog_diligence` returns ZIP parsed as JSON\".\n\n### Fixed\n\n- **ADR-174 Phase 2c — inverse phantom in `pica_works_update` (works slice).** Three jsonb compliance fields (`ai_disclosure`, `provenance_attestation`, `training_rights`) are satellite-routed to `work_licensing` via `WORK_SATELLITE_FIELDS` and accepted by both the HTTP route allow-list and the service layer, but were missing from `WORK_WRITE_PROPERTIES`. Agents following the `pica_works_update with ai_disclosure: ...` completion hint at works.ts:577 were hitting schema-level silent-drop (or strict-validator 400s). Added all three properties to the write schema with shapes copy-pasted from the parallel fields on `pica_recordings_update` (recordings.ts:193). Tool description updated to distinguish audio-trait satellite fields (still not exposed) from the three compliance satellite fields (now exposed). Full audit of the other 22 customer-MCP write tools yielded zero further inverse phantoms — see `docs/audits/2026-04-21-mcp-inverse-phantom-audit.md`.\n\n### Added\n\n- **ADR-189 Phase 4 slice 3: `pica_claim_artist` MCP tool.** INSTANT path for artist-claim on discovery-backed evidence. Wraps `artistClaimingService.processClaimDecision` to reuse the existing `work_claims.artist_claim_status` / `claimed_by_person_id` / `claim_confirmed_at` update path + `performer` work_credits insert. Refuses (409 `ADMIN_REVIEW_IN_PROGRESS`) when an open admin `artist_claims` row exists for the same (work, person) — returns `admin_review_id` in the body so the agent surface can route the user to resolve it. Rate-limited to 20/hour per user via the shared `claim_write` bucket. Wrapped in `withAgentActionStamp` when grant-authed — rollback captures pre-write `work_claims` row + tracks whether a new performer credit was inserted (deleted on compensation) or pre-existed (left alone). **Schema drift carryover:** the plan proposed capturing rollback state from 4 `works` columns, but live staging (`rtxcxazevrgcjnudvggf`) keeps the artist-claim lifecycle columns (`artist_claim_status`, `claimed_by_person_id`, `claim_confirmed_at`) on the `work_claims` satellite — only `primary_artist_id` lives on `works`. Service captures + restores from `work_claims` accordingly. The live `artist_claims.claim_status` CHECK constraint has no `under_review` state (only `pending | approved | rejected | withdrawn`), so the open-review gate checks `claim_status = 'pending'` only.\n\n### Removed\n\n- **ADR-154 F13: seven deprecated per-source enrich tools removed.** `pica_enrich_work_{mlc,musicbrainz,discogs,spotify,youtube}` and `pica_people_enrich_{isni,musicbrainz}` (tombstoned since ADR-179 Phase 1/2, 2026-04-17) are no longer registered — every call has returned a `-32070 TOOL_DEPRECATED` error for a full minor cycle, ending the one-minor deprecation window per ADR-179 Decision 2. Callers must use `pica_resolve_work(sources: [...])` or `pica_resolve_person(sources: [...])` instead; the `tools/list`, `metadata`, `recovery-hints`, and category-`discovery` surfaces shed the seven stale entries in this release. Downstream impact: clients that hardcoded the tool names now get `tools/list`-level absence rather than a deprecation envelope — fail-fast instead of fail-with-suggestion.\n\n### Changed\n\n- **ADR-154 F14: completion-hint sweep for the seven removed tools.** Updated every `→ then:` and hint-string reference that pointed at the F13 tombstones across `enrichment.ts`, `people.ts` (3 sites), `collaborators.ts`, `works.ts` (2 sites), `search.ts`, `server-instructions.ts`, `prompts/index.ts` (3 sites), and `resources/llms-primer.ts`. Agents discovering tools via descriptions will no longer be trained toward dead tool names. The ADR-179 \"Replaces the five/two per-source tools\" phrasing is gone from the resolver descriptions too — resolvers stand on their own now.\n- **ADR-180 Phase 3: full TOOL_METADATA coverage.** 29 tools retrofitted in `mcp-server/src/tools/metadata.ts` across eight family-scoped commits — resolve (3), cascade (3), enrichment proposals (4), collaborators (4), notify-user scheduling (3), physical-assets links (4), misc singletons (5), and the ADR-185 Part 1 agent-identity drift (3). `scripts/mcp-tool-lint-baseline.json` is deleted; MCP Tool Lint now runs in fully-strict mode. No behaviour change — tool discovery, audit categorisation, and risk-tier gating now classify the same 29 tools they couldn't classify before. `credits_required` deliberately omitted from new entries (credit gating is a no-op pass-through since ADR-162). Retry-safety follows ADR-180's `risk × retry_safe` table — e.g. `pica_enrichment_proposal_apply` is `retry_safe: false` (writes to entity columns), `_reject` is `retry_safe: true` (content-hash suppression is set-once). ADR-180 flipped from `Proposed` to `Accepted`.\n- **ADR-193 Surfaces 1+3: peer-connector coaching + URI source conventions (server-instructions addendum).** Handshake copy coaches agents to check peer MCPs (email / drive / notes / calendar / DAW) before asking users to paste or type data, and to cite findings via `pica_enrichment_propose` `sources[].url` using URI schemes — `gmail://` `gdrive://` `notion://` `file://` `telegram://` `calendar://` `daw://` `user://` `web://`. See `docs/mcp-source-uri-conventions.md` in the main repo for shapes. First concrete build for ADR-190 Principles 2 + 3 (Agent-Mediated Source Discovery). A latent HTTP-transport gap was fixed in the same develop commit (`63eef17f8`) — `/api/mcp/route.ts` was not wiring `SERVER_INSTRUCTIONS` into its Server constructor, so remote agentic clients (ChatGPT Apps, Claude Desktop remote, Cursor) saw zero coaching. The stdio transport in this package was always serving instructions correctly; only the remote transport was affected.\n\n### Added\n\n- **ADR-193 Surface 2: `gap_hints` envelope on 4 read tools.** `pica_works_inspect`, `pica_agreements_inspect`, `pica_people_inspect`, and `pica_enrichment_proposals_list` now emit an optional `gap_hints[]` field on `structuredContent` when a real gap is present. Each hint is capability-named (ADR-190 Principle 2 — `email_search` / `drive_search` / `filesystem_search` / `notes_search` / `calendar_search` / `web_search`, never vendor names), carries a concrete `query_shape`, and pre-fills the `then_call: \"pica_enrichment_propose\"` with the exact `then_args_shape` the agent should emit back (including URI-citation scaffolding from Surface 3). Gated by `MCP_GAP_HINTS_ENABLED=1` — off by default in prod. Empty array / omitted envelope when there's no real gap. Flat additive — the existing `CompletionHint` pipeline on `works_inspect` is untouched. Bundled: `enrich-metadata` prompt references the peer-connector pattern and points the agent at `gap_hints`.\n- **ADR-193 Surface 4: `pica_enrichment_propose` accepts `proposal_action: \"create\"`.** Closes the reserved-but-unwired create path from ADR-178 Phase 1. The tool schema now accepts `entity_type: \"recording\" | \"agreement\" | \"person\"` paired with `parent_entity_type` + `parent_entity_id` for create proposals. Apply-path branches on `rule_id === \"agent_research\"` and routes to `recordingsService.create` (parent required; `work_id` linkage), `agreementsService.create` (optional work parent, linked via `agreementWorksService.addWork` after create), or `peopleAdminService.create` (standalone — people have no parent FK). Recording creates seed `field_sources` verbatim from `proposal.sources[].url`, preserving URI schemes (gmail://, gdrive://, notion://, file://, telegram://, user://, web://) per ADR-193 AC 5. Agreements + people don't carry `field_sources` on the main table today; provenance URIs are captured in `resolution_note` until a follow-up migration adds the column. Work + publisher creation remain explicitly out of scope (dedup-critical — deferred to future ADR). Migration `20260422_01_adr193_proposal_parent_fields` adds nullable `parent_entity_type` + `parent_entity_id` columns with a CHECK pair + partial index for the review-queue scan. Legacy `artist_title_to_youtube` create rule is untouched (it continues to overload `entity_id` as the parent work id). 4 new service-layer tests green; total proposal-service suite 42/42.\n- **ADR-185 Part 1: three new session-auth-only tools.** `pica_create_agent_identity`, `pica_issue_agent_grant`, `pica_list_my_agent_grants`. Back a user-issued agent-identity + scoped-grant primitive — the substrate for Parts 2 (settings UI) and 3 (per-write provenance stamping). All three require `write:agent_identity` scope AND session-auth (raw API key / OAuth); the HTTP MCP dispatcher refuses `pica_grant_` callers with a structured `reason: \"session_auth_required\"` error before execution per AC 12. Subject is always the authenticated user — caller-supplied `user_id` is dropped per ADR-184 rule 2 / ADR-185 rule 1. Grant tokens use the format `pica_grant_<64 hex>` and are hashed at rest with HMAC-SHA256 + `API_KEY_HASH_PEPPER` (same scheme as api_keys per ADR-185 line 193 + ADR-167 D-5).\n- **ADR-185 Part 2: two new session-auth-only tools.** `pica_revoke_agent_grant` (DELETE `/admin/agent-grants/:id`, idempotent, 404 masks ownership failures) and `pica_get_agent_activity` (GET `/admin/agent-activity`, paginated, optionally filtered by identity or grant). Both appended to `SESSION_AUTH_ONLY_TOOLS` in the HTTP MCP dispatcher and to the `write:agent_identity` scope bucket. Together with the Part 1 trio this completes the five-tool agent-identity surface the ADR Scope requires. Revocation takes effect on the next request (AC: within 60s — `resolveGrantToken` checks `revoked_at` on every call, no cache layer).\n- **ADR-185 Part 3 passes 1-5: agent-action provenance stamping wraps 27 write-tool families.** Part 3 layers two complementary wrappers over existing write tools so every per-grant write records a row in `mcp_agent_actions` for audit + revoke-replay. `withAgentActionStamp` (compensation-after): handler runs, stamps; on stamp failure, compensation undoes the write via captured prior state — used for creates and updates (soft-delete families get meaningful delete compensation — flip `is_deleted` back). `withAgentActionStampFirst` (stamp-first, pass 4): stamp commits BEFORE the destructive op; stamp-ok + handler-fail logs a \"ghost stamp\" at error level — used for hard-delete families where compensation is impossible. Both wrappers are no-ops when the caller is not an agent grant (session-auth / raw API key writes are unaffected). Families covered across the five passes: works/recordings/people/agreements/releases/notes creates; notes_delete; sessions_create; share_links_create; projects_create; multimedia_create; recording_splits_create; works_update; recordings_update; people_update; agreements_update; projects_update; notes_update; releases_update; people_delete; publishers_create; the six hard-delete families (works/recordings/agreements/projects/sessions/releases) via the stamp-first variant; and pass 5's `pica_projects_attach_works` (project_works insert wrapped, GET + POST migrated from `requireAuth` + `getUserProfile` to `withOrgContext` for consistency). `pica_sessions_update` remains deferred — action-branching route (start/complete/cancel + participant add/remove + regular update) needs a dedicated design slice before wrapping.\n- **New tool** `pica_submit_feedback`: agent-native feedback submission. Routes bug_report→devops, feature_request→ceo, question→comms, other→category-mapped. Requires `write:feedback` scope. Subject is always the authenticated user per ADR-184 rule 2. (ADR-184 slice 8 — landed on develop 2026-04-19 post-2.23.0 publish.)\n- **ADR-189 Phase 3: two new identity-capture tools.** `pica_update_my_identity` (stage_name / IPI / ISNI / IPN / PRO) and `pica_update_organisation_profile` (org_type / display_name / tagline / ipi_number). Both admin-scoped, both `retry_safe: true` (idempotent upserts — re-applying the same IPI leaves the row in the same state). Subject derived from auth (no `user_id` / `organisation_id` parameters — ADR-184 rule 2). After the identity write, `pica_update_my_identity` re-runs cross-org discovery and returns the count of newly-visible credits / custody / artist-link rows so the agent can surface \"found N more — claim them?\" in the same conversation turn. Rate-limited at 20 writes/hour/user via `checkActionRateLimit` (R1 mitigation). Admin routes (`POST /api/admin/my-identity`, `POST /api/admin/organisation-profile`) wrap in `withAgentActionStamp` when the caller presents an agent grant (ADR-185 Part 3) — UPDATE compensation captures pre-write state via read-before-write and PATCHes the row back on stamp failure, or deletes a lazy-created person row.\n- **ADR-189 Phase 4 Task 1: `pica_claim_credit`.** New activation-loop tool that drains a `discovered_credits` row into a `work_credits` row in the calling org, giving the user `view` access to the linked work. Check-and-set on `discovered_credits.status` prevents double-claims in concurrent sessions. Rate-limited to 20/hour per user via `checkActionRateLimit`. Returns `is_first_claim: true` on first-ever claim by the user (derived from `agent_action_log` stamp count). Wraps in `withAgentActionStamp` for grant callers — compensating transaction calls `revertClaimCredit` (flips discovery back to `pending` + deletes the `work_credits` row) if the stamp INSERT fails. Error taxonomy: `DISCOVERY_NOT_FOUND` (404), `DISCOVERY_ALREADY_RESOLVED` (409), `EVIDENCE_REVOKED` (410), `RATE_LIMITED` (429 + `Retry-After`). `pica_claim_credit` added to `ADMIN_ONLY_TOOLS` in `mcp-scopes.ts`; metadata entry `category: \"discovery\", risk: \"mutating\", retry_safe: false`. Route: `POST /api/admin/discoveries/[id]/claim-credit`. SDK method: `pica.discoveries.claimCredit(id)`.\n- **ADR-189 Phase 4 Task 2: `pica_claim_custody` + +72h auto-approve worker.** Drains a `discovered_custody` row into a pending `custody_claims` row (status=`pending`, `chain`=custody_type, `custody_source`=`claimed`, provenance in `evidence.source`=`\"auto-discovered-via-email\"`). Schedules a silent-consent auto-approve by inserting a `scheduled_notifications` row (`source=pica_claim_custody`, `deliver_at`=+72h, message=`custody_auto_approve:<uuid>`). Does NOT mutate `works.{composition,master}_custodian_org_id` immediately — the 1-minute cron fires `scheduledNotificationsService.drainDue()` which now dispatches `source=pica_claim_custody` rows to a new `handleCustodyAutoApprove` branch that runs the **Delta 1 stale-promotion guard**: UPDATE `works` custodian columns ONLY IF the snapshot captured at claim time (`expected_previous_custodian_org_id` + `expected_custody_source` + `custody_side` — migration `20260421_01_custody_claims_expected_previous`) still matches; otherwise flip the claim to `superseded` (new status) and leave the catalog untouched. Error taxonomy identical to `pica_claim_credit`. `pica_claim_custody` was already in `ADMIN_ONLY_TOOLS` since Phase 4 Task 0; this ships the actual wiring. Route: `POST /api/admin/discoveries/[id]/claim-custody`. SDK method: `pica.discoveries.claimCustody(id)`. Stamp compensation via `revertClaimCustody` flips discovery back to pending, cancels the scheduled_notification, deletes the custody_claims row.\n\n## [2.24.0] - 2026-04-21\n\n### Fixed\n\n- **`pica_integrations_status` no longer tells users to \"connect Spotify\".** Two real-user failures on Claude Desktop (2026-04-21) traced back to the tool lumping platform-level Spotify/YouTube (PICA has its own credentials; no per-user OAuth exists or has ever existed) into the same \"Available to connect\" list as genuine user-OAuth peer connectors (Google/Notion/Airtable/Telegram). Failure modes observed: (1) user pasted a Spotify track URL → agent replied \"head to your Pica dashboard and add Spotify as an integration\"; (2) user asked \"what songs do I have in pica\" with a catalog holding 1 work → agent replied \"you currently have no connections set up in Pica — so there are no songs or any other data accessible.\" Reshape: the tool now returns `peerConnectors` (the 4 actual OAuth services) separately from `platformReads` (Spotify, YouTube, MusicBrainz, MLC, ISNI, Discogs, with the tool name for each). Summary leads with \"PICA catalog is ALWAYS accessible via pica_works_query, pica_people_query, pica_dashboard_briefing, pica_search_all — no setup required.\" The dead `connectedProviders.includes(\"spotify\")` check that could never evaluate true was removed.\n- **Server instructions: catalog-is-always-accessible guidance.** Handshake now explicitly states (a) the catalog is always accessible via the read tools with zero setup, (b) `pica_integrations_status` showing \"0 connected\" refers to optional peer connectors, NOT the catalog — call `pica_works_query` to check, (c) Spotify/YouTube URLs go through `pica_import_streaming_link` / `pica_import_youtube_link` directly; no per-user Spotify/YouTube OAuth exists to set up, do not tell the user to \"connect Spotify in your dashboard\". Replaces earlier copy that left the agent free to hallucinate a dashboard-integration flow. `lib/mcp/server-instructions.ts` parity copy updated in lockstep; the HTTP transport at `/api/mcp` picks up the new text on next handshake without requiring a redeploy of this package. Under the 2000-char token budget at 1833 chars.\n\n## [2.23.0] - 2026-04-19\n\n### Added\n\n- **ADR-181 Phase 1: `pica_audit_list` ported from `@withpica/mcp-server-settings`\n (ADR-154 F6).** Closes the one trailing-gap tool from the source-merge audit —\n every other tool the three sub-servers exposed was already registered by\n `mcp-server`'s superset. Registered in `lib/services/mcp-scopes.ts`\n `ADMIN_ONLY_TOOLS` alongside the team / org-profile admin operations; the\n `mcp_audit_log` read is org-scoped and matches the existing admin posture\n for `pica_organisation_profile` / `pica_team_list`. Landed in `54ae935d9`\n via PR #50.\n- **ADR-181 Phase 1: bundle-size CI gate per Decision 2.** New\n `scripts/check-mcp-bundle.ts` walks `mcp-server/dist/`, sums byte size\n (excluding source maps), and fails if total > 210 MB (70% × Vercel's\n 300 MB serverless-function cap). Runs on every push / PR that touches\n `mcp-server/**`, `mcp-server-shared/**`, the script, or the workflow\n itself (`.github/workflows/mcp-bundle-size.yml`). `package.json`\n `prepublishOnly` invokes it locally so a bloated bundle can't ship out\n of a developer machine. Current measurement on this branch:\n 0.79 MB / 210 MB limit (0.38% of cap). Landed in `558315069` via PR #50.\n\n## [2.22.0] - 2026-04-18\n\n### Added\n\n- **ADR-174 Phase 2 item 7 follow-up: `pica_projects_attach_works` (stdio).**\n Closes the `work_ids` FIELD_NOT_WIRED gap on `pica_projects_create` /\n `_update`. Pre-slice the MCP tools advertised `work_ids` but the admin\n route silently dropped it — the route redirect message already pointed\n agents at `POST /api/admin/projects/[id]/works`, but no MCP tool\n exposed that path. The new tool accepts\n `{ project_id, works: [{ work_id, project_day?, notes? }...] }` and\n attaches each item via `ProjectsResource.attachWork` with per-item\n result reporting (`attached[]`, `skipped[]` for already-linked,\n `failed[]` for other errors). Registered in `lib/services/mcp-scopes.ts`\n under `write:catalog`.\n\n### Changed\n\n- **ADR-174 Phase 2 item 22: `pica_publishers_create` reshaped.** Pre-slice\n the schema exposed only `{ name, ipi }` (2 fields) and the SDK's\n `PublishersResource.create` hit a 404 — the admin route did not exist.\n The companion slice 1 commit added `POST /api/admin/publishers`;\n this slice reshapes the tool to match. All 8 audit-row-22\n Add-candidates surfaced (`legal_name`, `country`, `isni`,\n `publisher_type`, `wikidata_id`, `parent_publisher_id`,\n `founded_date`, `headquarters`) plus the explicit `ipi → ipi_number`\n rename. `parent_publisher_id` description steers agents at\n `pica_publishers_query` to resolve the parent UUID. Required fields:\n `name`, `ipi_number`. The route is idempotent on `ipi_number` — a\n duplicate IPI returns the existing row with `already_existed: true`\n instead of failing.\n\n- **ADR-174 Phase 2 items 14+15: `pica_agreements_create` / `_update`\n reshaped to consume `AGREEMENTS_WRITE_PROPERTIES` from\n `@withpica/mcp-utils`.** Tool schemas now advertise all 13\n Add-candidate columns from audit rows 14+15. Tool descriptions steer\n agents toward `counterparty_org_id` (ADR-176 first-class-party) over\n free-text `other_party_name` — use `pica_search_all` to resolve an\n org name to an ID. `_update` description calls out that\n counterparty_org_id changes require the linked-org check at the\n route layer (orgLinkingService.areLinked). No tool signature change\n otherwise; existing fields preserved.\n\n### Route-side companion (non-package, same slice)\n\n- `app/api/admin/agreements/route.ts` POST and\n `app/api/admin/agreements/[id]/route.ts` PATCH — phantom/unknown key\n rejection via `AGREEMENT_POST_ALLOWED_FIELDS` /\n `AGREEMENT_PATCH_ALLOWED_FIELDS` /\n `AGREEMENT_WRITE_PHANTOM_REDIRECTS` in\n `lib/services/agreements-write-constants.ts`. Pre-slice both routes\n spread `body` straight into the Supabase insert/update — effectively\n a wide-open write surface. Also surfaces and fixes pre-existing dark\n code in the PATCH test file (3 tests were sending `name` and `type`\n — phantom field names that silently dropped against `title` and\n `agreement_type`).\n\n- `app/api/admin/publishers/route.ts` POST (NEW) — publishers had no\n admin route at all pre-slice, so `pica_publishers_create` and the\n SDK's `PublishersResource.create` 404'd at runtime. Slice 1\n (0ba4d400d) adds the route with phantom/unknown-field rejection via\n `PUBLISHERS_POST_ALLOWED_FIELDS` / `PUBLISHERS_WRITE_PHANTOM_REDIRECTS`\n in `lib/services/publishers-write-constants.ts`, idempotent\n deduplication by `ipi_number`, FK pre-validation on\n `parent_publisher_id`, and server-stamped provenance.\n\n- **ADR-174 Phase 2 item 21: `pica_multimedia_create` reshaped.** Added\n 15 real-column fields that were invisible to agents pre-ADR-174:\n `credits`, `duration_seconds`, `collection_id`, `display_order`,\n `is_featured`, `is_published`, `venue`, `event_name`,\n `performance_date`, `setlist_position`, `sync_side`, and the external\n identifier set (`spotify_url`, `spotify_track_uri`, `spotify_track_id`,\n `youtube_url`, `youtube_video_id`, `soundcloud_url`, `thumbnail_url`).\n Description now points agents at `POST /api/admin/multimedia/upload`\n for file uploads and `pica_multimedia_link_youtube` for the YouTube\n enrichment flow — the generic create surface is for external-URL\n linking and performance-context metadata.\n\n### Route-side companion (non-package, same slice)\n\n- `app/api/admin/multimedia/route.ts` POST — phantom/unknown key guard\n via `MULTIMEDIA_POST_ALLOWED_FIELDS` /\n `MULTIMEDIA_POST_PHANTOM_REDIRECTS` in\n `lib/services/multimedia-write-constants.ts`. Redirects upload-flow\n columns (s3*key, file_name, …) to `/api/admin/multimedia/upload`,\n enrichment columns (youtube_view_count, spotify_popularity) to their\n respective cascades, and scanner columns (virus_scan*\\*) to the\n scanner flow. Also closes a latent privilege-escalation path: pre-slice\n the route overwrote `body.user_id` with the authenticated session's\n id, but a caller could still _attempt_ to pass `user_id` (silently\n overwritten). The guard now 400s on `user_id` / `organisation_id`\n injection attempts with a clear PHANTOM_FIELD message.\n\n- **ADR-174 Phase 2 item 13: `pica_sessions_create` reshaped.** Dropped\n `additionalProperties: true` per Decision 2. Added 6 previously-missing\n real columns from audit row 13 as explicit Zod properties:\n `description`, `timezone`, `is_all_day`, `location_url`, `recording_id`,\n `status` (enum: scheduled / in_progress / completed / cancelled), plus\n the `metadata` jsonb bag and the `participants` relational array\n (already handled by the service but undocumented in the tool surface).\n `recurrence_rule` deferred — the service's `CreateSessionParams` type\n needs to accept it first (tracked in the route-guard PHANTOM_REDIRECT\n entry).\n\n### Route-side companion (non-package, same slice)\n\n- `app/api/admin/sessions/route.ts` POST now reads `body.status` and\n `body.metadata` (pre-slice silently dropped) and 400s on phantom /\n unknown keys via `SESSION_POST_ALLOWED_FIELDS` /\n `SESSION_POST_PHANTOM_REDIRECTS` in\n `lib/services/sessions-write-constants.ts`.\n\n- **ADR-174 Phase 2 item 20: `pica_share_links_create` reshaped to\n consume `SHARE_LINKS_WRITE_PROPERTIES` from `@withpica/mcp-utils`.**\n Tool schema now advertises all 13 add-candidate columns from audit\n row 20 that were previously invisible to agents (access_type,\n allowed_person_ids, allow_comments, allow_view_collaborators,\n allow_view_financials, notify_on_access, watermark_audio,\n sent_to_emails, playlist_name, allow_streaming, include_all_files,\n included_file_ids, description). Executor widened to pass every\n caller-provided property through to the SDK / admin route — the\n route-layer allow-list (slice 1) rejects anything outside the\n contract. `password` remains the canonical plain-text input; the\n route hashes to `password_hash`.\n\n- **ADR-174 Phase 2 items 16+17: `pica_agreement_types_create` / `_update`\n reshaped to consume `AGREEMENT_TYPES_WRITE_PROPERTIES` from\n `@withpica/mcp-utils`.** Dropped the inlined property map in favour of\n the shared module that documents per-branch applicability. Phantom\n fields `title`, `description`, `points_percentage`, `recoupment_terms`,\n `rights_assigned` removed from the schema (agents sending them now fail\n fast at the admin route guard with a `PHANTOM_FIELD` redirect pointing\n at the canonical column or resolution path). Tool descriptions updated\n to truthfully list the required fields per branch (template needs\n `name` + `category` + `templateText`; producer needs `producer_id` +\n `royalty_points` + `deliverables` + `work_id`|`recording_id`;\n work_for_hire needs `contractor_id` + `contractor_role` + `fee_amount`\n - `services_description` + `work_id`|`recording_id`). Tool description\n for `_update` now calls out that PATCH on producer_agreements and\n work_for_hire_agreements is action-only — the generic update path has\n no live field-update surface on those two branches until a follow-up\n slice promotes the action-based PATCH handlers to accept field\n updates.\n\n### Added\n\n- **ADR-179 Phase 1: `pica_resolve_work` (stdio).** Outcome-shaped\n resolver that fans a work out across every eligible enrichment source\n in one call. Replaces the five `pica_enrich_work_*` tools' role at\n the agent layer. Returns `applied[]` / `proposals[]` / `errors[]` /\n `recovery_hints[]`. `isError` is set only when every source that ran\n errored — partial failure is a non-error receipt. Credit + billing\n gates wire through the `external_resolver_call` action key.\n- **ADR-179 Phase 2: `pica_resolve_person` (stdio).** Person-side\n resolver mirroring `pica_resolve_work`. Sources are narrower —\n `isni` | `musicbrainz` — covering the identity-graph cascade rules\n (ISNI→Wikidata and MBID→Wikidata crosswalks plus their downstream\n awards / biography enrichment). Same output shape, same isError\n semantics, same credit-gate action key as the work resolver.\n Registered in `lib/services/mcp-scopes.ts` under `write:people` and\n listed in the layered-discovery `enrichment` category so\n `pica_discover` surfaces it above the deprecated\n `pica_people_enrich_*` pair.\n\n### Deprecated\n\n- **`pica_enrich_work_mlc`, `pica_enrich_work_musicbrainz`,\n `pica_enrich_work_discogs`, `pica_enrich_work_spotify`,\n `pica_enrich_work_youtube`.** All five now return\n `TOOL_DEPRECATED` (jsonrpc code -32070) with a suggested-call\n payload pointing at `pica_resolve_work` with the correct `sources`\n narrowing. Tool definitions stay registered so `tools/list` and\n `pica_tool_details` can still surface them with a migration hint for\n one minor version — removal scheduled for the next minor after\n ADR-179 Phase 4's publish.\n- **`pica_people_enrich_isni`, `pica_people_enrich_musicbrainz`.**\n Both now return `TOOL_DEPRECATED` (jsonrpc code -32070) with a\n suggested-call payload pointing at\n `pica_resolve_person(sources: ['isni' | 'musicbrainz'])`. Tool\n definitions stay registered until the next minor; same one-minor-\n version deprecation window as the work-side five.\n\n### Changed\n\n- `pica_tool_details` responses for the five deprecated work tools\n now carry a `TOOL_DEPRECATED` entry in `recovery_hints` as the first\n item. Existing `NO_MATCH` / `MISSING_INPUT` hints are kept behind\n it — they are dead code today but stay in the registry until tool\n removal so downstream consumers don't see a mid-version\n disappearance.\n- Same treatment applied to the two deprecated person tools:\n `pica_people_enrich_isni` and `pica_people_enrich_musicbrainz` each\n get a `TOOL_DEPRECATED` recovery hint prepended to their existing\n `NO_MATCH` entry.\n\n## [2.22.0] — 2026-04-16\n\n### Changed\n\n- **ADR-174 Phase 2 item 10 (recording_splits): reshape\n `pica_recording_splits_create`.** Adopts the shared\n `RECORDING_SPLITS_WRITE_PROPERTIES` from `@withpica/mcp-utils@1.4.0`,\n dropping `additionalProperties: true` per Decision 2. All 9 audit-\n Keep fields now enumerated as explicit Zod properties — no phantom\n additions, no renames. Description-level hint on `role` replaced\n with a proper `enum` array matching the route's validRoles allow-\n list. Schema is now byte-identical to `@withpica/mcp-server-business`\n (both consume the shared module) — pre-slice they were independent\n byte-divergent-risk copies.\n\n### Route-side companion (non-package, same slice)\n\n- `app/api/admin/recordings/[id]/splits/route.ts` POST — UNKNOWN_FIELD\n guard runs before the required-field check so misspelled keys fail\n fast with the field name. See the slice commit.\n\n## [2.21.0] — 2026-04-16\n\n### Fixed\n\n- **ADR-174 Phase 2 item 24 (team): `pica_team_update_role` now actually\n updates role.** Pre-ADR-174 the tool was named `_update_role` but its\n Zod schema only accepted `permissions` — the `role` field was missing\n entirely. The admin PATCH route at `/api/admin/team/[id]` hard-\n destructured `{ permissions }` and silently dropped every other\n field, so even if an agent hand-crafted a call with `role` the DB\n write would not happen. Audit row 24 flagged this as \"Add `role`, or\n rename the tool.\" Fixed by adding `role: string` to the MCP Zod\n schema, widening the route to build the update object from whichever\n of `role` / `permissions` are provided, and making the old\n \"permissions required\" check accept \"at least one of role or\n permissions.\" `id` stays required; `role` and `permissions` are now\n both optional but at least one must be set.\n\n### Route-side companion (non-package, same slice)\n\n- `app/api/admin/team/[id]/route.ts` PATCH — phantom/unknown key\n rejection via `TEAM_MEMBERSHIP_PATCH_ALLOWED_FIELDS` (allow-list of\n `permissions` + `role`), error message updated from \"permissions\n required\" to \"at least one of permissions or role is required\", and\n \"failed to update permissions\" to \"failed to update team membership\"\n (now-generic — it updates role too).\n\n## [2.20.0] — 2026-04-16\n\n### Changed\n\n- **ADR-174 Phase 2 item 7 (projects): reshape `pica_projects_create` /\n `pica_projects_update` Zod schemas.** Exposed 9 Add-candidate fields\n from audit row 18 that were already plumbed end-to-end through the\n route and service but invisible to agents via tool discovery:\n `start_date`, `end_date`, `location_name`, `location_address`,\n `location_url`, `virtual_url`, `is_open`, `max_participants`, `status`\n (enum: draft / scheduled / active / completed / cancelled). Also\n surfaced the route-level `generate_invite_code` flag and the\n freeform `metadata` jsonb object. Dropped `work_ids` from both\n schemas — the pre-ADR-174 tool advertised `work_ids` but the admin\n POST / PATCH routes never routed it to the `project_works` junction\n (see commit `edf890a24` for the route-side FIELD_NOT_WIRED rejection\n and redirect message pointing at\n `POST /api/admin/projects/[id]/works`). The `project_type`\n description replaces the pre-ADR-174 \"album, ep, compilation, single,\n mixtape\" hint (none of which are valid backend values) with the\n actual convention: writing_camp, recording_session, production,\n mixing, mastering, retreat, other.\n\n### Route-side companion (non-package, same slice)\n\n- `app/api/admin/projects/route.ts` POST and\n `app/api/admin/projects/[id]/route.ts` PATCH — phantom/unknown key\n rejection with `FIELD_NOT_WIRED` redirect for `work_ids`. See commit\n `edf890a24`.\n\n## [2.19.0] — 2026-04-16\n\n### Added\n\n- **ADR-178: `pica_enrichment_propose` stdio tool.** New agentic write\n tool that files enrichment proposals sourced from open-web research\n (Audiomack, Songdata, MusicBrainz page, label portals, artist bios,\n etc.) rather than from PICA's structured cascade. Every proposed\n field must cite at least one source URL — `sources[].fields` arrays\n form the trust moat, and the server rejects uncited claims with\n `code: MISSING_SOURCE`. Source type routes the proposal as\n `source = 'agent_research'`, `rule_id = 'agent_research'` on the\n existing `enrichment_proposals` table (no new queue, no new review\n tools — reuses `pica_enrichment_proposals_list` / `_apply` /\n `_reject` from `2.10.0`).\n\n Tool description carries ADR-178 Decision 3 language verbatim: when\n the user is in-session, the agent asks for approval directly and\n calls `pica_enrichment_proposal_apply` after confirmation — the\n dashboard card is the receipt, not the workflow. This shapes agent\n behaviour in-context without needing a new code path for \"in-\n session approval\".\n\n Wrapped in `withBillingGate` and (via\n `@withpica/mcp-utils@1.3.0`) `withCreditGate` under the new\n `enrichment_propose` action key. Credit gating is telemetric only\n while ADR-162 keeps the subscription gate on; the wrap is already\n in place so re-enabling billing doesn't need a tool-surface change.\n\n### Fixed\n\n- **ADR-178 slice 1b regression caught in smoke test:** agent-research\n proposals whose `proposed_fields` cite columns that don't exist on\n the target table (tempo_bpm, musical_key, producers — the Heinzmann\n transcript's fields, not columns on `works`) used to 500 with a\n Postgres \"column does not exist\" error because the service built a\n column-scoped `SELECT` from the proposed keys. Fix snapshots the\n full live row and builds `current_fields` from the intersection of\n proposed keys and actual columns. Unknown keys now land as pending\n proposals with an empty baseline instead of crashing the request.\n Apply path for unknown-column fields is a separate open question on\n the ADR (see Open Question 5).\n\n## [2.18.0] — 2026-04-16\n\n### Changed\n\n- **ADR-174 Phase 2 item 6: reshape `pica_credits_update` Zod schema.**\n Dropped phantom `publisher_name` and `publisher_ipi` properties —\n `work_credits` has no columns for either. Agents now resolve a\n publisher name or IPI to a UUID via `pica_publishers_query` (or\n create one via `pica_publishers_create`) and pass the result as\n `publisher_id`. Added three audit \"Add candidate\" columns to the\n per-credit-object shape: `is_primary` (boolean), `notes` (string),\n `attestation_status` (enum: pending / attested / disputed /\n declined). `attested_at` / `attested_by` remain service-managed.\n Description refresh calls out `credit_type` as the canonical column\n name stored behind the `role` alias and `writer_split_percentage`\n behind `splits`. No required-field change — `person_id`, `role`,\n `splits` stay required.\n\n### Route-side companion (non-package, same slice)\n\n- `app/api/admin/works/[id]/credits/route.ts` POST — phantom/unknown\n key rejection on each `credits[i]` element with field name + index\n in the error payload, plus a mirror-fill step that normalises\n `role` ↔ `credit_type` and `splits` ↔ `writer_split_percentage` so\n callers sending either spelling flow through. See commit\n `dbfb098ae` for the server-side guard.\n\n### Not covered by this slice\n\n- `work_collaborators` (publishing-side POST at\n `app/api/admin/works/[id]/collaborators/route.ts`) was not in the\n ADR-174 audit — the MCP tool's `updateCollaborators` SDK hop hits\n that route for writer/composer/lyricist/arranger roles today and\n inherits a separate column set. Tracked as a follow-up slice.\n\n## [2.17.0] — 2026-04-16\n\n### Changed\n\n- **ADR-174 Phase 2 item 5: reshape `pica_physical_assets_create` and\n `pica_physical_assets_update` Zod schemas.** Adopted the shared\n `PHYSICAL_ASSETS_WRITE_PROPERTIES` from `@withpica/mcp-utils@1.2.0`,\n dropped `additionalProperties: true` on both tools, and moved 11\n phantom top-level fields (`current_valuation`, `valuation_currency`,\n `valuation_source`, `valuation_date`, `valuation_notes`,\n `reverb_listing_url`, `ebay_item_url`, `insured`,\n `insurance_provider`, `insurance_policy_number`, `insurance_coverage`)\n off the top-level surface. Agents set these via\n `external_references: { current_valuation: 1500, insurer: \"ACME\", ... }`\n per the ADR-174 Open Decision 1 (2026-04-14) resolution. Two fields\n were renamed at the jsonb layer: `insurance_provider → insurer`,\n `insurance_coverage → insured_value`. `asset_type`, `condition`,\n `acquisition_method`, `license_type`, and `status` gained proper\n `enum` arrays matching the underlying `physical_assets_*_check` CHECK\n constraints — pre-reshape they were loose strings with the enum\n hinted in the description (so callers could pass `studio_equipment`\n at the MCP layer and get a 500 from the CHECK constraint at the DB\n layer).\n- **No description lie.** Both tool descriptions now explicitly name\n `external_references` as the home for valuation/insurance/DSP URL\n details rather than the pre-ADR-174 \"tracks … valuation, photos,\n insurance, and status\" claim that the schema couldn't honour.\n\n### Route-side companion (non-package, same slice)\n\n- `app/api/admin/assets/route.ts` POST and\n `app/api/admin/assets/[id]/route.ts` PATCH — phantom/unknown key\n rejection with redirect messages (400 + `PHANTOM_FIELD` /\n `UNKNOWN_FIELD` error codes). See commit `ced46b889` for the\n server-side guard.\n\n## [2.16.0] — 2026-04-15\n\n### Added\n\n- **ADR-173: five release-track tools.** Closes the gap flagged by two\n independent external MCP reviewers on 2026-04-14 (\"release layer looks\n shallow\"). New tools on the stdio transport:\n - `pica_releases_attach_track` — attach a recording and/or work at a\n specific `(disc_number, track_number)`. Idempotent on position.\n At least one of `recording_id` / `work_id` is required.\n - `pica_releases_list_tracks` — list tracks in `(disc, track)` order\n with inlined title/artist/ISRC/duration from the linked recording\n and work.\n - `pica_releases_detach_track` — soft-confirmation detach by position\n (preview without `confirm:true`, delete with).\n - `pica_releases_reorder_tracks` — transactional positional reorder\n via the `reorder_release_tracks_atomic` Postgres RPC. Rejects\n duplicate positions in the payload before any DB write.\n - `pica_releases_attach_recording_with_work` — compound workflow that\n auto-pulls the recording's linked work onto the new track row.\n\n### Changed\n\n- **`pica_works_inspect` and `pica_recordings_inspect` gain a `releases`\n section.** Lazy (only fetched when requested). Returns every release\n the entity appears on with its track position. Answers \"which albums\n is this master on?\" in one call — previously unanswerable via MCP.\n\n### Fixed\n\n- **`pica_releases_list_tracks` 500 on every call.** Pre-merge E2E\n caught two latent bugs in the `listTracks` service query: a missing\n FK `release_tracks.recording_id → recordings(id)` (PostgREST could\n not resolve the `recording:recordings(...)` embed) and a\n `duration_seconds` column reference where the live column is\n `duration_ms`. Fixed in migration\n `20260415_01_adr173_fix_release_tracks_recording_fk.sql` +\n a rename in `lib/services/releases.ts`. The migration also NULLs 85\n orphan `recording_id` values on production left behind by the\n 2026-04-04 soundslikefez duplicate-works cleanup.\n\n### Note on version number\n\nThis release would have been `2.15.0` per the original ADR-173\nimplementation record, but `2.15.0` was taken on `develop` by the\nADR-174 Phase 2 item 4 slice while the ADR-173 fix commits were in\nflight. Bumped to `2.16.0` to keep the published package timeline\nlinear.\n\n## [2.15.0] — 2026-04-15\n\n### Changed\n\n- **ADR-174 Phase 2 item 4: `pica_people_create` / `pica_people_update`\n schema reconciliation.** Introduced `PEOPLE_WRITE_PROPERTIES` as the\n canonical source of truth for the people write surface — every\n property maps to a real column on either `public.people` or\n `public.person_enrichment`. `additionalProperties: true` is off;\n unknown keys 400 at the HTTP layer (see develop commit\n `fbea9e2a3`).\n- **Satellite-routing made explicit.** Eleven fields remain in the\n schema but their descriptions now name `person_enrichment` as the\n write target: external identifiers (`isni`, `musicbrainz_id`,\n `wikidata_id`, `discogs_artist_id`, `deezer_artist_id`) and\n biographical data (`date_of_birth`, `gender`, `nationality`,\n `birth_place`, `instruments`, `career_start_year`). The service\n fans these out through `syncPersonEnrichmentSatellite`. Correction\n to the original audit (row 7) landed in ADR-174's Corrections\n block: six of these fields were classified as \"Remove — no column\n on people\", which missed the satellite hop. They are not phantom\n writes, and subsequent slices must audit satellite write paths\n before classifying any field as phantom.\n- **Twelve add-candidates surfaced** (audit row 7 \"Missing writable\n columns\"): `middle_name`, `person_type`, `company`, `position`,\n `territory`, `social_media`, `emails`, `pro_name`,\n `pro_member_number`, `mcps_member_number`, `relationship_strength`,\n `email_preferences`. All verified against `public.people` columns\n 2026-04-15 (project `fwgcmjhlwevdnxgqmkmh`).\n- **Deprecated duplicates rejected.** `type` (deprecated dup of\n `person_type`) and `role` (deprecated singular of `roles`) are\n now 400 PHANTOM_FIELD with a redirect message naming the canonical\n column. Both DB columns still exist as unused dead space —\n removing them is out of scope and scheduled for ADR-165-style\n cleanup.\n- **Description lies removed.** The audit (row 8) flagged\n `pica_people_update` description as \"Additional fields are also\n accepted\" with no enumeration. That sentence is gone from both\n `create` and `update` descriptions.\n\n### Breaking\n\n- Callers that were passing the deprecated `type` / `role`\n duplicates now get a 400 with a redirect hint — previously the\n keys were silently dropped by the ORM. Same failure-mode calculus\n as the works / recordings slices — the writes were already\n failing, now they fail visibly.\n- Callers that were passing arbitrary unlisted keys now get a 400 —\n previously `additionalProperties: true` let them through and the\n ORM dropped them silently. Zero rows observed in `people.metadata`\n jsonb for any of the pre-existing phantom keys (verified during\n ADR-174 Phase 1 2026-04-14).\n\n## [2.14.0] — 2026-04-14\n\n### Changed\n\n- **ADR-174 Phase 2: `pica_recordings_create` / `pica_recordings_update`\n schema reconciliation.** Introduced `RECORDING_WRITE_PROPERTIES` as\n the canonical source of truth for the recordings write surface —\n every property maps to a real column on `public.recordings`. Added\n thirteen fields the DB exposes that the tool was hiding:\n `duration_ms`, `preview_url`, `album_art_url`, `spotify_url`,\n `spotify_track_uri`, `spotify_track_id`, `youtube_video_id`,\n `youtube_url`, `apple_music_url`, `deezer_track_id`,\n `mlc_recording_id`, `mlc_song_code`, `isrc_prefix`. The\n `version_type` field is now enum-restricted to the ADR-166 values\n (`master`, `alternate_master`, `music_video`, `lyric_video`,\n `live_performance`, `acoustic`, `remix`, `cover`, `alternate`),\n matching the `recordings_version_type_check` DB constraint.\n- **`pica_recordings_create` default `version_type` changed from\n `\"original\"` to `\"master\"`.** Pre-fix the executor defaulted to\n `\"original\"`, which is not a valid version_type — every call without\n an explicit type tripped the recording-type CHECK constraint and\n surfaced as a 500 from the service. `\"master\"` is the DB-level\n default and the canonical ADR-166 value.\n- **Title rename made explicit.** `recording_title` is the canonical\n column on `public.recordings`. The tool keeps `title` as an input\n alias for ergonomics; the schema now declares both fields with the\n rename called out in their descriptions, instead of relying on\n `additionalProperties: true` to hide the translation.\n- Tool descriptions now steer album metadata (`album_name`,\n `album_release_date`, `upc`, `track_number`) to\n `pica_releases_create/update`, ISWCs to `pica_works_create/update`,\n and label metadata to `pica_releases_*.label_organization_id` via\n `pica_labels_query`. `duration_seconds` is explicitly named as the\n works convention; `recordings` carries `duration_ms`.\n\n### Removed\n\n- **ADR-174 Phase 2: seven phantom fields rejected on\n `pica_recordings_create` / `pica_recordings_update`.** The Zod schema\n no longer accepts them and `additionalProperties: true` is gone:\n `album_name`, `album_release_date`, `upc`, `track_number`, `label`,\n `duration_seconds`, `iswc` — none of these corresponded to columns on\n `recordings`. The HTTP route at `POST/PATCH /api/admin/recordings[/id]`\n now 400s on any of these keys with a redirect message naming the\n correct tool (commit `cffa6f947`).\n\n## [2.13.1] — 2026-04-14\n\n### Changed\n\n- **ADR-174 Phase 2: `pica_works_bulk_update.updates` schema gated on\n `WORK_WRITE_PROPERTIES`.** The bulk tool was the last write-path\n surface that still accepted any key — `updates: { type: \"object\" }`\n with no property list (audit row 25). Now validates against the same\n canonical schema as `pica_works_update`: phantom keys (label, upc,\n album_name, …) and arbitrary unlisted keys fail fast with a\n descriptive `VALIDATION_ERROR` before the SDK is called. One bad key\n invalidates the whole batch — no partial writes.\n\n## [2.13.0] — 2026-04-14\n\n### Changed\n\n- **ADR-174 Phase 2: `pica_works_create` / `pica_works_update` schema\n reconciliation.** Introduced `WORK_WRITE_PROPERTIES` as the canonical\n source of truth for the works write surface — every property maps to\n a real column on `public.works`. Added five fields the DB exposes\n that the tool was hiding: `tempo`, `key`, `display_artist`,\n `published`, `tunecode`. Tool descriptions now steer album/release\n metadata (`album_name`, `album_art_url`, `track_number`, `upc`,\n `spotify_url`) to `pica_releases_create/update` and label metadata to\n `pica_releases_*.label_organization_id` via `pica_labels_query`.\n\n### Removed\n\n- **ADR-174 Phase 2: seven phantom fields removed from\n `pica_works_create` / `pica_works_update`.** `label`, `spotify_url`,\n `album_name`, `album_release_date`, `album_art_url`, `track_number`,\n `upc` — none of these corresponded to columns on `works`. The HTTP\n route at `POST/PATCH /api/admin/works[/id]` now 400s on any of these\n keys with a redirect message naming the correct tool (commit\n `9d68b16b1`). Previously they routed silently into the\n `work_album_metadata` / `work_spotify_data` satellites that ADR-165\n marked as dead — a write succeeded but no reader could find the\n value.\n- **ADR-174 Phase 2: `additionalProperties: true` removed from both\n works write schemas.** The tool no longer silently accepts arbitrary\n keys; unknown keys surface as validation errors. Description lies\n about `available_for_licensing`, `vocal_type`, `energy`,\n `danceability` also removed — those fields live on satellite tables\n and are not exposed through MCP.\n\n## [2.12.0] — 2026-04-14\n\n### Added\n\n- **ADR-174 Phase 2: `pica_labels_query` tool** — read-only resolution of\n label names to `organisations.id`. Returns label organisations\n (`org_type='label'`) whose name or display_name matches the substring\n query, for use as `releases.label_organization_id` via\n `pica_releases_create` / `pica_releases_update`. `query` and `limit`\n both optional; limit defaults to 50, max 100. Category: catalog.\n Annotations: `readOnlyHint: true`.\n\n### Changed\n\n- **ADR-174 Phase 2: `pica_releases_create` / `pica_releases_update`\n schema reconciliation.** Input schemas now expose the nine ADR-174\n Decision 3 fields that `releases` actually stores:\n `label_organization_id`, `distributor_organization_id`,\n `pre_release_date`, `artwork_url`, `spotify_album_uri`, `spotify_url`,\n `apple_music_url`, `other_urls`, `notes`. Tool descriptions now\n direct agents to call `pica_labels_query` (new) or `pica_search_all`\n to resolve a label/distributor name to an organisation ID before\n writing.\n\n### Removed\n\n- **ADR-174 Phase 2: freetext `label` removed from\n `pica_releases_create` / `pica_releases_update`.** The field never\n corresponded to a real column on `releases` — the DB models labels\n via `label_organization_id` FK. Agents must now resolve a label name\n to an organisation ID (via `pica_labels_query`) instead of passing a\n string. Pre-fix behaviour: tool schema accepted `label`, service\n propagated it to the DB, the DB rejected it as `42703 column does not\nexist`, every call 500'd. No working integrations could have relied\n on this — the change is strictly a fix, not a break.\n\n## [2.11.0] — 2026-04-13\n\n### Changed\n\n- **ADR-171: Prompts replaced with workflow-level skills.**\n 11 prompts → 10 skills, each with decision trees, domain knowledge,\n enrichment source priority, and the shared preamble (tone, prerequisite\n check, summary pattern). Deployed as upgraded prompts; will convert to\n MCP skills format when the spec extension ships.\n\n New skills: `workspace-autopilot`, `establish-identity`,\n `catalog-your-music`, `upload-and-analyse`, `close-the-loop`,\n `manage-collaborators`, `establish-ownership`, `production-assets`,\n `stay-connected`, `export-and-report`.\n\n Retired prompts: `analyze-catalog`, `find-duplicates`,\n `enrich-metadata`, `verify-works`, `assess-catalog-health`,\n `audit-credits`, `new-catalog-setup`, `register-my-works`,\n `prepare-for-sync`. Functionality folded into new skills —\n see design spec for mapping.\n - `workspace-autopilot` now routes through the full journey sequence\n (identity → catalog → audio → gaps → collaborators → ownership →\n notifications → exports) instead of the old 5-condition router.\n - `close-the-loop` absorbs 7 former prompts and adds the enrichment\n cascade decision tree (MLC first if IPI, MusicBrainz second, Spotify\n third) and inline duplicate detection.\n - `export-and-report` absorbs `analyze-catalog`, `register-my-works`,\n and `prepare-for-sync` into a single export/report skill with CAR,\n CWR, CSV, provenance, sync readiness, and carbon footprint paths.\n\n## [2.10.0] — 2026-04-11\n\n### Added\n\n- **ADR-163: Tier B enrichment proposal review tools.**\n - `pica_enrichment_proposals_list` — list pending proposals\n awaiting review. Filters: `entity_type`, `entity_id`,\n `rule_id`, `source`, `limit` (1..100, default 20), `offset`.\n Only `status='pending'` rows are returned. Backed by\n `GET /api/admin/enrichment-proposals`.\n - `pica_enrichment_proposal_apply` — apply a pending proposal.\n For update proposals, runs drift detection first: if the\n entity has changed since the proposal was created, returns\n `{ status: 'drift_detected', conflicts }` without writing.\n Agents surface conflicts to the user before retrying with\n `force=true`. For create proposals (`artist_title_to_youtube`),\n a uniqueness check runs instead and cannot be forced. Backed\n by `POST /api/admin/enrichment-proposals/:id/apply`.\n - `pica_enrichment_proposal_reject` — reject a pending proposal\n with an optional `resolution_note`. Content-hash suppression\n (ADR-163) permanently blocks re-proposal of identical content\n — no cooldown, no timer. Backed by\n `POST /api/admin/enrichment-proposals/:id/reject`.\n\n- **ADR-166: YouTube import as a recording-version source.**\n - `pica_import_youtube_link` MCP tool wraps the Phase 3 orchestrator.\n Takes a YouTube URL, returns a preview (items + classification +\n work match), then `confirm: true` executes the import as a new\n recording on an existing or newly-created work. Supports\n `selectedVideoIds`, `targetWorkId`, and `overrideVersionType`\n for fine-grained agent control. Landed in `78da58344`\n (feat(adr-166): phase 4 — pica_import_youtube_link MCP tool + SDK\n methods).\n\n### Changed\n\n- `pica_cascade_health` outcome bucket list extended to include\n the ADR-163 Phase 1 `proposed` and `suppressed` outcomes. Tool\n description now reads `wrote / no_match / already_enriched /\nerror / proposed / suppressed`. Counters populate automatically\n from `cascadeOutcomeCounter` — no schema change required for\n existing `/api/admin/cascade-health` or\n `/api/internal/cascade-health` consumers.\n\n- Several mcp-server source files got minor reformatting from ADR-165's\n flattener strip (removing `work_spotify_data` + `work_album_metadata`\n fields from the Work shape) and ADR-166's cascade rule rewrites.\n These are consumer-invisible at the MCP tool surface — the tools\n still accept the same inputs and return the same outputs — but the\n underlying `PicaClient.works` reads + writes now route through the\n ADR-165 overlay. See the ADR-165 and ADR-166 implementation records\n for details.\n\n### Fixed\n\n- `pica_run_person_cascade` tool description had a dangling\n `→ then: pica_people_inspect` chain with no parenthetical reason hint,\n which the `composability-chains.test.ts` linter caught as a content\n bug. Description updated to `→ then: pica_people_inspect (see what\nthe cascade wrote)`. Fixed in `3a2843636` (test(mcp-server): fix 10\n pre-existing test failures across 8 suites).\n\n### Notes\n\n- Backwards-compatible minor bump. Three new tools, one widened\n description, no removals or signature changes.\n- Depends on `@withpica/mcp-sdk@^1.4.0` for the new\n `EnrichmentResource.listEnrichmentProposals` /\n `applyEnrichmentProposal` / `rejectEnrichmentProposal` methods.\n- Source additions landed across ADR-163 Phase 3d (`ff9cf265a`) and\n Phase 6 (`ff97faa56`).\n- Registry: https://www.npmjs.com/package/@withpica/mcp-server/v/2.10.0\n- Published alongside `@withpica/mcp-sdk@1.4.0` and\n `@withpica/mcp-server-business@1.3.0` in ADR-163 Phase 6.\n\n## [2.9.0] — 2026-04-11\n\n### Added\n\n- **ADR-164 audit follow-up: three new cascade MCP tools**\n - `pica_run_work_cascade(work_id)` — manually re-evaluate a work\n against every ADR-164 cascade rule and fire those whose\n preconditions are satisfied. Idempotent. Fire-and-forget. Backed by\n `POST /api/admin/works/:id/cascade-run`.\n - `pica_run_person_cascade(person_id)` — same for people. Fires\n `ipi_to_mlc_works` (MLC writer/publisher splits),\n `mbid_to_wikidata_crosswalk`, `isni_to_wikidata_crosswalk`,\n `wikidata_to_awards`, `wikidata_to_biography`, and\n `google_contact_suggest`. Backed by\n `POST /api/admin/people/:id/cascade-run`.\n - `pica_cascade_health` — snapshot of in-process cascade counters\n (ADR-164 Decision 5). Org-auth twin of the operator-only\n `/api/internal/cascade-health` endpoint. Returns per-rule failure\n counts bucketed by reason + outcome totals. Process-global, not\n persistent across serverless cold starts — treat as a spot-check.\n\n### Notes\n\n- Source additions landed in `38901f281` (ADR-164 audit follow-ups).\n Version bump + rebuilt dist + publish tagged in `edfbcb07b`.\n- Minor bump per semver — new tools, no removed or renamed surface.\n- Registry URL:\n https://www.npmjs.com/package/@withpica/mcp-server/v/2.9.0\n- Tarball verified post-publish by pulling\n `withpica-mcp-server-2.9.0.tgz` from the registry and grepping for\n all three new tool names in `package/dist/tools/enrichment.js`.\n\n## [2.8.0] — 2026-04-10\n\n### Changed\n\n- **ADR-162: subscription-based billing, credit gating disabled.**\n `withCreditGate` is now a pass-through — all tools are free for\n active subscribers. The MPP (Micropayment Protocol) machinery is\n retained in `@withpica/mcp-utils` for a future pay-per-credit\n re-enable but is dormant. Version bump carried in `7c4f5d24a`\n (`chore(adr-162): version bumps for npm publish`).\n\n## [2.7.0] — 2026-04-08\n\n### Added\n\n- **ADR-158c custody tool release.** Six `pica_custody_*` tools go\n live: claim, accept, decline, dispute, incoming list, history.\n Version bump in `91dd1c275` (`chore(adr-158c): version bumps for\ncustody tool release (Phase 6b)`).\n\n## [2.6.2] — pre-2026-04-08\n\n### Fixed\n\n- Stale version constant in the boot banner — the banner was still\n reporting an older version after an earlier bump. Fixed in\n `980dabc02` (`fix(mcp-server): correct stale version constant in\nboot banner (2.6.2)`).\n\n## [2.6.1] — pre-2026-04-08\n\n### Fixed\n\n- MCP server now emits `tools/list_changed` + `resources/list_changed`\n notifications after sign-in and sign-out, so clients refresh the\n tool list without a reconnect. Fixed in `f1ba2a211`.\n\n## [2.6.0] — 2026-04-07\n\n### Changed\n\n- **ADR-155 launch — publish 6 packages.** Catalog server rebaselined\n from the broken `3.0.0` publish (deprecated + unpublished from npm\n because `file:` deps had been baked into the tarball, leaving every\n fresh installer dead) to `2.6.0`. Five new sibling packages\n (`@withpica/mcp-sdk`, `@withpica/mcp-utils`,\n `@withpica/mcp-server-business`, `-enrichment`, `-settings`)\n published at `1.0.0` alongside with real semver deps so `npm\ninstall` actually resolves on user machines.\n- `connect.withpica.com` leads with the no-api-key lobby-mode flow.\n Landed in `e235aed40` (`feat(mcp): ADR-155 launch — publish 6\npackages, lobby-mode connect copy`).\n\n## Pre-2.6.0 — pre-changelog era\n\nEarlier versions (`2.0.0` through `2.5.x`) covered the pre-ADR-155\nmonolithic MCP server. Version history for that era is reconstructable\nvia `git log --follow -- mcp-server/package.json`. Notable milestones:\n\n- `2.5.x` — MCP Apps prebuild script + ext-apps devDependency added\n- `2.4.x` — build/publish polish, `.vercel/` excluded from tarball\n- `~2.0.0` — ADR-149 agentic hardening (write tiers, ProposedAction,\n confirmation, audit, annotations)\n\n[Unreleased]: https://github.com/withpica/pica/compare/edfbcb07b...HEAD\n[2.9.0]: https://github.com/withpica/pica/compare/7c4f5d24a...edfbcb07b\n[2.8.0]: https://github.com/withpica/pica/compare/91dd1c275...7c4f5d24a\n[2.7.0]: https://github.com/withpica/pica/compare/980dabc02...91dd1c275\n[2.6.2]: https://github.com/withpica/pica/compare/f1ba2a211...980dabc02\n[2.6.1]: https://github.com/withpica/pica/compare/e235aed40...f1ba2a211\n[2.6.0]: https://github.com/withpica/pica/commit/e235aed40\n";
3
+ export const CHANGELOG_MD = "# Changelog\n\nAll notable changes to `@withpica/mcp-server` will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n> **Rule of the road:** every version bump to this package MUST land with a\n> matching entry here in the same commit. See the project's \"npm publish\n> discipline\" memory entry for the enforcement rationale.\n\n## [Unreleased]\n\n## [2.57.0] - 2026-05-18\n\nCloses the ADR-241 substrate sprint — agent-side orientation skill, dashboard coherence with SQL-side `NOT EXISTS`, and 4 sister bug fixes that the agents themselves filed via `pica_report_issue` over the preceding 72 hours.\n\n### Added\n\n- **`first-session` skill (ADR-241).** Agent-side counterpart of `set-up-workspace`. Five phases: identity recognition → reporting-discipline opening note → context load → priority ranking + routing → close-out sweep. Names the right specialist skill per priority class and hands the steering wheel over — does NOT invoke the specialist itself. Discoverable via `pica_skill_list` + the `skill://withpica/first-session/SKILL.md` Resource per the SEP-2640 bridge.\n- **`SERVER_INSTRUCTIONS` coaching line.** Directs the agent to call `pica_skill_get(\"first-session\")` on the first user message of a session unless the prompt is already task-specific. Char budget bumped 2300 → 2400 to fit the addition; final length 2337.\n- **`pica_issue_agent_grant.scopes.items.enum`** — the 15 `VALID_SCOPES` are now declared inline in the JSON Schema, surfacing through `pica_tool_details` introspection. Closes ops_issue `3a65aa71` (agents trial-and-erroring on `write:works` / `write:credits` / `write:enrichment` which aren't valid; only `write:catalog` is).\n- **`pica_dashboard_attention` gains a `class` filter** taking one of `works_without_credits | works_without_registrations | audio_pending | unenriched_writers | recordings_without_splits | disputed_credits`. Specialist skills now have a single-call entry to the top-of-their-own-queue (ADR-242).\n- **`pica_count_explain` taxonomy mode** — omit `count_source` to get the full actionable-issue taxonomy as `sources[]` with `drill_down_skill` named per class. Machine-readable routing table that ADR-241's `first-session` skill reads to pick its next step.\n\n### Changed\n\n- **`pica_dashboard_briefing` / `_attention` / `pica_count_explain` are now coherent projections of a single shared source.** Implements ADR-242 § Decision: new `lib/services/dashboard-actionable.ts` (`getActionableIssues()` with a per-class registry); three projection helpers shape its output for the three tool handlers. `sum(count_explain.sources[].count) === briefing.critical_issues_total` for the same org/moment, by construction. Closes ops_issue `4042e806` (briefing 1495, count_explain 338, attention 0 — three tools, three numbers, no path through).\n- **`pica_works_query health_filter='needs_attention'` no longer errors.** Hardens `getWorksHealth()` with per-work try/catch; restores `needs_attention` routing in the assembled-truth path. Closes ops_issue `4da6a869`.\n- **`pica_split_sheet_generate` \"No credits found\" surfaces as 400, not 500.** Routes through the user-input-error classifier so agents see an actionable message instead of an opaque server error. Closes ops_issue `899a3d63`.\n- **`pica_submit_feedback` dedups by content-hash, not session-time.** Distinct content within the same session now passes; identical resubmissions still dedup within the rate-limit window. SDK errors propagate to `mcp_audit_log` via the error envelope (was silent generic error). Closes ops_issues `4bab716a` + `808e5fa0`.\n- **`pica_memory_save` accepts both kebab-case slugs and UUIDs.** Root cause: validator used `apiKey.keyId` (not a valid `user_id` FK) for the `user_id` field; row insert failed silently and surfaced as `\"invalid id format\"`. Closes ops_issue `315ef479`.\n\n### Dependencies\n\n- `@withpica/mcp-sdk` `^1.27.1` → `^1.28.0` (new `DashboardResource.actionableItems` + `CountExplainResource.taxonomy` methods).\n- `@withpica/mcp-utils` `^1.21.1` → `^1.22.0` (workspace-version-alignment fix; develop's Vercel deploy was failing since 2026-05-17 because the `^1.21.1` range that 2.56.1 introduced was not satisfied by the local `1.21.0` workspace, forcing CI/Vercel to pull a duplicate copy from npm registry and breaking type identity).\n\n### Database (staging applied; production applies on develop → main promote)\n\n- Migration `20260517220000_adr242_actionable_issues_rpcs.sql` — 4 Postgres functions (`dashboard_actionable_works_without_credits`, `..._works_without_registrations`, `..._recordings_without_splits`, `..._unenriched_writers`) using SQL-side `NOT EXISTS`. PICA builds for scale; the fetch-all + filter-in-JS pattern was rejected by the founder. All four `LANGUAGE sql STABLE SECURITY INVOKER SET search_path = ''` per the 2026-05-11 function-hardening sweep.\n\n## [2.56.1] - 2026-05-17\n\n### Changed\n\n- Brand consistency: \"PICA\" → \"withPICA\" in package metadata, keywords (added `\"withpica\"`, `\"music-catalog\"`, `\"music-rights\"`), README, JSDoc headers, and customer-visible tool descriptions: `pica_delete_my_account`, `pica_gdpr_export_my_data` (description + completion message), `pica_telegram_connect`, `pica_onboarding_complete` (description + `intent_notes` field), and the `new-catalog-setup` prompt.\n- Registered `pica_works_attest` and `pica_credits_send_for_attestation` in `REQUIRED_SCHEMAS_SOURCE` companion_calls (both tools declared workflow membership but weren't referenced — pre-existing drift caught by `lint:required-schemas`).\n\n### Fixed\n\n- **`pica_submit_feedback` + `pica_physical_assets_create` no longer leak SDK errors to the user (PRs #453 + #457, 2026-05-15).**\n Both executors had naked SDK calls — when the upstream API errored, the\n framework's outer catch in `tools/index.ts` JSON-stringified the error\n body straight to the conversation (`{error: \"UNKNOWN_ERROR\", message: \"...\"}`).\n Wrap each SDK call in `try/catch`: on throw, fire-and-forget\n `pica.opsIssues.reportIssue({ kind: \"tool_failure\", ... })` with the\n underlying message + status + parameter shape in `context`, return\n neutral text (`\"couldn't <verb> right now — the team has been alerted.\"`).\n Input-validation early-returns are preserved — those carry actionable\n text and aren't server failures. PR #457 added `tool_failure` to the\n `OpsIssueExplicitKind` taxonomy and retagged both wrappers (PR #453\n shipped as `kind: \"data_issue\"` because `tool_failure` didn't exist\n yet). 12 new unit tests across `feedback.test.ts` (new file) +\n `assets.test.ts`. **Note:** the auto-audit upsert path is bypassed\n because returning `isError: true` logs as `result_status: \"success\"`\n (`tools/index.ts:1859`) — the executor reports manually instead.\n\n### Added\n\n- **`pica_report_issue` accepts `kind: \"tool_failure\"` (PR #457, 2026-05-15).**\n Sixth value in the agent-explicit kinds enum. Lets agents file SDK /\n upstream-tool failures directly via the report-issue tool, mirroring\n the new fail-quiet wrappers.\n\n## [2.56.0] - 2026-05-14\n\n### Added\n\n- **`conflict_strategy` arg on `pica_import_execute` (PR #427, promoted to main via PR #428 on 2026-05-13).**\n New optional input on the import executor MCP tool. Enum `[\"error\", \"skip\"]`,\n defaults to `\"error\"` to preserve current bulk-batch behavior. `\"skip\"` falls\n back to per-row insert on Postgres 23505 unique-constraint collisions\n (duplicate `tunecode`/`iswc`), so a single duplicate no longer kills the\n entire batch — duplicates surface as warnings and the rest of the rows still\n land. Backward-compatible (existing callers without `conflict_strategy` get\n the default `\"error\"` behavior). Pairs with the underlying server-side\n satellite-write fix that also shipped in PR #427 (PRO-registration fields\n routed to `work_registrations` per ADR-125 WS5).\n\n## [2.55.0] - 2026-05-13\n\n### Added\n\n- **`pica_release_notes` tool + `release-notes://withpica/mcp-server/latest` Resource (PR #412, merged to develop 2026-05-13, promoted to main via PR #417).**\n Agent-facing surface for platform release notes. Reads `CHANGELOG.md`\n embedded at build time via `scripts/build-changelog.ts`. Returns the\n last 3 versions by default with optional `since_version` and `sections`\n filters. Resource counterpart serves the full CHANGELOG for\n Resource-native clients (SEP-2640 bridge pattern, consistent with\n ADR-140 Phase 2b). Disambiguated from catalog \"what's new\" phrasing\n by tool name (`release_notes` ≠ \"what's new\") + NOT-FOR disclaimer\n in description pointing catalog phrasing at `pica_dashboard_briefing` /\n `pica_works_query`.\n\n## [2.54.0] - 2026-05-13\n\n> Skipped `2.53.0` — that version was claimed by a parallel publish on\n> 2026-05-12 before this branch's publish chain ran. Sister of the\n> sdk's `1.26.0 → 1.27.0` skip in the same chain. See the\n> `feedback_npm_publish_chain_order` memory entry for the pattern.\n\n### Added\n\n- **`pica_import_analyze` / `pica_import_validate` / `pica_import_execute` accept `file_id` as an alternative to `file_content` (PR #415 → develop `2e74411bc`, PR #416 → main `3849c98e4`).**\n Closes the upload-then-import loop. After `pica_upload` →\n `pica_upload_complete`, agents can pass the resulting `documents.id`\n as `file_id` instead of pasting raw CSV content into a tool argument.\n Server resolves the bytes via a short-lived signed URL — org-scoped,\n CSV MIME-validated, 20 MB cap, UTF-8 validated. Requires\n `@withpica/mcp-sdk@^1.27.0` for the matching `ImportFileSource`\n type. Backwards-compatible: existing `file_content` callers\n unchanged.\n\n### Fixed\n\n- **Stale analyze-route assertions in `app/api/admin/import/__tests__/` flipped 500 → 400 (PR #396 era cleanup, bundled with the bridge).**\n Tests had been asserting the pre-PR-#396 500 status for parseCSV\n throws; route correctly returns 400 (caller-supplied bad input) since\n that fix. Loosened 4 `\"fileContent is required\"` exact-match\n assertions to `/fileContent or fileId/i` to match the new mutually-\n exclusive contract.\n\n## [2.52.2] - 2026-05-13\n\n### Changed\n\n- **Server-instructions polish — workspace deeplink hint after writes + paragraph trims (commits `5a2bca4a1`, `7a3e2c226`).**\n Added a one-line coaching that agents share `https://withpica.com/workspace?type=<entity>&id=<id>` after every write tool so users get a clickable receipt back to the workspace — the cheapest version of the \"chat ↔ workspace\" tie-in (ADR-234), no per-tool sweep, agents construct the URL from the entity ID already in every write response. Two trims funded the addition: the `pica_execute` collision disclaimer compressed to one sentence (~120 chars saved) and the peer-MCP paragraph dropped its inline URI-scheme inventory (`gmail://` etc.) in favour of pointing at `docs/mcp-source-uri-conventions.md`, while gaining a load-bearing sentence that citations persist verbatim and propagate to applied entities (ADR-178 — `field_proposals.sources` jsonb + on-apply propagation to `recordings.field_sources`). Token budget restored 2400 → 2300, final length 2192/2300, headroom 108 chars.\n\n## [2.52.1] - 2026-05-13\n\n### Fixed\n\n- **`pica_import_analyze` TypeError (`parsed.rows` → `parsed.preview`) (PR #408, shipped 2026-05-13).**\n Every successful analyze call returned `CSV analyze failed: Cannot read\nproperties of undefined (reading 'slice')`. Three-layer contract drift:\n the route returns `parsed: { headers, preview, totalRows, delimiter }`,\n the SDK type declared `parsed: { headers, rows, totalRows }` (wrong\n field, missing `delimiter`), and the MCP executor read `parsed.rows\n.slice(0, 3)`. The SDK's `request<T>()` JSON.parse-cast with no runtime\n validation let TypeScript compile the lie. Aligned executor to read\n `parsed.preview`; SDK type aligned in `@withpica/mcp-sdk@1.25.1`.\n\n## [2.52.0] - 2026-05-12\n\nCloses out the accumulated Unreleased buffer (some entries below shipped in\n2.49.0–2.51.0 but were never moved out of Unreleased; the `lint-changelog`\nscript that lands in the next bump prevents this drift going forward).\n\n### Added\n\n- **File-delivery tools `pica_file_deliver` + `pica_file_revoke_delivery` (PR #385, shipped 2026-05-12 in `@withpica/mcp-server@2.52.0`).**\n Agent-facing counterpart to the upload tools — symmetric with `pica_upload` /\n `pica_upload_file`. Wraps the first-class `/admin/files/deliver` surface\n (token + recipient_email + expiry + revocation) so agents can share files\n out of PICA with audit-trail accountability and a kill switch. Default\n expiry 48 hours; max 168 (one week). Registered in `discovery.uploads`\n (now bidirectional), `metadata.ts`, `recovery-hints.ts` (deliver →\n `rich_response`, revoke → `terminal`), and `lib/billing/tool-cost-model.data.ts`\n (deliver → export/EXPORT, revoke → admin/ADMIN). Backed by new\n `FilesResource` on `@withpica/mcp-sdk@1.25.0`.\n\n- **ADR-214 follow-up: cross-transport resource parity lint (`scripts/lint-resource-coverage.ts`).**\n Asserts that `ResourceRegistry.listResources()` (stdio) and `UI_RESOURCE_DEFS` / the\n anonymous-lobby handler (HTTP, `app/api/mcp/route.ts`) expose the same resource URIs.\n Catches the W2 drift class — resources added to one transport only — before publish.\n Four assertions: stdio-lobby ⊆ HTTP-lobby, HTTP-lobby ⊆ stdio-lobby,\n stdio-authenticated \\ ADR-152-carve-out ⊆ HTTP-authenticated, and the inverse\n HTTP-authenticated ⊆ stdio-authenticated. Wired into `prepublishOnly` (after\n `lint:agent-guide`) and `.github/workflows/mcp-tool-lint.yml`.\n\n **Pre-existing drift detected:** `pica://schemas/sync-placement-required` is present\n in `UI_RESOURCE_DEFS` (added in 2.47.0 per CHANGELOG) but absent from\n `ResourceRegistry.listResources()`. The lint correctly flags this; see the PR for\n the fix path.\n\n### Changed\n\n- **`metadata.test.ts` invariants tightened + counts re-baselined (PR #385).**\n Four long-standing failures resolved as part of the file-delivery sweep:\n (1) stale total-count assertion (175 → 242) reframed as a documented\n tripwire — drift means a tool was added without a `TOOL_METADATA` entry;\n (2) stale destructive-count assertion (12 → 17) — same shape, security-\n relevant because the destructive-tool dispatcher routes on `risk`;\n (3) `display_name` lowercase rule was over-strict — relaxed to \"first\n character lowercase\" so legitimate acronyms (S3, GDPR, ISNI, PICA, Azure,\n OAuth) pass per `.claude/rules/ui-components.md`'s proper-noun convention;\n (4) `pica_storage_disconnect` had `risk: \"destructive\"` + `retry_safe: true`\n in violation of the destructive-tool invariant — flipped `retry_safe` to\n `false`. Two-step confirmation token remains the actual safety mechanism;\n the tool's data-level idempotence claim stays true.\n\n- **Tool registry catch path now forwards `error_message` to the audit log (PR #308).**\n When a tool throws, the registry calls `formatError()` and now passes the\n parsed `message` through to `logToolExecution` as `error_message`. Pre-fix,\n every error row in `mcp_audit_log` landed with `error_message=null` because\n the wire shape stripped the field — even when the wrapper held the\n underlying cause. Net effect for diagnostics: rows like the 116 silent\n `pica_merge_duplicates` failures on 2026-04-09 (which couldn't be\n attributed to any specific cause) will now carry the message going forward.\n Sister change in `@withpica/mcp-utils` adds the field to `McpAuditEntry`.\n\n- **`pica_integrations_status` advertisement updated to current tools (PR #308).**\n ADR-179 (commit `dc1bfca72`, 2026-04-21) folded the six per-source\n `pica_enrich_*` tools into `pica_resolve_work` / `pica_resolve_person` /\n `pica_resolve_recording` with a `sources:[...]` parameter, then removed\n them. But `mcp-server/src/tools/integrations.ts` continued to advertise\n the removed names in the `platformReads` list, the tool description, and\n the summary prose. Agents reading the advertisement called names that no\n longer existed → UNKNOWN*ERROR loops on every catalog-enrichment ask\n routed through MLC/Spotify/MusicBrainz/YouTube/Discogs/ISNI. Now points\n at the surviving tools with the correct source value. Two regression\n tests in `integrations.test.ts` lock down that no removed\n `pica_enrich*\\*`tool name appears in the advertised`use_via` strings.\n\n## [2.48.0] - 2026-05-03\n\n### Changed\n\n- **Tool description scrub (PR #188).** Stripped internal-only ADR pointers and\n email-vendor names from user-visible tool descriptions across batch A\n (agreement-types, agreements, bulk, collaborators, credits), batch B\n (app-tools, feedback, projects, enrichment, recordings), and batch C.\n Replaced ADR-N references with the concept the ADR documented (e.g.\n \"ADR-198 round-trip\" → \"verify the credit persisted\") and removed\n Postmark from collaborator bulk-invite description and elicitation\n warning text. Tool descriptions surface to third-party agents and shouldn't\n reveal internal infrastructure choices.\n\n- **recovery_hints expansion (PR #188).** Annotation fix + additional\n recovery hints for tools that fan out across sections.\n\n- **`pica_releases_show` best-effort catch markers (ADR-224 convention).** Marked\n the two best-effort catches in `releases-rich.show()` (tracks + cover-art\n fallbacks) with `/* best-effort */` to match the ADR-224 Phase 4 lint\n convention. No behaviour change — the catches were already documented inline;\n this just makes the marker greppable so future scope extensions to `_show`\n tools recognise the intent. Surface audit confirmed all 9 `_inspect` tools\n addressed, 22 `_list` tools clean, no swallow patterns elsewhere.\n\n## [2.47.0] - 2026-05-02\n\n### Added\n\n- **ADR-222 W3 — sync placements MCP tool surface (6 tools).**\n - `pica_sync_placements_query` — list placements with filters (work_id, status, verification_status, brand, production_company, person_id, recording_id, source_license_enquiry_id, min_fee, currency).\n - `pica_sync_placements_inspect` — fetch one placement with linked recordings, sources, agreement, and parties.\n - `pica_sync_placements_create` — atomic create (placement + draft sync_license agreement + ≥1 agreement_party + recordings + evidence sources in a single Postgres transaction). Empty `contacts[]` rejects with structured `MISSING_CONTACT` (`next_tool: \"pica_people_query\"`). New people auto-created inline via `person_name` instead of `person_id`.\n - `pica_sync_placements_update` — patch placement fields. Operator-only when `verification_status='operator_verified'|'disputed'` or `confidentiality_level` changes (throws structured `OPERATOR_REQUIRED`); illegal status transitions throw `INVALID_TRANSITION`.\n - `pica_sync_placements_delete` — operator-only hard delete (two-step confirmation token). Customer agents receive structured `OPERATOR_REQUIRED` with `next_tool: \"pica_sync_placements_update\"` pointing at the soft-delete path (`status: 'terminated'`).\n - `pica_sync_placements_cite` — attach an evidence source; auto-recomputes `verification_status` (any non-attestation kind → `evidence_attached`).\n\n All 4 mutating tools wrapped with `withBillingGate`. Stdio path delegates to `pica.syncPlacements.*` (new `@withpica/mcp-sdk` resource). HTTP transport mirrors via the shared `ToolRegistry`. Paired with W4's REST routes at `/api/admin/sync-placements`.\n\n- **`pica://schemas/sync-placement-required` workflow schema resource (ADR-214).** Required + recommended fields for `pica_sync_placements_create` plus 4 companion call entries (inspect / update / cite / delete) and a worked example. Embeds the three `sync_placements` CHECK enums (`status` 5 values, `verification_status` 5 values, `confidentiality_level` 3 values) via the build-time generator + `schema-mirror.json` extension. Lives on both stdio (via the schema generator) and HTTP transport (`UI_RESOURCE_DEFS` in `app/api/mcp/route.ts`).\n\n- **`WorkflowTag` union expanded 15 → 16 values** (added `sync-placement-required`). All 6 sync-placement tools tagged with this workflow; `lint-required-schemas` enforces forward + inverse coverage.\n\n- **`schema-mirror.json` extended with `sync_placements` table** for status / verification_status / confidentiality_level CHECK enum embedding.\n\n- **6 cost-model entries in `lib/billing/tool-cost-model.ts`** (READ for query/inspect, WRITE for create/update/delete/cite). Unblocks ADR-180 lint cost-model coverage check; ADR-215 shadow-metering will record `billable_events` rows on these tools from first call.\n\n- **`sync_placements` discovery category** in `mcp-server/src/tools/discovery.ts` — layered-discovery agents (ChatGPT, Claude.ai connectors with `MCP_LAYERED_DISCOVERY=1`) can find the 6 tools via `pica_discover`.\n\n- **MCP scope mapping** for the 6 tools under existing `read:agreements` (query + inspect) and `write:agreements` (create + update + delete + cite). Bundled under the agreements scope rather than minting a new public scope for one feature — every placement is backed by a sync_license agreement.\n\n- **Four group-membership tools (ADR-223 Phase 5).** Customers can now\n manage group → member relationships on people directly via AI:\n - `pica_group_add_member` — add a person to a group person row.\n Server-side trigger enforces parent.is_group=true and same-org\n constraint; tool surfaces friendly errors at the route layer.\n Defaults: `role='member'`, `receive_notifications=true` (opt-out\n per membership). Wrapped in `withBillingGate`.\n - `pica_group_remove_member` — set `left_at` on the active row.\n Rows are never deleted; member history is preserved.\n - `pica_group_list_members` — active members by default;\n `include_inactive=true` for history.\n - `pica_person_list_groups` — inverse: every group a person is or\n was a member of.\n Role enum: `member`, `founder`, `lead`, `touring_member`,\n `session`, `guest`, `producer_in_residence`. Free-text `role_label`\n for variants outside the enum. Tools route through `mcp-sdk`\n `groups` resource → `/admin/groups/*` and\n `/admin/people/{id}/groups` HTTP routes.\n\n### Changed\n\n- **`@withpica/mcp-sdk` peer bumped to `^1.20.0`.** Required for the\n new `groups` and `syncPlacements` resources; older SDK versions lack\n `PicaClient.groups` and `PicaClient.syncPlacements`.\n\n### Notes\n\n- The 4 mutating sync-placement tools (`_create`, `_update`, `_delete`, `_cite`) need ADR-198 holdout contract specs in the sibling `Good-FM/pica-holdout-tests` repo. Coordinator follow-up — Path A from W3 Stage 1 audit §11.E.\n- The brief's references to a `mcp-server/src/__tests__/contract-baseline.json` file and a `lint:contract-baseline` script are out of date; both were removed in ADR-180 Phase 3 (the lint chain is now fully strict by default — `scripts/lint-mcp-tools.ts` runs as part of `prepublishOnly`). W3 reinterpreted Stage 4 as ADR-180 metadata + cost-model + taxonomy entries (all added) plus ADR-198 holdout contracts (sibling repo, follow-up).\n\n## [2.46.0] - 2026-05-02\n\n### Changed\n\n- **`pica_update_my_identity` now accepts `full_name`.** Customers can\n update the name on their PICA account via AI (e.g., fix typos from\n signup). Routes to `user_profiles.full_name`; rolls back via\n `revertMyIdentity` if the agent-action stamp insert fails. Tool\n description rewritten to lead with name capture. Closes the\n edit-symmetry gap surfaced during the SEV-1 sprint: previously the\n user could AI-rename their org but not their own name.\n\n- **`pica_update_organisation_profile` now accepts `name`.** Customers can\n rename their organisation via AI (e.g., fix signup typos, replace the\n default \"My Organization\" placeholder). Updates `organisations.name`\n directly; non-empty TRIM validation matches the DB-layer SEV-1 guard\n shipped earlier on 2026-05-01. Tool description updated to mention the\n typo-fix use case. Closes the placeholder-name lock-in trap surfaced\n during the SEV-1 onboarding-stuck-state cleanup.\n\n## [2.45.0] - 2026-05-01\n\n### Added\n\n- **ADR-214 Phase 3a — 3 new workflow schema resources.**\n - `pica://schemas/session-required` (studio session logging — `pica_sessions_create` primary; `pica_sessions_types` companion for session_type_id lookup; `pica_sessions_get` / `_list` for read).\n - `pica://schemas/split-sheet-required` (publishing royalty splits on works — `pica_split_sheet_generate` primary; `pica_split_sheet_send` / `_get` / `_list` companions).\n - `pica://schemas/recording-splits-required` (master ownership splits on recordings — `pica_recording_splits_create` primary with ADR-200 form-confirmation gate; `pica_recording_splits_verify` / `_list` companions).\n\n Each derives required + recommended fields from live tool input schemas at build time; `recording-splits-required` embeds the `split_type` and `role` CHECK enums (4 + 8 values respectively) from a hand-edited `schema-mirror.json` entry verified against prod project `fwgcmjhlwevdnxgqmkmh`.\n\n- **WorkflowTag union expanded 12 → 15 values** (added `session-required`, `split-sheet-required`, `recording-splits-required`). 11 tools migrated from `\"infrastructure\"` to their P3a workflow tag (4 sessions + 4 split-sheet + 3 recording-splits).\n\n- **Agent-guide expanded 6 → 14 sections** for authenticated mode:\n - 3 new write workflow sections (sessions, split-sheet, recording-splits) with canonical tool sequences and schema-URI footers.\n - 1 new identifier-assign narrative section explaining the inline-update pattern (`pica_*_update` accepts identifiers as inline fields including satellite-routed person identifiers — `isni`, `musicbrainz_id`, `wikidata_id`, `discogs_artist_id`, `deezer_artist_id` route to `person_enrichment` automatically; the surface is uniform).\n - 4 new read-workflow sections covering find-duplicates → merge, query → inspect → resolve gap-finding chain, lookup-person by industry identifier, and audit catalog completeness via dashboard tools.\n\n Authenticated guide now ~12,750 B (lobby variant unchanged ~855 B).\n\n- **`schema-mirror.json` extended with `recording_splits` table** for `split_type` + `role` CHECK enum embedding. `sessions.status` and `split_sheets.status` documented inline in schema `summary` fields rather than `enum_tables` because they are not DB-CHECK-enforced.\n\n- **2 new MCP prompts.**\n - `log-a-session` — guided studio session logging with optional `work_id` argument.\n - `set-recording-splits` — guided master ownership split assignment with ADR-200 propose-and-confirm + verify flow; takes optional `recording_id`.\n\n- **`_meta.schemas` dispatcher emit on workflow-tagged tool results.** New `attachSchemaHints` private method on `ToolRegistry` mirrors the existing `attachSessionState` pattern verbatim — same merge semantics, null-safe handling, fail-open behavior. Every tool whose `workflows` field references one or more schema URIs auto-emits `_meta.schemas: [\"pica://schemas/<workflow>-required\", ...]` on successful results. 47 workflow-tagged tools across 13 files automatically tagged via the dispatcher hook (no per-executor edits). `ToolResult._meta` interface widened to `{ session_state?: SessionState; schemas?: string[]; [key: string]: unknown }`. Cross-transport survival verified — both HTTP (`app/api/mcp/route.ts`) and stdio (`mcp-server/src/server.ts`) preserve `_meta` end-to-end.\n\n- **Cost-model entries for ADR-217 + ADR-218 tools** (`pica_notifications_recent` → READ, `pica_notification_acknowledge` → WRITE, `pica_storage_configure_start` + `pica_storage_disconnect` → ADMIN). Unblocks ADR-180 lint cost-model coverage check; ADR-215 shadow-metering now records `billable_events` rows for these tools.\n\n### Changed\n\n- **11 existing prompts updated to reference ADR-214 schema URIs** where the workflow shape is implicated: `analyze-catalog`, `find-duplicates`, `enrich-metadata`, `verify-works`, `assess-catalog-health`, `audit-credits`, `new-catalog-setup`, `close-the-loop`, `register-my-works`, `prepare-for-sync`, `workspace-autopilot`. Agents invoking a refreshed prompt pick up the relevant `pica://schemas/<workflow>-required` (and `pica://docs/agent-guide` where orientation helps) on first read.\n\n- **`pica_merge_duplicates.entity_type` now accepts both forms.** Previously the enum was singular (`\"work\" | \"person\"`) while `pica_find_duplicates` was plural (`\"works\" | \"people\"`) — a real footgun documented in ADR-214 P3a Stage 1 R4. Tool now accepts all four (`works` / `people` / `work` / `person`); canonical plural form (`works` / `people`) matches the rest of the catalog tools. Internally coerces to plural for the success message and to singular for the SDK call. Backwards-compatible — no existing caller breaks. Success message no longer renders the broken `work(s)` / `person(s)` artifact when callers pass the plural form. The R4 confirm-branch (two-step ADR-200 confirmation flow) also uses canonical coercion with a try/catch fallback to \"entities\" so unknown entity_types don't break the confirm UX.\n\n### Fixed\n\n- **`pica_recordings_by_work` drift cleanup.** Removed tool was still referenced in:\n - `mcp-server/src/prompts/index.ts` `verify-works` prompt body — swapped to `pica_recordings_query` with `work_id` filter (single-line drift fix).\n - `mcp-server/src/tools/recovery-hints.ts` `next_tool` annotation — swapped to `pica_recordings_query`.\n - `mcp-server/README.md` Recordings Management section — section refreshed to current 5 tools (`_query`, `_inspect`, `_create`, `_update`, `_delete`); count corrected 6 → 5. Larger README drift in works/people/etc. sections flagged as separate cleanup.\n - `@withpica/mcp-utils` `recovery-hints.ts` DUPLICATE_ISRC `next_tool` — same swap (mcp-utils@1.15.1).\n\n- **Source ↔ dist invariant restored** for `prompts/index.{js,d.ts,*.map}` (PR #173 source landed without committed dist regen — develop's dist had been missing `log-a-session` + `set-recording-splits`) and `tools/recovery-hints.{js,*.map}` (source was correct; dist was stale). No semantic change beyond what was already on develop; clears phantom local-tsc errors per `feedback_root_tsc_stale_mcp_dist`.\n\n### Dependencies\n\n- `@withpica/mcp-utils` `^1.14.0` → `^1.15.1` (recovery-hints `next_tool` fix).\n\n## [2.44.0] - 2026-04-30\n\n### Added\n\n- **ADR-214 Phase 2 — 6 new workflow schema resources.**\n - `pica://schemas/audio-upload-required` (3-step chain: presigned →\n complete → analyze + poll)\n - `pica://schemas/enrichment-resolve-required` (resolve fan-out →\n proposals_list → proposal_apply / reject)\n - `pica://schemas/agreement-required`\n - `pica://schemas/multimedia-required`\n - `pica://schemas/export-required`\n - `pica://schemas/claim-required`\n\n Each derives required + recommended fields from the live tool input\n schemas at build time and embeds CHECK enums from `schema-mirror.json`.\n Agent-guide expanded with 6 workflow sections (4 net-new, 2 rewrites\n with schema-URI footers); intro bumps \"five core\" → \"eleven core\" and\n \"~227 tools\" → \"~231 tools\".\n\n- **WorkflowTag union expanded to 12 values** (5 Phase 1 + 6 Phase 2 +\n `infrastructure`). 28 tools migrated from `\"infrastructure\"` to their\n Phase 2 workflow tag (4 audio-upload, 6 enrichment-resolve, 4\n agreement, 4 multimedia, 5 export, 5 claim).\n- **`schema-mirror.json` extended with 6 new tables** for Phase 2\n CHECK-constraint enum resolution (agreements, discovered_artists,\n discovered_credits, discovered_custody, enrichment_proposals,\n multimedia_items). Verified live against prod project\n `fwgcmjhlwevdnxgqmkmh`.\n- **HTTP transport coverage** — `app/api/mcp/route.ts` `UI_RESOURCE_DEFS`\n - `UI_RESOURCE_BODIES` extended with the 6 new schema URIs (matches\n the Phase 1 pattern from PR #152). Per\n `feedback_cross_transport_resource_coverage`.\n\n## [2.42.0] - 2026-04-30\n\n### Added\n\n- **ADR-218 Primitive B — `pica_notifications_recent` tool.** New read-only\n MCP tool (`risk: \"safe\"`, `retry_safe: true`) returning the cross-transport\n `discovery_events` feed for the calling org, ordered by `created_at` DESC\n with optional `unread_only: boolean` filter (per-surface dedup against\n `seen_in`). Default limit 20, max 100. Distinct from `pica_notifications_list`\n which targets the person-scoped `pica.notifications` system; this reads the\n org-wide ledger that web bell + telegram dispatcher also share.\n- **ADR-218 Primitive C — `pica_notification_acknowledge` tool.** New\n mutating tool (`risk: \"mutating\"`, `retry_safe: true`) that appends `'mcp'`\n to each event's `seen_in` array. Idempotent — re-acknowledging is a no-op.\n Org-scoped server-side: out-of-org ids are silently skipped. Empty\n `event_ids` returns a `VALIDATION_ERROR` without hitting the API.\n- \\*\\*Both tools registered in the existing `notifications` taxonomy bucket\n - TOOL*METADATA (`category: \"comms\"`)\\*\\* + tagged `workflows: \"infrastructure\"`\n per ADR-214 W4. Ride alongside the legacy `pica_notifications*_`and`pica*notify*_` families — the agent disambiguates from the descriptions.\n\n### Changed\n\n- **ADR-218 Primitive D — telegram dispatch dedup.** `telegramNotificationService.notifyEvent`\n now consults `discovery_events` for an existing undismissed row matching\n `(organisation_id, event_type, entity_id)` where `'mcp' = ANY(seen_in)`.\n When found, suppresses the entire dispatch — closes the re-nag loop for\n `until_resolved`-strategy alerts. Fresh `one_shot` events with no prior\n row still fire normally. Lookup is fail-soft: any DB error logs a debug\n and proceeds with dispatch (better an extra ping than a silently-dropped\n alert).\n- **ADR-218 Primitive A — `_meta.session_state` envelope gains optional\n `notifications` field.** `fetchSessionCounts` propagates the cross-transport\n unread summary from the catalog-stats response into the envelope. Missing\n field on older API servers leaves the envelope key off (no fabricated zero).\n\n### Bumped\n\n- `@withpica/mcp-sdk` peer to `^1.18.0` (`DiscoveriesResource.recent` +\n `.acknowledge` methods + `NotificationsSummary` type on `CatalogStats`).\n- `@withpica/mcp-utils` peer to `^1.14.0` (optional `notifications` field on\n `SessionStateCounts` + exported `NotificationsSummary` type).\n\n## [2.41.0] - 2026-04-30\n\n### Added\n\n- **ADR-210 P3 — `getAuthenticatedInstructions(slice)` + `getTrialEndingClause(slice)`\n exports in `src/server-instructions.ts`.** New helpers that optionally append\n a state-conditional trial-ending nudge to the authenticated handshake\n instructions. The clause fires only when `billing_state === 'trial'` AND\n `trial_days_remaining` is non-null AND `<= 3`; in all other cases the\n function returns the unchanged base const. Pass `null` when no slice is\n available — slice-less callers fail safe. Existing\n `SERVER_INSTRUCTIONS_AUTHENTICATED` const is unchanged (parity with\n `lib/mcp/server-instructions.ts` preserved).\n- **New `TrialNudgeSlice` interface export.** Minimal shape consumed by\n the helper: `{ billing_state: string; trial_days_remaining: number | null }`.\n Structurally compatible with the platform's `OrgBillingSlice` type so\n callers can pass either.\n\n### Note on stdio behaviour\n\nThe stdio binary in this release continues to call the equivalent of\n`getAuthenticatedInstructions(null)` at boot (returns the unchanged const) —\ntrial state is not resolvable at boot without a `pica.catalogStats()` round\ntrip. Stdio agents still see live `trial_days_remaining` via\n`_meta.session_state` on every write-tool result. A future phase may add\nboot-time slice resolution; this release ships the helper itself so the\nHTTP transport (`/api/mcp`) can use it immediately on a per-request basis.\n\n## [2.40.0] - 2026-04-30\n\n### Changed\n\n- **ADR-214 W4 — `workflows` field is now required on `ToolDefinition`.**\n Flips the optional `workflows?: WorkflowTag | WorkflowTag[]` field\n introduced in W1 to a required `workflows: WorkflowTag | WorkflowTag[]`.\n TypeScript compilation now enforces that every new tool authored\n declares its workflow membership at the source site — no escape\n hatch except the explicit `\"infrastructure\"` opt-out. Drift\n prevention mechanism #1 from ADR-214 §\"Drift prevention\" is now\n fully load-bearing. `lint-required-schemas.ts` hardened: the\n parallel-window warning for untagged tools becomes a hard error\n (defence-in-depth in case a tool somehow reaches the registry\n without a `workflows` field at runtime).\n\n### Added\n\n- **ADR-214 W2 — agent-guide + required-fields schema resources.**\n Two new resource families on the catalog `mcp-server`:\n - `pica://docs/agent-guide` — workflow narrative for agents. Visible\n in both lobby and authenticated modes; content branches on\n `lobbyMode`. Lobby variant (~865 bytes) covers the signup → magic\n link flow + what unlocks. Authenticated variant (~4.3 KB) lists the\n five core workflows (register a work, add a recording, add audio,\n add recording credits, enrich metadata) with verbatim tool sequences\n and 8 common gotchas — verified against the live tool registry on\n 2026-04-30.\n - `pica://schemas/work-required`, `pica://schemas/recording-required`,\n `pica://schemas/work-credits-required`,\n `pica://schemas/recording-credits-required`,\n `pica://schemas/person-required` — JSON contracts derived at build\n time from each tool's `inputSchema` (in `ToolRegistry`) joined with\n `schema-mirror.json` for live CHECK constraint enums. Authenticated\n mode only.\n- **Build-time generator + schema mirror.**\n - `mcp-server/scripts/build-required-schemas.ts` — runs as part of\n `npm run prebuild` (chained after `bundle-apps.ts`); reads\n `required-schemas.source.ts` + `ToolRegistry` + `schema-mirror.json`\n and emits the deterministic `required-schemas.generated.ts`\n (committed to git so PR diffs surface drift, per\n `feedback_type_regen_cumulative_drift`).\n - `mcp-server/src/resources/schema-mirror.json` — committed snapshot\n of CHECK constraint enums for `works`, `recordings`, `work_credits`,\n `recording_credits`, `audio_files`. Refresh via\n `mcp-server/scripts/refresh-schema-mirror.ts` (humans only; CI never\n auto-regenerates).\n- **Inverse-coverage CI lint (`scripts/lint-required-schemas.ts`).**\n Walks `ToolRegistry` and `REQUIRED_SCHEMAS_SOURCE` from both\n directions: every tool whose `workflows` field tags it for a workflow\n must appear in the source file; every source reference must resolve\n to a real tool. During the parallel-development window (W1 still in\n flight), tools missing the `workflows` field emit a single summary\n warning (per coordinator decision Stage 1 §R2). Once W4 makes the\n field required, the warning becomes an error.\n- **Agent-guide drift lint (`scripts/lint-agent-guide.ts`).** Greps\n every `pica_*` token in `agent-guide.ts` against `ToolRegistry` (in\n both `discoveryMode` settings, so meta-tools like `pica_discover` are\n resolvable). Catches stale references after tool renames.\n- **Meta-tests** for both lints (per `feedback_meta_test_load_bearing`):\n 3 / 3 regressions caught and reverted before ship — see\n `docs/follow-ups/2026-04-30-adr214-w2-meta-test-outcomes.md`.\n\n### Changed\n\n- `mcp-server/package.json` — `prebuild` now chains\n `bundle-apps.ts && build-required-schemas.ts`. New scripts\n `lint:required-schemas` and `lint:agent-guide` added; both wired into\n `prepublishOnly` after the existing checks.\n- `mcp-server/src/resources/index.ts` — registers 6 new URIs across\n `listResources()` (1 in the lobby branch, 5 in the authenticated\n branch) and `readResource()` (1 case for the agent-guide variant\n branch, 5 cases for the schema URIs).\n\n### Dependencies\n\n- `pg` + `@types/pg` added as devDependencies (used only by\n `refresh-schema-mirror.ts` for direct Postgres CHECK-constraint pulls\n against staging).\n\n### Internal\n\n- **ADR-214 W1 — `WorkflowTag` type + optional `workflows` field on tool\n definitions.** Adds a union type\n (`\"work-required\" | \"recording-required\" | \"work-credits-required\"\n| \"recording-credits-required\" | \"person-required\" | \"infrastructure\"`)\n and a `workflows?: WorkflowTag | WorkflowTag[]` field to\n `ToolDefinition` at `mcp-server/src/tools/index.ts`. All 231 tools now\n carry the field — 8 catalog-core tools (`pica_works_create`,\n `pica_works_update`, `pica_recordings_create`,\n `pica_recordings_update`, `pica_people_create`, `pica_people_update`,\n `pica_credits_update`, `pica_recording_credits_update`) reference one\n or more Phase 1 workflows; the remaining 223 carry\n `\"infrastructure\"`. Field is optional in W1 to keep the rollout\n additive; W4 (post-merge of W1 + W2 resource scaffolding) flips it to\n required so every future tool is forced to declare its workflow at\n compile time. No runtime behaviour change in this release.\n\n## [2.39.0] - 2026-04-30\n\n### Added\n\n- **ADR-211 Phase 1 — `pica_signup_start` unauthenticated tool.** New\n agent-discoverable signup verb available without a connection key on\n both stdio (lobby mode) and HTTP `/api/mcp` (anonymous mode). Mints\n nothing locally — every invocation calls\n `POST /api/public/onboarding/signup-start` so the\n `ONBOARDING_TOKEN_SECRET` signing secret stays on the backend, never\n in customer-distributed binaries. Returns a 15-minute JWT-bound\n `/onboard/<token>` URL via `resource_link` (universal floor) +\n capability-gated `elicitation/create url` (mode: \"url\"). Constructor\n takes `{apiUrl, transport, clientId?}` — stdio binary stamps\n `transport: \"stdio\"`, the HTTP carve-out stamps `transport: \"http\"`\n and threads through any DCR `client_id` for OAuth resume.\n\n- **`SERVER_INSTRUCTIONS_UNAUTHENTICATED` lobby variant.** Short\n ~600-char handshake text pointing the agent at the 3 lobby tools\n (`pica_signup_start`, `pica_sign_in`, `pica_sign_out`) instead of the\n full 200+ catalog surface. Selected at boot when `lobbyMode === true`\n (stdio binary without `PICA_API_KEY`) and at handshake when\n `/api/mcp` is invoked without a Bearer token. Catalog-tool guidance\n omitted because no catalog tools are reachable in lobby mode.\n\n- **`SERVER_INSTRUCTIONS_AUTHENTICATED` alias** of the legacy\n `SERVER_INSTRUCTIONS` export — the unaliased symbol stays exported\n unchanged for backward compatibility.\n\n### Changed\n\n- **Lobby surface is now THREE tools** (was two): `pica_signup_start`\n joins the existing `pica_sign_in` + `pica_sign_out` pair. Additive,\n not replacement — Phase 1 evaluates consolidation in Phase 2 once\n the `/onboard/<token>` page is live and the JWT-bound flow is the\n preferred path. ADR-211 § Primitive A editorial amendment 2026-04-30\n reflects this.\n\n### Notes\n\n- **`ONBOARDING_TOKEN_SECRET` env var required** on backend\n environments (preview + prod already provisioned 2026-04-30). The\n `lib/auth/scoped-jwt.ts` substrate gained an additive\n `options.secretEnvVar` parameter so each scoped-JWT consumer\n (upload-token, onboarding-token, future ADR-214 storage-config) can\n rotate its signing secret independently. SUPABASE_JWT_SECRET still\n serves as the local-dev fallback in both modes.\n\n- **No new exports in `@withpica/mcp-utils` or `@withpica/mcp-sdk`** —\n Phase 1 consumes existing exports (`clientSupportsUrlElicitation`,\n `CallerContext`) only. Per\n `feedback_workspace_package_publish_discipline.md`: no bumps needed\n upstream of this release.\n\n## [2.38.0] - 2026-04-30\n\n### Added\n\n- **ADR-208 Phase 3 Primitive D — `pica_release_show` rich-render tool.**\n The catalog's first MCP tool returning `image` + `text` content blocks\n in a single agent turn. Cover art ships as a base64 JPEG ≤512px;\n markdown summary covers title, year, primary artists, label name, UPC,\n catalog number, and tracklist with ISRCs and durations. Read-only\n (`readOnlyHint: true`). Registered in\n `mcp-server/src/tools/discovery.ts` `CATEGORIES.releases.tools` in\n the same commit as the `ToolRegistry` registration per the layered-\n discovery completeness rule.\n- **`_meta.ui.resourceUri = \"ui://pica/release\"`** — MCP Apps clients\n (Claude Desktop, Cursor) render the iframe via the new resource at\n `mcp-server/src/apps/release.ts`. Phase 3 ships the resource stub\n (title + markdown + cover image binding); full interactive iframe\n with track-list expand and inline streaming embeds is queued under\n the ADR-200 Phase 1.x backlog.\n- **`structuredContent`** envelope — `{ title, markdown, cover_base64,\ncover_mime_type, resource_link_uri }`. Apps clients prefer this over\n re-decoding the image content block; non-Apps clients ignore it.\n\n### Notes\n\n- **Universal floor is `image + text` only in Phase 3.** A `resource_link`\n block is intentionally omitted because no release UI page exists in\n the codebase yet (verified — neither `/portal/releases/[id]` nor\n `/admin/releases/[id]`). Building one is queued under\n `docs/follow-ups/2026-04-30-adr208-phase3-5-release-detail-page.md`\n and ADR-208 § Primitive D was editorially amended on develop\n (`30ceefc9d`) to reflect the deferral.\n- **\"Key credits\" deferred from the markdown body.** The existing\n `releasesService.listTracks()` join surfaces work + recording artist\n but not `work_credits`; adding the join widens Phase 3 scope. Will\n land alongside ADR-213 when credit-attribution surfaces consume the\n data cheaply.\n- **Sharp lives in the main Next.js app, not in this stdio binary.**\n Cover-art bytes come from the new `/api/admin/releases/[id]/cover-art-thumbnail`\n endpoint that does the resize + cache server-side, so the\n customer-distributed `@withpica/mcp-server` install stays free of\n sharp's ~50MB platform-specific native binaries.\n\n### Changed\n\n- **Bumps `@withpica/mcp-sdk` peer to ^1.17.0** to consume the new\n `ReleasesResource.getCoverArtThumbnail()` method.\n `@withpica/mcp-utils` stays at ^1.12.0 (T2.4's bump absorbed via the rebase).\n\n## [2.37.0] - 2026-04-30\n\n### Added\n\n- **ADR-210 Phase 2 — `pica_subscription_status` and `pica_subscription_manage`.**\n Two new tools shipping the explicit billing read + action surface\n that complements Phase 1's ambient `_meta.session_state.billing_slice`.\n - `pica_subscription_status` (`readOnlyHint: true`) wraps the\n existing `GET /api/admin/subscription` route and flattens it into\n the 9-field shape ADR-210 § Phase 2 specifies (`billing_state`,\n `trial_days_remaining`, `trial_ends_at`, `current_tier`,\n `capacity_used`, `capacity_limit`, `capacity_pct`,\n `recommended_tier`, `summary`). The `summary` line is a\n server-side template the agent uses verbatim — predictable\n wording, less variance across connectors.\n - `pica_subscription_manage` (`readOnlyHint: false`) is a single-verb\n dispatcher over the existing `POST /api/admin/subscription`\n (subscribe / upgrade) and `POST /api/admin/subscription/portal`\n (manage / cancel) routes. Returns `{url, expires_at, surface}`.\n Subscribe / upgrade without `tier` returns a recoverable error\n with `next_tool: pica_subscription_status` so the agent can\n chain to read `recommended_tier` first rather than auto-pick.\n Universal-floor `resource_link` content block ships on every\n success response per ADR-200 Phase 1; `elicitation/create url`\n fires only when `clientSupportsUrlElicitation(server)` (the\n capability gate is mandatory because `elicitInput` with\n `mode: \"url\"` throws synchronously against non-supporters per\n `feedback_mcp_sdk_capability_gates_elicitation.md`).\n- **`subscription` category in `discovery.ts:CATEGORIES`** (\"view your\n billing state, manage your subscription, and pick a tier\"). Lint\n enforced by `scripts/lint-mcp-tools.ts` per\n `feedback_mcp_taxonomy_completeness.md`.\n\n### Changed\n\n- **Bumps `@withpica/mcp-sdk` peer to ^1.16.0** to consume the new\n `SubscriptionResource`. `@withpica/mcp-utils` stays at ^1.12.0\n (T2.4's bump absorbed via the rebase).\n\n## [2.36.0] - 2026-04-30\n\n### Added\n\n- **ADR-213 Primitive A — `pica_recordings_create` post-create attribution hints.**\n Every successful create call now appends up to three Important-severity\n hints via the new `buildRecordingAttributionHints(recording)` helper\n (`mcp-server/src/tools/recording-attribution-hints.ts`). Mirror of\n `buildCustodyHints` for works:\n - `recording_ownership_unset` — fires when `ownership_percentage IS NULL`.\n Suggests `pica_recordings_update ownership_percentage:N`.\n - `recording_no_credits` — always fires (we never know credits from a\n single fresh row). Suggests the new `pica_recording_credits_update`.\n - `recording_master_unclaimed` — fires when `ownership_percentage IS NULL`.\n Alternative path for multi-party master claims via `pica_custody_claim`.\n NULL-only triggers: `0` is \"explicit zero\", no hint. Negative-path\n covered by jest at `recording-attribution-hints.test.ts` per\n `feedback_meta_test_load_bearing.md`.\n- **ADR-213 Primitive B — `pica_recording_credits_update`.** First-party\n recording-side write tool; closes the work/recording credit-write\n asymmetry. Writes to `recording_credits` (NOT the trade-secret\n enrichment-cascade-fed `credits` table — see `.claude/rules/ip-protection.md`).\n Uses the 16-role `RECORDING_CREDIT_ROLES` enum (`MainArtist`,\n `FeaturedArtist`, `Producer`, `Mixer`, `Engineer`, ... `Other`).\n Songwriting credits (Writer, Composer, Lyricist, Arranger as a publishing\n role) continue to route through `pica_credits_update` on the parent work.\n Registered in `discovery.ts` `CATEGORIES.credits` in the same commit per\n `feedback_mcp_taxonomy_completeness.md`. Listed under `write:catalog` scope\n in `lib/services/mcp-scopes.ts`. `nextSteps` points at\n `pica_recordings_inspect sections:[\"recording_credits\"]` for ADR-198\n round-trip verification.\n- **ADR-213 Primitive A.1 — `pica_recordings_inspect recording_credits`\n section.** Additive (not replacement). The existing `credits` section\n (work-side credits via parent work) keeps its current behaviour. New\n `recording_credits` section reads first-party operator-authored credits\n directly from the `recording_credits` table via the new\n `pica.recordingCredits.list()` SDK method.\n- **`TOOL_METADATA` entry for `pica_recording_credits_update`** in\n `mcp-server/src/tools/metadata.ts` (catalog/mutating/non-retry-safe).\n\n### Changed\n\n- **Bumps `@withpica/mcp-sdk` peer to ^1.15.0** and `@withpica/mcp-utils` to\n ^1.12.0 to consume the new `RecordingCreditsResource` and the metadata\n entry shipped alongside ADR-213.\n- **Tool count moves from 224 → 225** with the addition of\n `pica_recording_credits_update`.\n\n## [2.35.0] - 2026-04-29\n\n### Added\n\n- **ADR-208 Phase 2 — `pica_upload` returns a JWT-bound `/upload/<token>` URL.**\n The executor now calls `pica.uploads.createSession()` for server-side\n mint of a 600s-TTL HS256 JWT scoped to the caller's org / user /\n bucket-key / acceptFilter. Universal floor (`resource_link`) and\n capability-gated `elicitation/create url` shapes unchanged — only the\n URL flips from `${webBase}/workspace` to `${webBase}/upload/<jwt>`.\n Tool description updated; obsolete Phase 1.5 forward-reference removed.\n\n### Changed\n\n- **`session_state.pending_uploads` now reads from\n `organisations.pending_uploads_count`** (atomic +1 on JWT mint via\n `/api/admin/uploads/sessions`, atomic -1 on JWT-path completion via\n `/api/upload/[token]`). Phase 1's stub at `0` is gone. Atomic semantics\n via the `inc_pending_uploads` SECURITY DEFINER RPC; `GREATEST(0, ...)`\n clamp prevents negative drift. Sits alongside T1.2's billing fields on\n the same `_meta.session_state` envelope — no shared edit to\n `mcp-server-shared/mcp-utils/src/session-state.ts`.\n\n### Notes\n\n- Fail-soft: if `createSession()` throws (network blip, route 5xx), the\n executor falls back to the legacy workspace URL and surfaces the error\n in the `text_summary`. The card still works for MCP Apps clients via\n `_meta.ui.resourceUri` regardless.\n\n### Bumped\n\n- `@withpica/mcp-sdk` dependency range bumped to `^1.14.0`\n (`UploadsResource`, `CreateUploadSession*` types,\n `CatalogStats.pending_uploads_count` now consumed).\n- `@withpica/mcp-utils` dependency range bumped to `^1.11.0`\n (T1.2's billing-fields extension on `SessionStateCounts`).\n- `mcp-server/server.json` registry manifest version bumped to `2.35.0`\n in lockstep with the npm package.\n\n## [2.34.0] - 2026-04-29\n\n### Added\n\n- **ADR-210 Phase 1 — billing slice on `_meta.session_state`.** The\n `fetchSessionCounts` private in `ToolRegistry` now resolves the four\n billing fields (`billing_state`, `trial_days_remaining`, `current_tier`,\n `capacity_pct`) from `pica.catalogStats().billing_slice` alongside the\n existing counts. `attachSessionState` flows them onto every successful\n write-tool result through the same `_meta.session_state` envelope (no\n new emission path — extends the existing one) so the agent sees ambient\n billing posture between mutations without a `pica_subscription_status`\n round-trip. Phase 2 will land that explicit read tool; Phase 1 ships\n the substrate the tool reads from.\n- Same fail-soft posture as the existing fetcher: when `this.pica` is\n missing (HTTP-discovery without bearer scope), or when the SDK response\n is missing `billing_slice` (older server pre-Phase-1), the fetcher\n emits a conservative `{ billing_state: \"trial\", trial_days_remaining:\nnull, current_tier: null, capacity_pct: 0 }` rather than fabricating\n \"active\" — the agent never sees misleading \"active\" billing for an\n uninitialized context.\n\n### Bumped\n\n- `@withpica/mcp-sdk` dependency range bumped to `^1.13.0`\n (`CatalogStats.billing_slice` field now consumed).\n- `@withpica/mcp-utils` dependency range bumped to `^1.11.0`\n (`SessionStateCounts` shape extended with `BillingSlice` fields).\n- `mcp-server/server.json` registry manifest version bumped to `2.34.0`\n in lockstep with the npm package.\n\n## [2.33.0] - 2026-04-29\n\n### Added\n\n- **ADR-208 Primitive B — `_meta.session_state` attached to write-tool results.**\n The central `ToolRegistry.executeTool` wrapper now composes the six-key\n session-state envelope (`works_count`, `recordings_count`,\n `completeness_pct`, `mutations_this_session`, `since_last_briefing`,\n `pending_uploads`) for every tool whose risk is `mutating` or\n `destructive` (`readOnlyHint: false`), and attaches it under\n `result._meta.session_state`. Read tools (`risk: safe`) skip this\n entirely so the high-volume read path stays cheap; failed mutations\n (`isError: true`) also skip because catalog state didn't change.\n `pica_dashboard_briefing` running successfully resets the\n `since_last_briefing` counter — handled in the wrapper, not the tool.\n Cache key is org-scoped via `config.picaApiKey` (stdio) or\n `callerContext.callerIdentity` (HTTP); two orgs sharing a worker\n process never share state. Fail-open: any error in session-state\n composition is swallowed and the result returns without `_meta.session_state`.\n See `@withpica/mcp-utils@1.10.0` for the underlying `buildSessionState`\n helper and the load-bearing cross-org isolation regression test.\n\n### Changed\n\n- Bump `@withpica/mcp-utils` dep range to `^1.10.0` to pick up the\n `buildSessionState` / `incrementSessionMutations` /\n `resetSinceLastBriefing` exports that compose Primitive B.\n\n## [2.32.0] - 2026-04-28\n\n### Changed\n\n- Bump `@withpica/mcp-utils` dep range to `^1.9.0`. The previously-pinned `^1.8.0`\n resolved (via the npm registry) to a tarball that pre-dated the addition of\n `clientSupportsUrlElicitation` and `elicitBulkConfirmation` to the source — Vercel\n builds where the lockfile resolved from registry instead of the local workspace\n link failed with `TS2305`. 1.9.0 republishes the same source state with both\n exports present, so registry-pinned lockfiles now build cleanly without needing\n the workspace-link override.\n\n## [2.31.0] - 2026-04-28\n\n### Added\n\n- **ADR-200 Phase 1 — `ToolExecutorContext` plumbed through the registry.**\n `ToolExecutor` now takes an optional second arg `(args, ctx?)` carrying the\n per-request `Server` reference. `server.ts` passes `{ server }` through to\n `executeTool`; the discovery dispatcher (`pica_execute`) forwards it to its\n delegate. Existing executors with the legacy `(args)` signature keep working\n unchanged — only tools that need `server.elicitInput()` opt into the second\n arg. Pre-existing destructive-confirmation gate (two-step token) is\n preserved.\n- **`pica_upload` portable across non-MCP-Apps clients.** Response now ships\n with a `resource_link` content block (universal MCP floor) alongside the\n legacy text envelope and `_meta.ui.resourceUri` — Apps clients render the\n iframe unchanged, ChatGPT / Gemini / Claude Code / curl-style clients see a\n clickable link to the workspace upload page. Clients that advertised\n `capabilities.elicitation.url` additionally receive a server-issued\n `elicitation/create url` consent prompt; the call is gated on the new\n `clientSupportsUrlElicitation` helper from `@withpica/mcp-utils@1.8.0` so\n callers without the capability never see the SDK's synchronous\n \"Client does not support url elicitation\" throw. `elicitationId` is a\n per-call UUID. Universal floor remains usable when the user declines or the\n elicitation times out — the resource_link in the response is the fallback.\n- **`pica_download` ships a `resource_link` for the signed file URL.** Same\n universal-floor improvement on the download surface — text envelope still\n carries the JSON shape ADR-152 cards expect, plus the new resource_link\n exposes the URL/filename/mime to clients that render link blocks.\n- **ADR-200 Phase 1 — form-confirmation gate on the 4 customer-MCP Class D\n bulk tools** (`pica_works_bulk_update`, `pica_people_bulk_update_roles`,\n `pica_recording_splits_create`, `pica_collaborators_invite_bulk`). Each\n now calls `elicitBulkConfirmation` from `@withpica/mcp-utils@1.8.0`\n after the validation + dry_run paths but before persisting. The gate\n fires only when the connected client advertises\n `capabilities.elicitation`, and in that case the destructive write only\n proceeds if the form returns `accept` with `confirm: true`. Universal\n floor: clients without elicitation continue to execute as before\n (existing destructive-token gate, where applicable, remains\n authoritative). 11 new tests cover decline, accept-without-confirm,\n no-caps fallback, and dry_run-skips-elicitation across the four tools.\n `team_comms_send` (5th Class D tool) is gated in\n `@withpica/team-mcp-server@1.3.0`.\n- **`ToolResult.content` widened to permit `resource_link` blocks.** Legacy\n `Array<{ type, text }>` shape kept compatible via a structural union; tools\n that only return text need no changes.\n\n### Changed\n\n- **Tool descriptions for `pica_upload` / `pica_download` updated** to point\n at the ADR-200 fallback ladder rather than the prose \"tell the user to use\n the workspace dashboard\" hint that ADR-152 originally shipped. Behaviour\n for MCP Apps clients is unchanged.\n\n### Removed\n\n- **9 nested `withCreditGate(...)` wrappers unwrapped** across `tools/audio-files.ts` (2), `tools/exports.ts` (3), and `tools/enrichment.ts` (4). Each always ran inside a `withBillingGate(...)`; the inner wrapper was a no-op shim retained since ADR-162 disabled credit gating. Unwrapping leaves the subscription check as the sole gate on these tools, which matches the billing model.\n- **`tests/utils/credit-gate-mpp.test.ts` + `credit-gate-mpp-paths.test.ts` deleted.** Both suites exercised a disabled MPP + pay-per-credit path that no longer has any production call-sites. `tests/tools/metadata.test.ts` also drops its `credit-gated tools should have credits_required set` assertion — redundant now that `credits_required` is gone from the shared `@withpica/mcp-utils` type (companion entry in that package's CHANGELOG). `tests/tools/credits.test.ts` stale `describe(\"pica_credits_balance\")` block (and associated `mockCreditsBalance` setup) removed — that tool was pulled from the surface 2026-04-22 but the tests were missed in that pass.\n- **`src/__mocks__/mppx-server.ts` + `mppx-mcp-sdk-server.ts` deleted** and the matching `moduleNameMapper` entries removed from `jest.config.js`. Both mocks existed only to stub out `mppx` for the now-deleted MPP unit tests. The `testPathIgnorePatterns` entry pointing at `credit-gate-mpp-paths.test.ts` is also removed (ghost reference to the deleted file).\n- **\"credit-gated\" prose stripped from tool descriptions** in `tools/app-tools.ts` (`pica_car_preview` description + carPreview reuse comment) and `tools/documents.ts` (`pica_documents_analyse` description). These strings were advertised in the tool description, telling agents a tool was \"credit-gated (5 credits)\" when it's actually subscription-gated at workspace level.\n- **`mppx` runtime dep still listed in `package.json`** — left in place to avoid lockfile churn; no `src/` consumer remains after this commit. Next publisher should drop it and rerun `npm install` to clean the lockfile.\n\n## [2.30.0] - 2026-04-27\n\n### Added\n\n- **`pica_audio_inspect` basic section surfaces 4 previously-invisible\n columns** — `recording_id`, `stem_label`, `version_label`, and\n `classification`. All four are real columns on `audio_files` written by\n `pica_audio_complete_upload`. The 5th audit-flagged field\n (`content_type`) is mapped to `audio_format` at write time and was\n already surfaced. Closes a Phase 2 gap from the 2026-04-27 read-write\n parity audit. SDK type `AudioFile` extended with the same three\n optional fields (classification was already there).\n- **`pica_organisation_profile` includes `org_type`** — paired read tool's\n underlying `/admin/settings/organisation-profile` SELECT now returns\n the CHECK-enum value that `pica_update_organisation_profile` already\n accepted (publisher / label / pro / sync_library / client / venue /\n distributor / other). Same class as the settings/identity fan-out\n fixed in 2.29.0 — write side accepted, read side truncated.\n- **`pica_physical_assets_inspect` adds a `links` section** — surfaces\n the typed-edge rows that `pica_physical_assets_link_work` and\n `pica_physical_assets_link_recording` write to `work_production_assets`\n and `recording_production_assets`. Pre-fix the link rows were\n write-only from the MCP surface even though both\n `/admin/assets/[id]/{work,recording}-links` GET endpoints already\n existed. SDK gains `assets.listWorkLinks(id)` and\n `assets.listRecordingLinks(id)`.\n- **`dry_run` flag on three more Class D mutating tools** —\n `pica_recording_splits_create`, `pica_collaborators_invite_bulk`,\n and `team_comms_send`. Completes the Class D coverage started in the\n ADR-199 5a part 1 commit (`a10006e5b`). Each tool early-returns\n `{ dry_run: true, would_affect, sample / target_count }` after\n validation and before the mutating SDK call, so agents can preview\n bulk effects and external-comms dispatch before committing. For\n `team_comms_send`, the preview echoes recipient and length-only\n metadata; the message body is not surfaced to keep ops messaging\n off the dry-run trace.\n\n### Fixed\n\n- **`pica_recordings_inspect` no longer hallucinates into the void on 404.**\n ADR-198 verification 2026-04-26 found the inspect tool was returning 200\n with `recording_error: \"API request failed: 404 ...\"` for every missing\n entity / missing route handler. Agents read this as a successful empty\n result and proceeded to call downstream sections (credits, audio) that\n also 404'd silently — no Sentry alert, no audit row, no user-visible\n error. Fix: basic-section catch now re-throws `EntityNotFoundError`\n (new typed export from `@withpica/mcp-sdk` 1.12.0+), so 404 surfaces\n as a hard `isError: true` envelope. Non-404 errors on the basic fetch\n still get absorbed into `recording_error` (preserves the partial-result\n pattern for transient failures).\n\n## [2.29.0] - 2026-04-25\n\n### Fixed\n\n- **94 previously-undiscoverable tools retrofitted into the layered-discovery\n taxonomy.** Same bug class that bit four times in three weeks\n (`pica_upload`/`pica_download` since ADR-152, `pica_submit_feedback` since\n ADR-184, `pica_report_issue`/`pica_my_reported_issues` from ADR-196 Phase 3):\n registered in `ToolRegistry` but absent from `CATEGORIES` in\n `mcp-server/src/tools/discovery.ts`, so layered-discovery agents (default\n for ChatGPT and Claude.ai connectors with `MCP_LAYERED_DISCOVERY=1`) could\n not find them via `pica_discover`. The 2026-04-25 hardening that added\n blocking `checkTaxonomyCompleteness` to `scripts/lint-mcp-tools.ts`\n surfaced 94 grandfathered violators in the baseline. This release retrofits\n every one. Fourteen new categories — `agreements`, `collaborators`,\n `custody`, `physical_assets`, `recording_splits`, `royalties_statements`,\n `share_links`, `split_sheets`, `licensing`, `notifications`, `messaging`,\n `agent_identity`, `telegram`, `labels` — and the tools fold into existing\n ones (`releases`, `analytics`, `enrichment`, `import`, `projects`,\n `profile`) where they belong. `scripts/mcp-tool-lint-baseline.json\n→ missing_taxonomy` is now empty.\n- **`pica_upload` and `pica_download` newly reachable via `pica_discover`** —\n the two generic harness cards (ADR-152) had been silently absent from the\n `CATEGORIES` taxonomy since they shipped. `pica_upload` added to the\n existing `uploads` category alongside the programmatic `pica_upload_file` +\n `pica_upload_complete` pair. `pica_download` added to the `export` category\n since it's the delivery side of any export-tool flow.\n\n### Changed\n\n- **`CATEGORIES` is now exported** from `mcp-server/src/tools/discovery.ts`\n so `scripts/lint-mcp-tools.ts` can read it. Compile-time only; no\n consumer change.\n\n## [2.28.1] - 2026-04-25\n\n### Fixed\n\n- **`pica_report_issue`, `pica_my_reported_issues`, and `pica_submit_feedback`\n were unreachable via `pica_discover`** — the layered-discovery taxonomy\n in `mcp-server/src/tools/discovery.ts` did not list them in any of its\n 26 categories, so agents using the layered flow (default for ChatGPT\n and Claude.ai connectors that need to keep their context window\n manageable) literally couldn't find these tools. Real-world failure\n caught 2026-04-25: a Claude Desktop session dogfooding the issue-\n reporting flow returned \"no feedback or support tool exposed in the\n PICA MCP\" and suggested `pica_notes_create` as the closest match —\n the exact failure mode `pica_report_issue` was designed to catch\n (which it couldn't, because it wasn't discoverable). New `feedback`\n category added to the discovery taxonomy listing all three tools.\n `pica_submit_feedback` had been silently invisible since ADR-184\n shipped — same bug class, same fix.\n\n### Changed\n\n- **`pica_report_issue` description tightened** to instruct the agent\n on WHEN to call: PROACTIVELY without being asked when the agent itself\n hits a workflow gap, AND on-demand when the user says \"this is broken\"\n / \"this didn't work\". Previously the description was descriptive\n (\"file a structured issue when…\") which left agents reading it as a\n passive option rather than a recommended habit. Also adds a\n cross-reference to `pica_my_reported_issues` for the resolution-poll\n side of the closed loop.\n\n## [2.28.0] - 2026-04-24\n\n### Added\n\n- **ADR-196 Phase 4a — `pica_my_reported_issues` tool.** Org-scoped\n customer-side polling tool that closes the loop on `pica_report_issue`.\n Lets the agent answer \"did anyone fix that thing I reported?\" without\n going through the operator surface. Returns the issue, current status,\n resolution_note, and occurrence_count for each issue the calling org\n has reported or been impacted by. Default sort most-recently-touched\n first; optional `status` filter (open / triaged / investigating /\n resolved / wont_fix). Tool metadata: `category=comms`, `risk=safe`,\n `retry_safe=true`. Pairs with `@withpica/mcp-sdk@1.12.0` for the new\n `OpsIssuesResource.listMine()` method.\n\n### Changed\n\n- **`mcp-server/src/config.ts` VERSION constant is now derived from\n `package.json`** via `createRequire(import.meta.url)(\"../package.json\")`,\n not a hardcoded literal. Drift-proof — future bumps no longer require\n manual sync between the two files. The version-sync lint in\n `scripts/lint-mcp-tools.ts` now accepts both forms (literal still\n blocks on drift; derived is always valid). Motivated by two\n consecutive publishes (2.27.0 + 2.28.0) being blocked by the stale\n literal — the trap is now permanently sealed.\n\n### Fixed\n\n- **`mcp-server/src/tools/discovery.ts` no longer references\n `metadata.credits_required`** — the property was removed from\n `ToolMetadata` in the chore/drop-mcp-credit-gating cleanup (per\n ADR-162: PICA is subscription-only) but two stale references in\n `discovery.ts` slipped through, blocking the publish until fixed.\n No tool carries the field anymore so the conditional spread was\n dead code; replaced with a comment recording the history. The\n comment itself is removed in chore/drop-mcp-credit-gating\n (this PR) — credit gating is gone for good.\n\n### Changed\n\n- **ADR-199 Week 1 — `withBillingGate` extended to every write-tool\n surface.** Previously the gate only covered `audio-files.ts`,\n `exports.ts`, and `enrichment.ts` (8 tools). Now wraps 38 write\n executors across 9 tool families: `agreements` (4), `agreement-types`\n (5 — `renderTemplate` deliberately ungated as it's a pure read),\n `custody` (4), `people` (3), `works` (5), `recordings` (3), `credits`\n (1), `assets` (7 — `assetExport` deliberately ungated to match\n `pica_export_catalog_csv`), and `dashboard` claim/review tools (4).\n Read tools (query / list / inspect / history / search / stats /\n pulse / briefing) intentionally not wrapped. Behaviour change for\n agents on hibernated workspaces: write tools that previously executed\n now return the lobby error. Operation labels in the lobby message\n use domain terms (\"agreement creation\", \"physical asset link\",\n \"custody claim\", \"discovery review\", etc.). The gate itself reads\n from `organisations.billing_state` via the new effective-state route\n (see `[Unreleased]` in `@withpica/mcp-utils`); `is_internal=true`\n organisations bypass the gate. Rollback path is the\n `ADR199_READ_BILLING_FROM_ORG` env var on the Vercel app — flipping\n to `false` reverts the read source to `user_profiles.billing_state`\n without an MCP redeploy.\n- **ADR-199 Week 1 language sweep — agent-facing copy moves to domain\n terms.** \"Your organisation\" / \"this organisation\" / \"your org\"\n swept to \"your catalog\" (where the noun is the music data) or \"your\n account\" (where no domain term fits) across `audit`, `collaborators`,\n `custody`, `dashboard`, `directory`, `memory`, `metadata`,\n `my-reported-issues`, `releases`, and `settings` tool descriptions.\n Internal identifiers (`pica_organisation_profile`,\n `pica_update_organisation_profile`, `org_type` parameter, the\n `\"organisation\"` memory-visibility enum value) deliberately\n preserved — those are wire-protocol or schema names, not copy.\n Industry term \"Performing rights organisation\" preserved (it's a\n PRO, not a withPICA org). Display names in `metadata.ts`\n (`view organisation profile` / `update your organisation profile`)\n swept to `view account profile` / `update your account profile`.\n\n## [2.27.0] - 2026-04-24\n\n### Added\n\n- **ADR-196 Phase 3 — `pica_report_issue` tool.** Lets an agent file a\n structured issue when a workflow breaks in a way raw tool failures can't\n capture (`workflow_gap` / `inconsistent_result` / `missing_step` /\n `data_issue` / `ux_confusion`). Auto-dedupes via the v2 signature\n (sha256 of `\"v2|{kind}|{canonicalised_summary}\"`), so two reports of\n the same problem with different wording collapse into one\n `ops_issues` row. Operators triage from the same record. Raw tool\n errors continue to auto-populate `ops_issues` via the `mcp-audit.ts`\n upsert path — agents should NOT call `pica_report_issue` for those\n (it would create a duplicate). Tool metadata: `category=comms`,\n `risk=mutating`, `retry_safe=true`. Pairs with\n `@withpica/mcp-sdk@1.11.0` and `@withpica/mcp-utils@1.7.0` published\n in the same cycle.\n\n### Fixed\n\n- **`config.ts` VERSION constant bumped to 2.27.0** to match the\n `package.json` version. The `version-sync` lint in\n `scripts/lint-mcp-tools.ts` blocked the initial 2.27.0 publish until\n this was corrected — caught a pre-existing trap where the banner\n version is hardcoded in source rather than derived from `package.json`\n at build time. Future bumps must update both files; consider\n auto-deriving in a follow-up.\n- **`pica_report_issue` tool — drop double-unwrap of SDK response.**\n `OpsIssuesResource.reportIssue()` now returns the unwrapped payload\n (mcp-sdk@1.11.0 tightened the return type), so the tool's previous\n `result?.data || result` fallback was dead code that didn't\n typecheck. Now `const data = result;` directly.\n\n## [2.26.0] - 2026-04-22\n\nVersion leapfrogs 2.25.0 (which was published to npm without a matching commit / changelog entry in this repo, discovered during this publish cycle). 2.26.0 ships from a clean main at commit `a3c8ca870` with the full bundle below. Pairs with `@withpica/mcp-sdk@1.10.0` and `@withpica/mcp-utils@1.6.0`, both published the same day.\n\n### Removed\n\n- **Billing-credit tools removed from the MCP surface:** `pica_credits_balance` (credits.ts), `pica_credits_history` (settings.ts), `pica_credits_purchase` (purchases.ts tombstoned to an empty class). See `docs/MCP_REFINEMENT_LOG.md` entry B-001. withPICA is subscription-only at £9.99/mo; surfacing a credit-balance + credit-history + credit-purchase tool trio contradicted the billing model and misled agents (caught 2026-04-22 when an agent transcript opened with \"998,894 credits — plenty. Running the export now.\"). The underlying SDK methods (`creditsBalance.*`, `settings.creditsHistory`) and `lib/services/credits/**` infra remain intact — only the MCP tool surface shrinks. `pica_credits_list` and `pica_credits_update` are **kept**: they're work_credits (songwriter roles + splits on a work), not billing credits.\n- **`CREDIT_INSUFFICIENT` recovery hints pointing at `pica_credits_balance`** removed from `recovery-hints.ts` for `pica_resolve_work`, `pica_export_song_registration`, `pica_export_catalog_asset_report`, `pica_audio_analyze`. Paired tests under `__tests__/tools/recovery-hints.test.ts` + `settings.test.ts` updated to assert the new shape.\n\n### Changed\n\n- **Credit-gating language stripped from tool descriptions** — `pica_audio_identify` (\"Costs 3 pica credits on match…\"), `pica_export_song_registration` (\"Costs 1 pica credit.\"), `pica_export_industry_ready` (same), `pica_export_catalog_asset_report` (\"Costs 5 pica credits…\"), and the 3 `pica_resolve_*` tools in `enrichment.ts` (\"Costs 1 pica credit per call.\"). The `withCreditGate` / `withBillingGate` runtime wrappers are **left in place** — only the agent-facing prompt-gating copy goes. Same B-001 refinement entry.\n- **Server instructions** (`src/server-instructions.ts`, mirrored in `lib/mcp/server-instructions.ts` via the parity test) open with a one-line disambiguation from `@picahq/mcp` (Pica AI / picaos.com) — a different product whose short name collides with ours. Helps agents that have both connectors installed (or users who pasted their withPICA key into the wrong config) recognise which server they're actually talking to. See the picaos name-collision memory rule.\n- **`pica_catalog_diligence` now returns structured JSON** instead of failing with a JSON-parse error on binary ZIP bytes. The fix lives in `@withpica/mcp-sdk`'s `AnalyticsResource.catalogDiligence()` — the SDK now requests `?format=json`. See the mcp-sdk CHANGELOG for detail. MCP refinement log: \"Singleton — `pica_catalog_diligence` returns ZIP parsed as JSON\".\n\n### Fixed\n\n- **ADR-174 Phase 2c — inverse phantom in `pica_works_update` (works slice).** Three jsonb compliance fields (`ai_disclosure`, `provenance_attestation`, `training_rights`) are satellite-routed to `work_licensing` via `WORK_SATELLITE_FIELDS` and accepted by both the HTTP route allow-list and the service layer, but were missing from `WORK_WRITE_PROPERTIES`. Agents following the `pica_works_update with ai_disclosure: ...` completion hint at works.ts:577 were hitting schema-level silent-drop (or strict-validator 400s). Added all three properties to the write schema with shapes copy-pasted from the parallel fields on `pica_recordings_update` (recordings.ts:193). Tool description updated to distinguish audio-trait satellite fields (still not exposed) from the three compliance satellite fields (now exposed). Full audit of the other 22 customer-MCP write tools yielded zero further inverse phantoms — see `docs/audits/2026-04-21-mcp-inverse-phantom-audit.md`.\n\n### Added\n\n- **ADR-189 Phase 4 slice 3: `pica_claim_artist` MCP tool.** INSTANT path for artist-claim on discovery-backed evidence. Wraps `artistClaimingService.processClaimDecision` to reuse the existing `work_claims.artist_claim_status` / `claimed_by_person_id` / `claim_confirmed_at` update path + `performer` work_credits insert. Refuses (409 `ADMIN_REVIEW_IN_PROGRESS`) when an open admin `artist_claims` row exists for the same (work, person) — returns `admin_review_id` in the body so the agent surface can route the user to resolve it. Rate-limited to 20/hour per user via the shared `claim_write` bucket. Wrapped in `withAgentActionStamp` when grant-authed — rollback captures pre-write `work_claims` row + tracks whether a new performer credit was inserted (deleted on compensation) or pre-existed (left alone). **Schema drift carryover:** the plan proposed capturing rollback state from 4 `works` columns, but live staging (`rtxcxazevrgcjnudvggf`) keeps the artist-claim lifecycle columns (`artist_claim_status`, `claimed_by_person_id`, `claim_confirmed_at`) on the `work_claims` satellite — only `primary_artist_id` lives on `works`. Service captures + restores from `work_claims` accordingly. The live `artist_claims.claim_status` CHECK constraint has no `under_review` state (only `pending | approved | rejected | withdrawn`), so the open-review gate checks `claim_status = 'pending'` only.\n\n### Removed\n\n- **ADR-154 F13: seven deprecated per-source enrich tools removed.** `pica_enrich_work_{mlc,musicbrainz,discogs,spotify,youtube}` and `pica_people_enrich_{isni,musicbrainz}` (tombstoned since ADR-179 Phase 1/2, 2026-04-17) are no longer registered — every call has returned a `-32070 TOOL_DEPRECATED` error for a full minor cycle, ending the one-minor deprecation window per ADR-179 Decision 2. Callers must use `pica_resolve_work(sources: [...])` or `pica_resolve_person(sources: [...])` instead; the `tools/list`, `metadata`, `recovery-hints`, and category-`discovery` surfaces shed the seven stale entries in this release. Downstream impact: clients that hardcoded the tool names now get `tools/list`-level absence rather than a deprecation envelope — fail-fast instead of fail-with-suggestion.\n\n### Changed\n\n- **ADR-154 F14: completion-hint sweep for the seven removed tools.** Updated every `→ then:` and hint-string reference that pointed at the F13 tombstones across `enrichment.ts`, `people.ts` (3 sites), `collaborators.ts`, `works.ts` (2 sites), `search.ts`, `server-instructions.ts`, `prompts/index.ts` (3 sites), and `resources/llms-primer.ts`. Agents discovering tools via descriptions will no longer be trained toward dead tool names. The ADR-179 \"Replaces the five/two per-source tools\" phrasing is gone from the resolver descriptions too — resolvers stand on their own now.\n- **ADR-180 Phase 3: full TOOL_METADATA coverage.** 29 tools retrofitted in `mcp-server/src/tools/metadata.ts` across eight family-scoped commits — resolve (3), cascade (3), enrichment proposals (4), collaborators (4), notify-user scheduling (3), physical-assets links (4), misc singletons (5), and the ADR-185 Part 1 agent-identity drift (3). `scripts/mcp-tool-lint-baseline.json` is deleted; MCP Tool Lint now runs in fully-strict mode. No behaviour change — tool discovery, audit categorisation, and risk-tier gating now classify the same 29 tools they couldn't classify before. `credits_required` deliberately omitted from new entries (credit gating is a no-op pass-through since ADR-162). Retry-safety follows ADR-180's `risk × retry_safe` table — e.g. `pica_enrichment_proposal_apply` is `retry_safe: false` (writes to entity columns), `_reject` is `retry_safe: true` (content-hash suppression is set-once). ADR-180 flipped from `Proposed` to `Accepted`.\n- **ADR-193 Surfaces 1+3: peer-connector coaching + URI source conventions (server-instructions addendum).** Handshake copy coaches agents to check peer MCPs (email / drive / notes / calendar / DAW) before asking users to paste or type data, and to cite findings via `pica_enrichment_propose` `sources[].url` using URI schemes — `gmail://` `gdrive://` `notion://` `file://` `telegram://` `calendar://` `daw://` `user://` `web://`. See `docs/mcp-source-uri-conventions.md` in the main repo for shapes. First concrete build for ADR-190 Principles 2 + 3 (Agent-Mediated Source Discovery). A latent HTTP-transport gap was fixed in the same develop commit (`63eef17f8`) — `/api/mcp/route.ts` was not wiring `SERVER_INSTRUCTIONS` into its Server constructor, so remote agentic clients (ChatGPT Apps, Claude Desktop remote, Cursor) saw zero coaching. The stdio transport in this package was always serving instructions correctly; only the remote transport was affected.\n\n### Added\n\n- **ADR-193 Surface 2: `gap_hints` envelope on 4 read tools.** `pica_works_inspect`, `pica_agreements_inspect`, `pica_people_inspect`, and `pica_enrichment_proposals_list` now emit an optional `gap_hints[]` field on `structuredContent` when a real gap is present. Each hint is capability-named (ADR-190 Principle 2 — `email_search` / `drive_search` / `filesystem_search` / `notes_search` / `calendar_search` / `web_search`, never vendor names), carries a concrete `query_shape`, and pre-fills the `then_call: \"pica_enrichment_propose\"` with the exact `then_args_shape` the agent should emit back (including URI-citation scaffolding from Surface 3). Gated by `MCP_GAP_HINTS_ENABLED=1` — off by default in prod. Empty array / omitted envelope when there's no real gap. Flat additive — the existing `CompletionHint` pipeline on `works_inspect` is untouched. Bundled: `enrich-metadata` prompt references the peer-connector pattern and points the agent at `gap_hints`.\n- **ADR-193 Surface 4: `pica_enrichment_propose` accepts `proposal_action: \"create\"`.** Closes the reserved-but-unwired create path from ADR-178 Phase 1. The tool schema now accepts `entity_type: \"recording\" | \"agreement\" | \"person\"` paired with `parent_entity_type` + `parent_entity_id` for create proposals. Apply-path branches on `rule_id === \"agent_research\"` and routes to `recordingsService.create` (parent required; `work_id` linkage), `agreementsService.create` (optional work parent, linked via `agreementWorksService.addWork` after create), or `peopleAdminService.create` (standalone — people have no parent FK). Recording creates seed `field_sources` verbatim from `proposal.sources[].url`, preserving URI schemes (gmail://, gdrive://, notion://, file://, telegram://, user://, web://) per ADR-193 AC 5. Agreements + people don't carry `field_sources` on the main table today; provenance URIs are captured in `resolution_note` until a follow-up migration adds the column. Work + publisher creation remain explicitly out of scope (dedup-critical — deferred to future ADR). Migration `20260422_01_adr193_proposal_parent_fields` adds nullable `parent_entity_type` + `parent_entity_id` columns with a CHECK pair + partial index for the review-queue scan. Legacy `artist_title_to_youtube` create rule is untouched (it continues to overload `entity_id` as the parent work id). 4 new service-layer tests green; total proposal-service suite 42/42.\n- **ADR-185 Part 1: three new session-auth-only tools.** `pica_create_agent_identity`, `pica_issue_agent_grant`, `pica_list_my_agent_grants`. Back a user-issued agent-identity + scoped-grant primitive — the substrate for Parts 2 (settings UI) and 3 (per-write provenance stamping). All three require `write:agent_identity` scope AND session-auth (raw API key / OAuth); the HTTP MCP dispatcher refuses `pica_grant_` callers with a structured `reason: \"session_auth_required\"` error before execution per AC 12. Subject is always the authenticated user — caller-supplied `user_id` is dropped per ADR-184 rule 2 / ADR-185 rule 1. Grant tokens use the format `pica_grant_<64 hex>` and are hashed at rest with HMAC-SHA256 + `API_KEY_HASH_PEPPER` (same scheme as api_keys per ADR-185 line 193 + ADR-167 D-5).\n- **ADR-185 Part 2: two new session-auth-only tools.** `pica_revoke_agent_grant` (DELETE `/admin/agent-grants/:id`, idempotent, 404 masks ownership failures) and `pica_get_agent_activity` (GET `/admin/agent-activity`, paginated, optionally filtered by identity or grant). Both appended to `SESSION_AUTH_ONLY_TOOLS` in the HTTP MCP dispatcher and to the `write:agent_identity` scope bucket. Together with the Part 1 trio this completes the five-tool agent-identity surface the ADR Scope requires. Revocation takes effect on the next request (AC: within 60s — `resolveGrantToken` checks `revoked_at` on every call, no cache layer).\n- **ADR-185 Part 3 passes 1-5: agent-action provenance stamping wraps 27 write-tool families.** Part 3 layers two complementary wrappers over existing write tools so every per-grant write records a row in `mcp_agent_actions` for audit + revoke-replay. `withAgentActionStamp` (compensation-after): handler runs, stamps; on stamp failure, compensation undoes the write via captured prior state — used for creates and updates (soft-delete families get meaningful delete compensation — flip `is_deleted` back). `withAgentActionStampFirst` (stamp-first, pass 4): stamp commits BEFORE the destructive op; stamp-ok + handler-fail logs a \"ghost stamp\" at error level — used for hard-delete families where compensation is impossible. Both wrappers are no-ops when the caller is not an agent grant (session-auth / raw API key writes are unaffected). Families covered across the five passes: works/recordings/people/agreements/releases/notes creates; notes_delete; sessions_create; share_links_create; projects_create; multimedia_create; recording_splits_create; works_update; recordings_update; people_update; agreements_update; projects_update; notes_update; releases_update; people_delete; publishers_create; the six hard-delete families (works/recordings/agreements/projects/sessions/releases) via the stamp-first variant; and pass 5's `pica_projects_attach_works` (project_works insert wrapped, GET + POST migrated from `requireAuth` + `getUserProfile` to `withOrgContext` for consistency). `pica_sessions_update` remains deferred — action-branching route (start/complete/cancel + participant add/remove + regular update) needs a dedicated design slice before wrapping.\n- **New tool** `pica_submit_feedback`: agent-native feedback submission. Routes bug_report→devops, feature_request→ceo, question→comms, other→category-mapped. Requires `write:feedback` scope. Subject is always the authenticated user per ADR-184 rule 2. (ADR-184 slice 8 — landed on develop 2026-04-19 post-2.23.0 publish.)\n- **ADR-189 Phase 3: two new identity-capture tools.** `pica_update_my_identity` (stage_name / IPI / ISNI / IPN / PRO) and `pica_update_organisation_profile` (org_type / display_name / tagline / ipi_number). Both admin-scoped, both `retry_safe: true` (idempotent upserts — re-applying the same IPI leaves the row in the same state). Subject derived from auth (no `user_id` / `organisation_id` parameters — ADR-184 rule 2). After the identity write, `pica_update_my_identity` re-runs cross-org discovery and returns the count of newly-visible credits / custody / artist-link rows so the agent can surface \"found N more — claim them?\" in the same conversation turn. Rate-limited at 20 writes/hour/user via `checkActionRateLimit` (R1 mitigation). Admin routes (`POST /api/admin/my-identity`, `POST /api/admin/organisation-profile`) wrap in `withAgentActionStamp` when the caller presents an agent grant (ADR-185 Part 3) — UPDATE compensation captures pre-write state via read-before-write and PATCHes the row back on stamp failure, or deletes a lazy-created person row.\n- **ADR-189 Phase 4 Task 1: `pica_claim_credit`.** New activation-loop tool that drains a `discovered_credits` row into a `work_credits` row in the calling org, giving the user `view` access to the linked work. Check-and-set on `discovered_credits.status` prevents double-claims in concurrent sessions. Rate-limited to 20/hour per user via `checkActionRateLimit`. Returns `is_first_claim: true` on first-ever claim by the user (derived from `agent_action_log` stamp count). Wraps in `withAgentActionStamp` for grant callers — compensating transaction calls `revertClaimCredit` (flips discovery back to `pending` + deletes the `work_credits` row) if the stamp INSERT fails. Error taxonomy: `DISCOVERY_NOT_FOUND` (404), `DISCOVERY_ALREADY_RESOLVED` (409), `EVIDENCE_REVOKED` (410), `RATE_LIMITED` (429 + `Retry-After`). `pica_claim_credit` added to `ADMIN_ONLY_TOOLS` in `mcp-scopes.ts`; metadata entry `category: \"discovery\", risk: \"mutating\", retry_safe: false`. Route: `POST /api/admin/discoveries/[id]/claim-credit`. SDK method: `pica.discoveries.claimCredit(id)`.\n- **ADR-189 Phase 4 Task 2: `pica_claim_custody` + +72h auto-approve worker.** Drains a `discovered_custody` row into a pending `custody_claims` row (status=`pending`, `chain`=custody_type, `custody_source`=`claimed`, provenance in `evidence.source`=`\"auto-discovered-via-email\"`). Schedules a silent-consent auto-approve by inserting a `scheduled_notifications` row (`source=pica_claim_custody`, `deliver_at`=+72h, message=`custody_auto_approve:<uuid>`). Does NOT mutate `works.{composition,master}_custodian_org_id` immediately — the 1-minute cron fires `scheduledNotificationsService.drainDue()` which now dispatches `source=pica_claim_custody` rows to a new `handleCustodyAutoApprove` branch that runs the **Delta 1 stale-promotion guard**: UPDATE `works` custodian columns ONLY IF the snapshot captured at claim time (`expected_previous_custodian_org_id` + `expected_custody_source` + `custody_side` — migration `20260421_01_custody_claims_expected_previous`) still matches; otherwise flip the claim to `superseded` (new status) and leave the catalog untouched. Error taxonomy identical to `pica_claim_credit`. `pica_claim_custody` was already in `ADMIN_ONLY_TOOLS` since Phase 4 Task 0; this ships the actual wiring. Route: `POST /api/admin/discoveries/[id]/claim-custody`. SDK method: `pica.discoveries.claimCustody(id)`. Stamp compensation via `revertClaimCustody` flips discovery back to pending, cancels the scheduled_notification, deletes the custody_claims row.\n\n## [2.24.0] - 2026-04-21\n\n### Fixed\n\n- **`pica_integrations_status` no longer tells users to \"connect Spotify\".** Two real-user failures on Claude Desktop (2026-04-21) traced back to the tool lumping platform-level Spotify/YouTube (PICA has its own credentials; no per-user OAuth exists or has ever existed) into the same \"Available to connect\" list as genuine user-OAuth peer connectors (Google/Notion/Airtable/Telegram). Failure modes observed: (1) user pasted a Spotify track URL → agent replied \"head to your Pica dashboard and add Spotify as an integration\"; (2) user asked \"what songs do I have in pica\" with a catalog holding 1 work → agent replied \"you currently have no connections set up in Pica — so there are no songs or any other data accessible.\" Reshape: the tool now returns `peerConnectors` (the 4 actual OAuth services) separately from `platformReads` (Spotify, YouTube, MusicBrainz, MLC, ISNI, Discogs, with the tool name for each). Summary leads with \"PICA catalog is ALWAYS accessible via pica_works_query, pica_people_query, pica_dashboard_briefing, pica_search_all — no setup required.\" The dead `connectedProviders.includes(\"spotify\")` check that could never evaluate true was removed.\n- **Server instructions: catalog-is-always-accessible guidance.** Handshake now explicitly states (a) the catalog is always accessible via the read tools with zero setup, (b) `pica_integrations_status` showing \"0 connected\" refers to optional peer connectors, NOT the catalog — call `pica_works_query` to check, (c) Spotify/YouTube URLs go through `pica_import_streaming_link` / `pica_import_youtube_link` directly; no per-user Spotify/YouTube OAuth exists to set up, do not tell the user to \"connect Spotify in your dashboard\". Replaces earlier copy that left the agent free to hallucinate a dashboard-integration flow. `lib/mcp/server-instructions.ts` parity copy updated in lockstep; the HTTP transport at `/api/mcp` picks up the new text on next handshake without requiring a redeploy of this package. Under the 2000-char token budget at 1833 chars.\n\n## [2.23.0] - 2026-04-19\n\n### Added\n\n- **ADR-181 Phase 1: `pica_audit_list` ported from `@withpica/mcp-server-settings`\n (ADR-154 F6).** Closes the one trailing-gap tool from the source-merge audit —\n every other tool the three sub-servers exposed was already registered by\n `mcp-server`'s superset. Registered in `lib/services/mcp-scopes.ts`\n `ADMIN_ONLY_TOOLS` alongside the team / org-profile admin operations; the\n `mcp_audit_log` read is org-scoped and matches the existing admin posture\n for `pica_organisation_profile` / `pica_team_list`. Landed in `54ae935d9`\n via PR #50.\n- **ADR-181 Phase 1: bundle-size CI gate per Decision 2.** New\n `scripts/check-mcp-bundle.ts` walks `mcp-server/dist/`, sums byte size\n (excluding source maps), and fails if total > 210 MB (70% × Vercel's\n 300 MB serverless-function cap). Runs on every push / PR that touches\n `mcp-server/**`, `mcp-server-shared/**`, the script, or the workflow\n itself (`.github/workflows/mcp-bundle-size.yml`). `package.json`\n `prepublishOnly` invokes it locally so a bloated bundle can't ship out\n of a developer machine. Current measurement on this branch:\n 0.79 MB / 210 MB limit (0.38% of cap). Landed in `558315069` via PR #50.\n\n## [2.22.0] - 2026-04-18\n\n### Added\n\n- **ADR-174 Phase 2 item 7 follow-up: `pica_projects_attach_works` (stdio).**\n Closes the `work_ids` FIELD_NOT_WIRED gap on `pica_projects_create` /\n `_update`. Pre-slice the MCP tools advertised `work_ids` but the admin\n route silently dropped it — the route redirect message already pointed\n agents at `POST /api/admin/projects/[id]/works`, but no MCP tool\n exposed that path. The new tool accepts\n `{ project_id, works: [{ work_id, project_day?, notes? }...] }` and\n attaches each item via `ProjectsResource.attachWork` with per-item\n result reporting (`attached[]`, `skipped[]` for already-linked,\n `failed[]` for other errors). Registered in `lib/services/mcp-scopes.ts`\n under `write:catalog`.\n\n### Changed\n\n- **ADR-174 Phase 2 item 22: `pica_publishers_create` reshaped.** Pre-slice\n the schema exposed only `{ name, ipi }` (2 fields) and the SDK's\n `PublishersResource.create` hit a 404 — the admin route did not exist.\n The companion slice 1 commit added `POST /api/admin/publishers`;\n this slice reshapes the tool to match. All 8 audit-row-22\n Add-candidates surfaced (`legal_name`, `country`, `isni`,\n `publisher_type`, `wikidata_id`, `parent_publisher_id`,\n `founded_date`, `headquarters`) plus the explicit `ipi → ipi_number`\n rename. `parent_publisher_id` description steers agents at\n `pica_publishers_query` to resolve the parent UUID. Required fields:\n `name`, `ipi_number`. The route is idempotent on `ipi_number` — a\n duplicate IPI returns the existing row with `already_existed: true`\n instead of failing.\n\n- **ADR-174 Phase 2 items 14+15: `pica_agreements_create` / `_update`\n reshaped to consume `AGREEMENTS_WRITE_PROPERTIES` from\n `@withpica/mcp-utils`.** Tool schemas now advertise all 13\n Add-candidate columns from audit rows 14+15. Tool descriptions steer\n agents toward `counterparty_org_id` (ADR-176 first-class-party) over\n free-text `other_party_name` — use `pica_search_all` to resolve an\n org name to an ID. `_update` description calls out that\n counterparty_org_id changes require the linked-org check at the\n route layer (orgLinkingService.areLinked). No tool signature change\n otherwise; existing fields preserved.\n\n### Route-side companion (non-package, same slice)\n\n- `app/api/admin/agreements/route.ts` POST and\n `app/api/admin/agreements/[id]/route.ts` PATCH — phantom/unknown key\n rejection via `AGREEMENT_POST_ALLOWED_FIELDS` /\n `AGREEMENT_PATCH_ALLOWED_FIELDS` /\n `AGREEMENT_WRITE_PHANTOM_REDIRECTS` in\n `lib/services/agreements-write-constants.ts`. Pre-slice both routes\n spread `body` straight into the Supabase insert/update — effectively\n a wide-open write surface. Also surfaces and fixes pre-existing dark\n code in the PATCH test file (3 tests were sending `name` and `type`\n — phantom field names that silently dropped against `title` and\n `agreement_type`).\n\n- `app/api/admin/publishers/route.ts` POST (NEW) — publishers had no\n admin route at all pre-slice, so `pica_publishers_create` and the\n SDK's `PublishersResource.create` 404'd at runtime. Slice 1\n (0ba4d400d) adds the route with phantom/unknown-field rejection via\n `PUBLISHERS_POST_ALLOWED_FIELDS` / `PUBLISHERS_WRITE_PHANTOM_REDIRECTS`\n in `lib/services/publishers-write-constants.ts`, idempotent\n deduplication by `ipi_number`, FK pre-validation on\n `parent_publisher_id`, and server-stamped provenance.\n\n- **ADR-174 Phase 2 item 21: `pica_multimedia_create` reshaped.** Added\n 15 real-column fields that were invisible to agents pre-ADR-174:\n `credits`, `duration_seconds`, `collection_id`, `display_order`,\n `is_featured`, `is_published`, `venue`, `event_name`,\n `performance_date`, `setlist_position`, `sync_side`, and the external\n identifier set (`spotify_url`, `spotify_track_uri`, `spotify_track_id`,\n `youtube_url`, `youtube_video_id`, `soundcloud_url`, `thumbnail_url`).\n Description now points agents at `POST /api/admin/multimedia/upload`\n for file uploads and `pica_multimedia_link_youtube` for the YouTube\n enrichment flow — the generic create surface is for external-URL\n linking and performance-context metadata.\n\n### Route-side companion (non-package, same slice)\n\n- `app/api/admin/multimedia/route.ts` POST — phantom/unknown key guard\n via `MULTIMEDIA_POST_ALLOWED_FIELDS` /\n `MULTIMEDIA_POST_PHANTOM_REDIRECTS` in\n `lib/services/multimedia-write-constants.ts`. Redirects upload-flow\n columns (s3*key, file_name, …) to `/api/admin/multimedia/upload`,\n enrichment columns (youtube_view_count, spotify_popularity) to their\n respective cascades, and scanner columns (virus_scan*\\*) to the\n scanner flow. Also closes a latent privilege-escalation path: pre-slice\n the route overwrote `body.user_id` with the authenticated session's\n id, but a caller could still _attempt_ to pass `user_id` (silently\n overwritten). The guard now 400s on `user_id` / `organisation_id`\n injection attempts with a clear PHANTOM_FIELD message.\n\n- **ADR-174 Phase 2 item 13: `pica_sessions_create` reshaped.** Dropped\n `additionalProperties: true` per Decision 2. Added 6 previously-missing\n real columns from audit row 13 as explicit Zod properties:\n `description`, `timezone`, `is_all_day`, `location_url`, `recording_id`,\n `status` (enum: scheduled / in_progress / completed / cancelled), plus\n the `metadata` jsonb bag and the `participants` relational array\n (already handled by the service but undocumented in the tool surface).\n `recurrence_rule` deferred — the service's `CreateSessionParams` type\n needs to accept it first (tracked in the route-guard PHANTOM_REDIRECT\n entry).\n\n### Route-side companion (non-package, same slice)\n\n- `app/api/admin/sessions/route.ts` POST now reads `body.status` and\n `body.metadata` (pre-slice silently dropped) and 400s on phantom /\n unknown keys via `SESSION_POST_ALLOWED_FIELDS` /\n `SESSION_POST_PHANTOM_REDIRECTS` in\n `lib/services/sessions-write-constants.ts`.\n\n- **ADR-174 Phase 2 item 20: `pica_share_links_create` reshaped to\n consume `SHARE_LINKS_WRITE_PROPERTIES` from `@withpica/mcp-utils`.**\n Tool schema now advertises all 13 add-candidate columns from audit\n row 20 that were previously invisible to agents (access_type,\n allowed_person_ids, allow_comments, allow_view_collaborators,\n allow_view_financials, notify_on_access, watermark_audio,\n sent_to_emails, playlist_name, allow_streaming, include_all_files,\n included_file_ids, description). Executor widened to pass every\n caller-provided property through to the SDK / admin route — the\n route-layer allow-list (slice 1) rejects anything outside the\n contract. `password` remains the canonical plain-text input; the\n route hashes to `password_hash`.\n\n- **ADR-174 Phase 2 items 16+17: `pica_agreement_types_create` / `_update`\n reshaped to consume `AGREEMENT_TYPES_WRITE_PROPERTIES` from\n `@withpica/mcp-utils`.** Dropped the inlined property map in favour of\n the shared module that documents per-branch applicability. Phantom\n fields `title`, `description`, `points_percentage`, `recoupment_terms`,\n `rights_assigned` removed from the schema (agents sending them now fail\n fast at the admin route guard with a `PHANTOM_FIELD` redirect pointing\n at the canonical column or resolution path). Tool descriptions updated\n to truthfully list the required fields per branch (template needs\n `name` + `category` + `templateText`; producer needs `producer_id` +\n `royalty_points` + `deliverables` + `work_id`|`recording_id`;\n work_for_hire needs `contractor_id` + `contractor_role` + `fee_amount`\n - `services_description` + `work_id`|`recording_id`). Tool description\n for `_update` now calls out that PATCH on producer_agreements and\n work_for_hire_agreements is action-only — the generic update path has\n no live field-update surface on those two branches until a follow-up\n slice promotes the action-based PATCH handlers to accept field\n updates.\n\n### Added\n\n- **ADR-179 Phase 1: `pica_resolve_work` (stdio).** Outcome-shaped\n resolver that fans a work out across every eligible enrichment source\n in one call. Replaces the five `pica_enrich_work_*` tools' role at\n the agent layer. Returns `applied[]` / `proposals[]` / `errors[]` /\n `recovery_hints[]`. `isError` is set only when every source that ran\n errored — partial failure is a non-error receipt. Credit + billing\n gates wire through the `external_resolver_call` action key.\n- **ADR-179 Phase 2: `pica_resolve_person` (stdio).** Person-side\n resolver mirroring `pica_resolve_work`. Sources are narrower —\n `isni` | `musicbrainz` — covering the identity-graph cascade rules\n (ISNI→Wikidata and MBID→Wikidata crosswalks plus their downstream\n awards / biography enrichment). Same output shape, same isError\n semantics, same credit-gate action key as the work resolver.\n Registered in `lib/services/mcp-scopes.ts` under `write:people` and\n listed in the layered-discovery `enrichment` category so\n `pica_discover` surfaces it above the deprecated\n `pica_people_enrich_*` pair.\n\n### Deprecated\n\n- **`pica_enrich_work_mlc`, `pica_enrich_work_musicbrainz`,\n `pica_enrich_work_discogs`, `pica_enrich_work_spotify`,\n `pica_enrich_work_youtube`.** All five now return\n `TOOL_DEPRECATED` (jsonrpc code -32070) with a suggested-call\n payload pointing at `pica_resolve_work` with the correct `sources`\n narrowing. Tool definitions stay registered so `tools/list` and\n `pica_tool_details` can still surface them with a migration hint for\n one minor version — removal scheduled for the next minor after\n ADR-179 Phase 4's publish.\n- **`pica_people_enrich_isni`, `pica_people_enrich_musicbrainz`.**\n Both now return `TOOL_DEPRECATED` (jsonrpc code -32070) with a\n suggested-call payload pointing at\n `pica_resolve_person(sources: ['isni' | 'musicbrainz'])`. Tool\n definitions stay registered until the next minor; same one-minor-\n version deprecation window as the work-side five.\n\n### Changed\n\n- `pica_tool_details` responses for the five deprecated work tools\n now carry a `TOOL_DEPRECATED` entry in `recovery_hints` as the first\n item. Existing `NO_MATCH` / `MISSING_INPUT` hints are kept behind\n it — they are dead code today but stay in the registry until tool\n removal so downstream consumers don't see a mid-version\n disappearance.\n- Same treatment applied to the two deprecated person tools:\n `pica_people_enrich_isni` and `pica_people_enrich_musicbrainz` each\n get a `TOOL_DEPRECATED` recovery hint prepended to their existing\n `NO_MATCH` entry.\n\n## [2.22.0] — 2026-04-16\n\n### Changed\n\n- **ADR-174 Phase 2 item 10 (recording_splits): reshape\n `pica_recording_splits_create`.** Adopts the shared\n `RECORDING_SPLITS_WRITE_PROPERTIES` from `@withpica/mcp-utils@1.4.0`,\n dropping `additionalProperties: true` per Decision 2. All 9 audit-\n Keep fields now enumerated as explicit Zod properties — no phantom\n additions, no renames. Description-level hint on `role` replaced\n with a proper `enum` array matching the route's validRoles allow-\n list. Schema is now byte-identical to `@withpica/mcp-server-business`\n (both consume the shared module) — pre-slice they were independent\n byte-divergent-risk copies.\n\n### Route-side companion (non-package, same slice)\n\n- `app/api/admin/recordings/[id]/splits/route.ts` POST — UNKNOWN_FIELD\n guard runs before the required-field check so misspelled keys fail\n fast with the field name. See the slice commit.\n\n## [2.21.0] — 2026-04-16\n\n### Fixed\n\n- **ADR-174 Phase 2 item 24 (team): `pica_team_update_role` now actually\n updates role.** Pre-ADR-174 the tool was named `_update_role` but its\n Zod schema only accepted `permissions` — the `role` field was missing\n entirely. The admin PATCH route at `/api/admin/team/[id]` hard-\n destructured `{ permissions }` and silently dropped every other\n field, so even if an agent hand-crafted a call with `role` the DB\n write would not happen. Audit row 24 flagged this as \"Add `role`, or\n rename the tool.\" Fixed by adding `role: string` to the MCP Zod\n schema, widening the route to build the update object from whichever\n of `role` / `permissions` are provided, and making the old\n \"permissions required\" check accept \"at least one of role or\n permissions.\" `id` stays required; `role` and `permissions` are now\n both optional but at least one must be set.\n\n### Route-side companion (non-package, same slice)\n\n- `app/api/admin/team/[id]/route.ts` PATCH — phantom/unknown key\n rejection via `TEAM_MEMBERSHIP_PATCH_ALLOWED_FIELDS` (allow-list of\n `permissions` + `role`), error message updated from \"permissions\n required\" to \"at least one of permissions or role is required\", and\n \"failed to update permissions\" to \"failed to update team membership\"\n (now-generic — it updates role too).\n\n## [2.20.0] — 2026-04-16\n\n### Changed\n\n- **ADR-174 Phase 2 item 7 (projects): reshape `pica_projects_create` /\n `pica_projects_update` Zod schemas.** Exposed 9 Add-candidate fields\n from audit row 18 that were already plumbed end-to-end through the\n route and service but invisible to agents via tool discovery:\n `start_date`, `end_date`, `location_name`, `location_address`,\n `location_url`, `virtual_url`, `is_open`, `max_participants`, `status`\n (enum: draft / scheduled / active / completed / cancelled). Also\n surfaced the route-level `generate_invite_code` flag and the\n freeform `metadata` jsonb object. Dropped `work_ids` from both\n schemas — the pre-ADR-174 tool advertised `work_ids` but the admin\n POST / PATCH routes never routed it to the `project_works` junction\n (see commit `edf890a24` for the route-side FIELD_NOT_WIRED rejection\n and redirect message pointing at\n `POST /api/admin/projects/[id]/works`). The `project_type`\n description replaces the pre-ADR-174 \"album, ep, compilation, single,\n mixtape\" hint (none of which are valid backend values) with the\n actual convention: writing_camp, recording_session, production,\n mixing, mastering, retreat, other.\n\n### Route-side companion (non-package, same slice)\n\n- `app/api/admin/projects/route.ts` POST and\n `app/api/admin/projects/[id]/route.ts` PATCH — phantom/unknown key\n rejection with `FIELD_NOT_WIRED` redirect for `work_ids`. See commit\n `edf890a24`.\n\n## [2.19.0] — 2026-04-16\n\n### Added\n\n- **ADR-178: `pica_enrichment_propose` stdio tool.** New agentic write\n tool that files enrichment proposals sourced from open-web research\n (Audiomack, Songdata, MusicBrainz page, label portals, artist bios,\n etc.) rather than from PICA's structured cascade. Every proposed\n field must cite at least one source URL — `sources[].fields` arrays\n form the trust moat, and the server rejects uncited claims with\n `code: MISSING_SOURCE`. Source type routes the proposal as\n `source = 'agent_research'`, `rule_id = 'agent_research'` on the\n existing `enrichment_proposals` table (no new queue, no new review\n tools — reuses `pica_enrichment_proposals_list` / `_apply` /\n `_reject` from `2.10.0`).\n\n Tool description carries ADR-178 Decision 3 language verbatim: when\n the user is in-session, the agent asks for approval directly and\n calls `pica_enrichment_proposal_apply` after confirmation — the\n dashboard card is the receipt, not the workflow. This shapes agent\n behaviour in-context without needing a new code path for \"in-\n session approval\".\n\n Wrapped in `withBillingGate` and (via\n `@withpica/mcp-utils@1.3.0`) `withCreditGate` under the new\n `enrichment_propose` action key. Credit gating is telemetric only\n while ADR-162 keeps the subscription gate on; the wrap is already\n in place so re-enabling billing doesn't need a tool-surface change.\n\n### Fixed\n\n- **ADR-178 slice 1b regression caught in smoke test:** agent-research\n proposals whose `proposed_fields` cite columns that don't exist on\n the target table (tempo_bpm, musical_key, producers — the Heinzmann\n transcript's fields, not columns on `works`) used to 500 with a\n Postgres \"column does not exist\" error because the service built a\n column-scoped `SELECT` from the proposed keys. Fix snapshots the\n full live row and builds `current_fields` from the intersection of\n proposed keys and actual columns. Unknown keys now land as pending\n proposals with an empty baseline instead of crashing the request.\n Apply path for unknown-column fields is a separate open question on\n the ADR (see Open Question 5).\n\n## [2.18.0] — 2026-04-16\n\n### Changed\n\n- **ADR-174 Phase 2 item 6: reshape `pica_credits_update` Zod schema.**\n Dropped phantom `publisher_name` and `publisher_ipi` properties —\n `work_credits` has no columns for either. Agents now resolve a\n publisher name or IPI to a UUID via `pica_publishers_query` (or\n create one via `pica_publishers_create`) and pass the result as\n `publisher_id`. Added three audit \"Add candidate\" columns to the\n per-credit-object shape: `is_primary` (boolean), `notes` (string),\n `attestation_status` (enum: pending / attested / disputed /\n declined). `attested_at` / `attested_by` remain service-managed.\n Description refresh calls out `credit_type` as the canonical column\n name stored behind the `role` alias and `writer_split_percentage`\n behind `splits`. No required-field change — `person_id`, `role`,\n `splits` stay required.\n\n### Route-side companion (non-package, same slice)\n\n- `app/api/admin/works/[id]/credits/route.ts` POST — phantom/unknown\n key rejection on each `credits[i]` element with field name + index\n in the error payload, plus a mirror-fill step that normalises\n `role` ↔ `credit_type` and `splits` ↔ `writer_split_percentage` so\n callers sending either spelling flow through. See commit\n `dbfb098ae` for the server-side guard.\n\n### Not covered by this slice\n\n- `work_collaborators` (publishing-side POST at\n `app/api/admin/works/[id]/collaborators/route.ts`) was not in the\n ADR-174 audit — the MCP tool's `updateCollaborators` SDK hop hits\n that route for writer/composer/lyricist/arranger roles today and\n inherits a separate column set. Tracked as a follow-up slice.\n\n## [2.17.0] — 2026-04-16\n\n### Changed\n\n- **ADR-174 Phase 2 item 5: reshape `pica_physical_assets_create` and\n `pica_physical_assets_update` Zod schemas.** Adopted the shared\n `PHYSICAL_ASSETS_WRITE_PROPERTIES` from `@withpica/mcp-utils@1.2.0`,\n dropped `additionalProperties: true` on both tools, and moved 11\n phantom top-level fields (`current_valuation`, `valuation_currency`,\n `valuation_source`, `valuation_date`, `valuation_notes`,\n `reverb_listing_url`, `ebay_item_url`, `insured`,\n `insurance_provider`, `insurance_policy_number`, `insurance_coverage`)\n off the top-level surface. Agents set these via\n `external_references: { current_valuation: 1500, insurer: \"ACME\", ... }`\n per the ADR-174 Open Decision 1 (2026-04-14) resolution. Two fields\n were renamed at the jsonb layer: `insurance_provider → insurer`,\n `insurance_coverage → insured_value`. `asset_type`, `condition`,\n `acquisition_method`, `license_type`, and `status` gained proper\n `enum` arrays matching the underlying `physical_assets_*_check` CHECK\n constraints — pre-reshape they were loose strings with the enum\n hinted in the description (so callers could pass `studio_equipment`\n at the MCP layer and get a 500 from the CHECK constraint at the DB\n layer).\n- **No description lie.** Both tool descriptions now explicitly name\n `external_references` as the home for valuation/insurance/DSP URL\n details rather than the pre-ADR-174 \"tracks … valuation, photos,\n insurance, and status\" claim that the schema couldn't honour.\n\n### Route-side companion (non-package, same slice)\n\n- `app/api/admin/assets/route.ts` POST and\n `app/api/admin/assets/[id]/route.ts` PATCH — phantom/unknown key\n rejection with redirect messages (400 + `PHANTOM_FIELD` /\n `UNKNOWN_FIELD` error codes). See commit `ced46b889` for the\n server-side guard.\n\n## [2.16.0] — 2026-04-15\n\n### Added\n\n- **ADR-173: five release-track tools.** Closes the gap flagged by two\n independent external MCP reviewers on 2026-04-14 (\"release layer looks\n shallow\"). New tools on the stdio transport:\n - `pica_releases_attach_track` — attach a recording and/or work at a\n specific `(disc_number, track_number)`. Idempotent on position.\n At least one of `recording_id` / `work_id` is required.\n - `pica_releases_list_tracks` — list tracks in `(disc, track)` order\n with inlined title/artist/ISRC/duration from the linked recording\n and work.\n - `pica_releases_detach_track` — soft-confirmation detach by position\n (preview without `confirm:true`, delete with).\n - `pica_releases_reorder_tracks` — transactional positional reorder\n via the `reorder_release_tracks_atomic` Postgres RPC. Rejects\n duplicate positions in the payload before any DB write.\n - `pica_releases_attach_recording_with_work` — compound workflow that\n auto-pulls the recording's linked work onto the new track row.\n\n### Changed\n\n- **`pica_works_inspect` and `pica_recordings_inspect` gain a `releases`\n section.** Lazy (only fetched when requested). Returns every release\n the entity appears on with its track position. Answers \"which albums\n is this master on?\" in one call — previously unanswerable via MCP.\n\n### Fixed\n\n- **`pica_releases_list_tracks` 500 on every call.** Pre-merge E2E\n caught two latent bugs in the `listTracks` service query: a missing\n FK `release_tracks.recording_id → recordings(id)` (PostgREST could\n not resolve the `recording:recordings(...)` embed) and a\n `duration_seconds` column reference where the live column is\n `duration_ms`. Fixed in migration\n `20260415_01_adr173_fix_release_tracks_recording_fk.sql` +\n a rename in `lib/services/releases.ts`. The migration also NULLs 85\n orphan `recording_id` values on production left behind by the\n 2026-04-04 soundslikefez duplicate-works cleanup.\n\n### Note on version number\n\nThis release would have been `2.15.0` per the original ADR-173\nimplementation record, but `2.15.0` was taken on `develop` by the\nADR-174 Phase 2 item 4 slice while the ADR-173 fix commits were in\nflight. Bumped to `2.16.0` to keep the published package timeline\nlinear.\n\n## [2.15.0] — 2026-04-15\n\n### Changed\n\n- **ADR-174 Phase 2 item 4: `pica_people_create` / `pica_people_update`\n schema reconciliation.** Introduced `PEOPLE_WRITE_PROPERTIES` as the\n canonical source of truth for the people write surface — every\n property maps to a real column on either `public.people` or\n `public.person_enrichment`. `additionalProperties: true` is off;\n unknown keys 400 at the HTTP layer (see develop commit\n `fbea9e2a3`).\n- **Satellite-routing made explicit.** Eleven fields remain in the\n schema but their descriptions now name `person_enrichment` as the\n write target: external identifiers (`isni`, `musicbrainz_id`,\n `wikidata_id`, `discogs_artist_id`, `deezer_artist_id`) and\n biographical data (`date_of_birth`, `gender`, `nationality`,\n `birth_place`, `instruments`, `career_start_year`). The service\n fans these out through `syncPersonEnrichmentSatellite`. Correction\n to the original audit (row 7) landed in ADR-174's Corrections\n block: six of these fields were classified as \"Remove — no column\n on people\", which missed the satellite hop. They are not phantom\n writes, and subsequent slices must audit satellite write paths\n before classifying any field as phantom.\n- **Twelve add-candidates surfaced** (audit row 7 \"Missing writable\n columns\"): `middle_name`, `person_type`, `company`, `position`,\n `territory`, `social_media`, `emails`, `pro_name`,\n `pro_member_number`, `mcps_member_number`, `relationship_strength`,\n `email_preferences`. All verified against `public.people` columns\n 2026-04-15 (project `fwgcmjhlwevdnxgqmkmh`).\n- **Deprecated duplicates rejected.** `type` (deprecated dup of\n `person_type`) and `role` (deprecated singular of `roles`) are\n now 400 PHANTOM_FIELD with a redirect message naming the canonical\n column. Both DB columns still exist as unused dead space —\n removing them is out of scope and scheduled for ADR-165-style\n cleanup.\n- **Description lies removed.** The audit (row 8) flagged\n `pica_people_update` description as \"Additional fields are also\n accepted\" with no enumeration. That sentence is gone from both\n `create` and `update` descriptions.\n\n### Breaking\n\n- Callers that were passing the deprecated `type` / `role`\n duplicates now get a 400 with a redirect hint — previously the\n keys were silently dropped by the ORM. Same failure-mode calculus\n as the works / recordings slices — the writes were already\n failing, now they fail visibly.\n- Callers that were passing arbitrary unlisted keys now get a 400 —\n previously `additionalProperties: true` let them through and the\n ORM dropped them silently. Zero rows observed in `people.metadata`\n jsonb for any of the pre-existing phantom keys (verified during\n ADR-174 Phase 1 2026-04-14).\n\n## [2.14.0] — 2026-04-14\n\n### Changed\n\n- **ADR-174 Phase 2: `pica_recordings_create` / `pica_recordings_update`\n schema reconciliation.** Introduced `RECORDING_WRITE_PROPERTIES` as\n the canonical source of truth for the recordings write surface —\n every property maps to a real column on `public.recordings`. Added\n thirteen fields the DB exposes that the tool was hiding:\n `duration_ms`, `preview_url`, `album_art_url`, `spotify_url`,\n `spotify_track_uri`, `spotify_track_id`, `youtube_video_id`,\n `youtube_url`, `apple_music_url`, `deezer_track_id`,\n `mlc_recording_id`, `mlc_song_code`, `isrc_prefix`. The\n `version_type` field is now enum-restricted to the ADR-166 values\n (`master`, `alternate_master`, `music_video`, `lyric_video`,\n `live_performance`, `acoustic`, `remix`, `cover`, `alternate`),\n matching the `recordings_version_type_check` DB constraint.\n- **`pica_recordings_create` default `version_type` changed from\n `\"original\"` to `\"master\"`.** Pre-fix the executor defaulted to\n `\"original\"`, which is not a valid version_type — every call without\n an explicit type tripped the recording-type CHECK constraint and\n surfaced as a 500 from the service. `\"master\"` is the DB-level\n default and the canonical ADR-166 value.\n- **Title rename made explicit.** `recording_title` is the canonical\n column on `public.recordings`. The tool keeps `title` as an input\n alias for ergonomics; the schema now declares both fields with the\n rename called out in their descriptions, instead of relying on\n `additionalProperties: true` to hide the translation.\n- Tool descriptions now steer album metadata (`album_name`,\n `album_release_date`, `upc`, `track_number`) to\n `pica_releases_create/update`, ISWCs to `pica_works_create/update`,\n and label metadata to `pica_releases_*.label_organization_id` via\n `pica_labels_query`. `duration_seconds` is explicitly named as the\n works convention; `recordings` carries `duration_ms`.\n\n### Removed\n\n- **ADR-174 Phase 2: seven phantom fields rejected on\n `pica_recordings_create` / `pica_recordings_update`.** The Zod schema\n no longer accepts them and `additionalProperties: true` is gone:\n `album_name`, `album_release_date`, `upc`, `track_number`, `label`,\n `duration_seconds`, `iswc` — none of these corresponded to columns on\n `recordings`. The HTTP route at `POST/PATCH /api/admin/recordings[/id]`\n now 400s on any of these keys with a redirect message naming the\n correct tool (commit `cffa6f947`).\n\n## [2.13.1] — 2026-04-14\n\n### Changed\n\n- **ADR-174 Phase 2: `pica_works_bulk_update.updates` schema gated on\n `WORK_WRITE_PROPERTIES`.** The bulk tool was the last write-path\n surface that still accepted any key — `updates: { type: \"object\" }`\n with no property list (audit row 25). Now validates against the same\n canonical schema as `pica_works_update`: phantom keys (label, upc,\n album_name, …) and arbitrary unlisted keys fail fast with a\n descriptive `VALIDATION_ERROR` before the SDK is called. One bad key\n invalidates the whole batch — no partial writes.\n\n## [2.13.0] — 2026-04-14\n\n### Changed\n\n- **ADR-174 Phase 2: `pica_works_create` / `pica_works_update` schema\n reconciliation.** Introduced `WORK_WRITE_PROPERTIES` as the canonical\n source of truth for the works write surface — every property maps to\n a real column on `public.works`. Added five fields the DB exposes\n that the tool was hiding: `tempo`, `key`, `display_artist`,\n `published`, `tunecode`. Tool descriptions now steer album/release\n metadata (`album_name`, `album_art_url`, `track_number`, `upc`,\n `spotify_url`) to `pica_releases_create/update` and label metadata to\n `pica_releases_*.label_organization_id` via `pica_labels_query`.\n\n### Removed\n\n- **ADR-174 Phase 2: seven phantom fields removed from\n `pica_works_create` / `pica_works_update`.** `label`, `spotify_url`,\n `album_name`, `album_release_date`, `album_art_url`, `track_number`,\n `upc` — none of these corresponded to columns on `works`. The HTTP\n route at `POST/PATCH /api/admin/works[/id]` now 400s on any of these\n keys with a redirect message naming the correct tool (commit\n `9d68b16b1`). Previously they routed silently into the\n `work_album_metadata` / `work_spotify_data` satellites that ADR-165\n marked as dead — a write succeeded but no reader could find the\n value.\n- **ADR-174 Phase 2: `additionalProperties: true` removed from both\n works write schemas.** The tool no longer silently accepts arbitrary\n keys; unknown keys surface as validation errors. Description lies\n about `available_for_licensing`, `vocal_type`, `energy`,\n `danceability` also removed — those fields live on satellite tables\n and are not exposed through MCP.\n\n## [2.12.0] — 2026-04-14\n\n### Added\n\n- **ADR-174 Phase 2: `pica_labels_query` tool** — read-only resolution of\n label names to `organisations.id`. Returns label organisations\n (`org_type='label'`) whose name or display_name matches the substring\n query, for use as `releases.label_organization_id` via\n `pica_releases_create` / `pica_releases_update`. `query` and `limit`\n both optional; limit defaults to 50, max 100. Category: catalog.\n Annotations: `readOnlyHint: true`.\n\n### Changed\n\n- **ADR-174 Phase 2: `pica_releases_create` / `pica_releases_update`\n schema reconciliation.** Input schemas now expose the nine ADR-174\n Decision 3 fields that `releases` actually stores:\n `label_organization_id`, `distributor_organization_id`,\n `pre_release_date`, `artwork_url`, `spotify_album_uri`, `spotify_url`,\n `apple_music_url`, `other_urls`, `notes`. Tool descriptions now\n direct agents to call `pica_labels_query` (new) or `pica_search_all`\n to resolve a label/distributor name to an organisation ID before\n writing.\n\n### Removed\n\n- **ADR-174 Phase 2: freetext `label` removed from\n `pica_releases_create` / `pica_releases_update`.** The field never\n corresponded to a real column on `releases` — the DB models labels\n via `label_organization_id` FK. Agents must now resolve a label name\n to an organisation ID (via `pica_labels_query`) instead of passing a\n string. Pre-fix behaviour: tool schema accepted `label`, service\n propagated it to the DB, the DB rejected it as `42703 column does not\nexist`, every call 500'd. No working integrations could have relied\n on this — the change is strictly a fix, not a break.\n\n## [2.11.0] — 2026-04-13\n\n### Changed\n\n- **ADR-171: Prompts replaced with workflow-level skills.**\n 11 prompts → 10 skills, each with decision trees, domain knowledge,\n enrichment source priority, and the shared preamble (tone, prerequisite\n check, summary pattern). Deployed as upgraded prompts; will convert to\n MCP skills format when the spec extension ships.\n\n New skills: `workspace-autopilot`, `establish-identity`,\n `catalog-your-music`, `upload-and-analyse`, `close-the-loop`,\n `manage-collaborators`, `establish-ownership`, `production-assets`,\n `stay-connected`, `export-and-report`.\n\n Retired prompts: `analyze-catalog`, `find-duplicates`,\n `enrich-metadata`, `verify-works`, `assess-catalog-health`,\n `audit-credits`, `new-catalog-setup`, `register-my-works`,\n `prepare-for-sync`. Functionality folded into new skills —\n see design spec for mapping.\n - `workspace-autopilot` now routes through the full journey sequence\n (identity → catalog → audio → gaps → collaborators → ownership →\n notifications → exports) instead of the old 5-condition router.\n - `close-the-loop` absorbs 7 former prompts and adds the enrichment\n cascade decision tree (MLC first if IPI, MusicBrainz second, Spotify\n third) and inline duplicate detection.\n - `export-and-report` absorbs `analyze-catalog`, `register-my-works`,\n and `prepare-for-sync` into a single export/report skill with CAR,\n CWR, CSV, provenance, sync readiness, and carbon footprint paths.\n\n## [2.10.0] — 2026-04-11\n\n### Added\n\n- **ADR-163: Tier B enrichment proposal review tools.**\n - `pica_enrichment_proposals_list` — list pending proposals\n awaiting review. Filters: `entity_type`, `entity_id`,\n `rule_id`, `source`, `limit` (1..100, default 20), `offset`.\n Only `status='pending'` rows are returned. Backed by\n `GET /api/admin/enrichment-proposals`.\n - `pica_enrichment_proposal_apply` — apply a pending proposal.\n For update proposals, runs drift detection first: if the\n entity has changed since the proposal was created, returns\n `{ status: 'drift_detected', conflicts }` without writing.\n Agents surface conflicts to the user before retrying with\n `force=true`. For create proposals (`artist_title_to_youtube`),\n a uniqueness check runs instead and cannot be forced. Backed\n by `POST /api/admin/enrichment-proposals/:id/apply`.\n - `pica_enrichment_proposal_reject` — reject a pending proposal\n with an optional `resolution_note`. Content-hash suppression\n (ADR-163) permanently blocks re-proposal of identical content\n — no cooldown, no timer. Backed by\n `POST /api/admin/enrichment-proposals/:id/reject`.\n\n- **ADR-166: YouTube import as a recording-version source.**\n - `pica_import_youtube_link` MCP tool wraps the Phase 3 orchestrator.\n Takes a YouTube URL, returns a preview (items + classification +\n work match), then `confirm: true` executes the import as a new\n recording on an existing or newly-created work. Supports\n `selectedVideoIds`, `targetWorkId`, and `overrideVersionType`\n for fine-grained agent control. Landed in `78da58344`\n (feat(adr-166): phase 4 — pica_import_youtube_link MCP tool + SDK\n methods).\n\n### Changed\n\n- `pica_cascade_health` outcome bucket list extended to include\n the ADR-163 Phase 1 `proposed` and `suppressed` outcomes. Tool\n description now reads `wrote / no_match / already_enriched /\nerror / proposed / suppressed`. Counters populate automatically\n from `cascadeOutcomeCounter` — no schema change required for\n existing `/api/admin/cascade-health` or\n `/api/internal/cascade-health` consumers.\n\n- Several mcp-server source files got minor reformatting from ADR-165's\n flattener strip (removing `work_spotify_data` + `work_album_metadata`\n fields from the Work shape) and ADR-166's cascade rule rewrites.\n These are consumer-invisible at the MCP tool surface — the tools\n still accept the same inputs and return the same outputs — but the\n underlying `PicaClient.works` reads + writes now route through the\n ADR-165 overlay. See the ADR-165 and ADR-166 implementation records\n for details.\n\n### Fixed\n\n- `pica_run_person_cascade` tool description had a dangling\n `→ then: pica_people_inspect` chain with no parenthetical reason hint,\n which the `composability-chains.test.ts` linter caught as a content\n bug. Description updated to `→ then: pica_people_inspect (see what\nthe cascade wrote)`. Fixed in `3a2843636` (test(mcp-server): fix 10\n pre-existing test failures across 8 suites).\n\n### Notes\n\n- Backwards-compatible minor bump. Three new tools, one widened\n description, no removals or signature changes.\n- Depends on `@withpica/mcp-sdk@^1.4.0` for the new\n `EnrichmentResource.listEnrichmentProposals` /\n `applyEnrichmentProposal` / `rejectEnrichmentProposal` methods.\n- Source additions landed across ADR-163 Phase 3d (`ff9cf265a`) and\n Phase 6 (`ff97faa56`).\n- Registry: https://www.npmjs.com/package/@withpica/mcp-server/v/2.10.0\n- Published alongside `@withpica/mcp-sdk@1.4.0` and\n `@withpica/mcp-server-business@1.3.0` in ADR-163 Phase 6.\n\n## [2.9.0] — 2026-04-11\n\n### Added\n\n- **ADR-164 audit follow-up: three new cascade MCP tools**\n - `pica_run_work_cascade(work_id)` — manually re-evaluate a work\n against every ADR-164 cascade rule and fire those whose\n preconditions are satisfied. Idempotent. Fire-and-forget. Backed by\n `POST /api/admin/works/:id/cascade-run`.\n - `pica_run_person_cascade(person_id)` — same for people. Fires\n `ipi_to_mlc_works` (MLC writer/publisher splits),\n `mbid_to_wikidata_crosswalk`, `isni_to_wikidata_crosswalk`,\n `wikidata_to_awards`, `wikidata_to_biography`, and\n `google_contact_suggest`. Backed by\n `POST /api/admin/people/:id/cascade-run`.\n - `pica_cascade_health` — snapshot of in-process cascade counters\n (ADR-164 Decision 5). Org-auth twin of the operator-only\n `/api/internal/cascade-health` endpoint. Returns per-rule failure\n counts bucketed by reason + outcome totals. Process-global, not\n persistent across serverless cold starts — treat as a spot-check.\n\n### Notes\n\n- Source additions landed in `38901f281` (ADR-164 audit follow-ups).\n Version bump + rebuilt dist + publish tagged in `edfbcb07b`.\n- Minor bump per semver — new tools, no removed or renamed surface.\n- Registry URL:\n https://www.npmjs.com/package/@withpica/mcp-server/v/2.9.0\n- Tarball verified post-publish by pulling\n `withpica-mcp-server-2.9.0.tgz` from the registry and grepping for\n all three new tool names in `package/dist/tools/enrichment.js`.\n\n## [2.8.0] — 2026-04-10\n\n### Changed\n\n- **ADR-162: subscription-based billing, credit gating disabled.**\n `withCreditGate` is now a pass-through — all tools are free for\n active subscribers. The MPP (Micropayment Protocol) machinery is\n retained in `@withpica/mcp-utils` for a future pay-per-credit\n re-enable but is dormant. Version bump carried in `7c4f5d24a`\n (`chore(adr-162): version bumps for npm publish`).\n\n## [2.7.0] — 2026-04-08\n\n### Added\n\n- **ADR-158c custody tool release.** Six `pica_custody_*` tools go\n live: claim, accept, decline, dispute, incoming list, history.\n Version bump in `91dd1c275` (`chore(adr-158c): version bumps for\ncustody tool release (Phase 6b)`).\n\n## [2.6.2] — pre-2026-04-08\n\n### Fixed\n\n- Stale version constant in the boot banner — the banner was still\n reporting an older version after an earlier bump. Fixed in\n `980dabc02` (`fix(mcp-server): correct stale version constant in\nboot banner (2.6.2)`).\n\n## [2.6.1] — pre-2026-04-08\n\n### Fixed\n\n- MCP server now emits `tools/list_changed` + `resources/list_changed`\n notifications after sign-in and sign-out, so clients refresh the\n tool list without a reconnect. Fixed in `f1ba2a211`.\n\n## [2.6.0] — 2026-04-07\n\n### Changed\n\n- **ADR-155 launch — publish 6 packages.** Catalog server rebaselined\n from the broken `3.0.0` publish (deprecated + unpublished from npm\n because `file:` deps had been baked into the tarball, leaving every\n fresh installer dead) to `2.6.0`. Five new sibling packages\n (`@withpica/mcp-sdk`, `@withpica/mcp-utils`,\n `@withpica/mcp-server-business`, `-enrichment`, `-settings`)\n published at `1.0.0` alongside with real semver deps so `npm\ninstall` actually resolves on user machines.\n- `connect.withpica.com` leads with the no-api-key lobby-mode flow.\n Landed in `e235aed40` (`feat(mcp): ADR-155 launch — publish 6\npackages, lobby-mode connect copy`).\n\n## Pre-2.6.0 — pre-changelog era\n\nEarlier versions (`2.0.0` through `2.5.x`) covered the pre-ADR-155\nmonolithic MCP server. Version history for that era is reconstructable\nvia `git log --follow -- mcp-server/package.json`. Notable milestones:\n\n- `2.5.x` — MCP Apps prebuild script + ext-apps devDependency added\n- `2.4.x` — build/publish polish, `.vercel/` excluded from tarball\n- `~2.0.0` — ADR-149 agentic hardening (write tiers, ProposedAction,\n confirmation, audit, annotations)\n\n[Unreleased]: https://github.com/withpica/pica/compare/edfbcb07b...HEAD\n[2.9.0]: https://github.com/withpica/pica/compare/7c4f5d24a...edfbcb07b\n[2.8.0]: https://github.com/withpica/pica/compare/91dd1c275...7c4f5d24a\n[2.7.0]: https://github.com/withpica/pica/compare/980dabc02...91dd1c275\n[2.6.2]: https://github.com/withpica/pica/compare/f1ba2a211...980dabc02\n[2.6.1]: https://github.com/withpica/pica/compare/e235aed40...f1ba2a211\n[2.6.0]: https://github.com/withpica/pica/commit/e235aed40\n";
4
4
  export const PACKAGE_NAME = "@withpica/mcp-server";
5
- export const PACKAGE_VERSION = "2.56.0";
5
+ export const PACKAGE_VERSION = "2.57.0";
6
6
  //# sourceMappingURL=changelog.generated.js.map