vantage-peers-mcp 2.18.0 → 3.0.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.
package/CHANGELOG.md CHANGED
@@ -1,613 +1,237 @@
1
1
  # Changelog
2
2
 
3
- ## [2.18.0] — 2026-08-11
4
-
5
- ### Changed
6
- - **Expose only the CORE tool surface (mission `vp-mcp-alias-cleanup-v1`, S8).** A data-driven allowlist (`mcp-server/tool-exposure.json`, `{"core":[...]}`) masks every tool whose `T2_verdict` is not `CORE` in `analysis/vantagepeers/vp-restructuring/vp-by-tool-day158.csv`. Masking ≠ deletion: non-CORE tools stay registered + handler-wired and are `disable()`d so `tools/list` does not advertise them; reverting = removing a line from the data file. Exposed = CORE ∩ registered = **66** tools; masked = **43** (registered 109). The exposure list is derived from the CSV, never typed; a name in the file matching no registered tool makes the server refuse to start, naming it. Applied at the single shared `registerTools` surface, so both stdio and HTTP transports (online clients) inherit the reduced surface. 5 CORE names from the day158 CSV are #1169-removed aliases whose CORE survivors stay exposed (zero capability lost). Tests: `test/tool-exposure.test.ts` 2/2, full suite 1071 passed / 0 failed, tsc 0.
7
-
8
- ## [2.17.0] — 2026-08-11
3
+ ## [3.0.0] — 2026-10-01
9
4
 
10
- ### Removed
11
- - 14 duplicate alias tools removed (mission `vp-mcp-alias-cleanup-v1`, S2, merged in #1169), keeping the fleet-used survivor of each pair — decided by call-site usage, never the code's `DEPRECATED ALIAS` label. Registered tool count 123→109. Context-token saving 1347 (11.1%) of the tool-list surface. Full list + arbitration in the root `CHANGELOG.md` and `elpi-corp/.../S1-arbitrated-pairs-day159.md`.
12
-
13
- ## [Unreleased] — final refus-total sweep (8 tools) → remaining: 0
14
-
15
- ### Security
5
+ Customer-facing summary of every `mcp-server/` change since 2.19.0 (commit `f718dd3`). Earlier releases are listed below.
16
6
 
17
- - **Close the last 8 same-class refus-total instances on the client MCP surface.** `get_profile`, `list_peers`, `list_repo_mappings`, `get_repo_mapping`, `get_message` fed `scopeFilterList`/`scopeFilterGet` rows lacking `createdBy`/`namespace` → named remap of the real ownership field (`profiles.orchestratorId`, `githubRepoMapping.orchestrator`, `messages.from`) → `createdBy` before the filter, synthetic field stripped (the `list_broadcast_status` precedent). `list_issues`, `get_issue`, `issue_stats` have no client-owner field (fleet routing/aggregate data; sibling mutations already master-only) → `defineTool` scope `{ kind: "master" }`, structural removal from the client surface. Per tool RED→GREEN with four independent poles; 37 new tests (4 files) + updated `scope-aware-filter-wave-c2`/`c3` (stale fixtures that asserted the old leak as acceptable, aligned to the merged `list_errors` template). RED without fix: 18 owner-pole failures; full CI-scoped suite 2679/2679 green; tsc + scope-typecheck exit 0. **Final class sweep: `remaining: 0`** — every remaining `scopeFilterList`/`scopeFilterGet` site operates on a table with native `createdBy`/`namespace` or already remaps its non-native owner; `check_messages`/`mark_as_read`/`list_tasks`/`list_missions`/`list_diaries` use dedicated non-`scopeFilterList` gates (out of this defect class). Closes VP `k1759mg282aqy6t7c91gnk10598bn4sv`; completes mission `vp-multitenant-zero-hole-v1`.
7
+ ### Breaking
18
8
 
19
- ## [Unreleased] — list_bus / list_mandates / list_errors refus-total close
9
+ - The `components` registry (six tools: `list_components`, `register_component`, `get_component`, `update_component`, `delete_component`, `search_components`) is removed, together with its entry in the `vantage-peers-mcp/api` type exports. These tools were not advertised to clients in 2.19.0.
10
+ - Two legacy credential types are no longer accepted: tokens from the retired dynamic-registration token store, and legacy internal tenant bearers. A request presenting either is refused with HTTP 401. OAuth access tokens issued by `/token` and Clerk session tokens are unaffected.
20
11
 
21
- ### Security
22
-
23
- - **Scope `list_bus`/`get_bu`, `list_mandates`/`get_mandate` to their owner; move `list_errors`/`get_error` to master-only.** These six handlers fed `scopeFilterList`/`scopeFilterGet` rows whose shape carried neither `createdBy` nor `namespace`, so the guard refused **every** non-master caller including the owner (the refus-total form measured in the S0 campaign). Per-table remedy, decided by measurement: `businessUnits` is owned by `orchestratorId` → named remap to `createdBy` before the filter (the `list_broadcast_status` precedent); `mandates` has two owners `requestedBy`/`fulfilledBy` → dual remap unioned by `_id` (a single remap would hide one party's own mandates); `errorLogs` has no client owner (fleet-ops monitoring) → its `defineTool` scope becomes `{ kind: "master" }`, a structural removal from the client surface (non-master now gets an explicit Forbidden instead of a silent empty list). Per tool: RED (owner refused) → GREEN with owner/deny/master poles moving independently; 28 new tests + updated `scope-aware-filter-wave-c3`; full CI-scoped suite green, tsc + scope-typecheck exit 0. Class sweep found 8 further same-class instances (`get_profile`, `list_peers`, `list_issues`, `get_issue`, `issue_stats`, `list_repo_mappings`, `get_repo_mapping`, `get_message`) — tracked as a follow-up, out of this PR's named scope. Closes VP `k177617dqg6z5c099p1rdp5rqn8b2rp0`.
24
-
25
- ## [Unreleased] — content-search multi-tenant scope (refus-total close)
26
-
27
- ### Security
12
+ ### Added
28
13
 
29
- - **Scope three content-rendering MCP tools to their caller.** `list_messages`, `search_messages_by_keyword`, and `search_tasks_by_keyword` fed `scopeFilterList` rows whose rendered shape carried neither `createdBy` nor `namespace`, so the naive guard wrap would have refused **every** caller including the owner (the refus-total defect PR #1122 deliberately avoided for the two search tools; `list_messages` already exhibited it). Fix: message-shaped tools (`from` field) get a named `from`→`createdBy` remap before `scopeFilterList` with the synthetic field stripped on output (the `list_broadcast_status` precedent); `search_tasks_by_keyword` requests `fields=full` internally, filters against the real `createdBy`, then reprojects to the public `lite` shape (avoids changing the public tool shape). Per-tool RED→GREEN with four independent poles (cross-tenant reproduction, owner-only, deny-only, master-all): RED 8-fail without fix → GREEN 17/17. tsc exit 0. Unremapped-shape audit: all 22 `scopeFilterList` sites checked, only the two message sites needed the remap. Closes VP `k175j2jems5deccegp4p0fy4x98b4ypn` + `k1780azk7n8fdb7bpnx5n91sx18b5vjf`.
14
+ - `correct_task_segment`: narrow a recorded work span to its real boundaries, once, with a mandatory reason. The original span is kept for audit.
15
+ - Now available to clients: `whoami` (returns the identity attached to your own credential: agent name, scope profile, namespaces) and `generate_upload_url` (an upload URL for your own organisation's storage, used before `store_document_chunked`).
16
+ - Now available to clients: `fail_task` (a third terminal state, distinct from done and cancelled), `pause_task` and `resume_task` (stop and restart a task's work clock without ending it).
17
+ - Now available to clients: the fix-pattern tools `create_fix_pattern`, `get_fix_pattern`, `list_fix_patterns`, `search_fix_patterns`, `add_fix_attempt`, `validate_fix` and `link_issue_to_pattern`.
18
+ - `check_messages` reports how many in-progress tasks are stuck past the configured threshold on an open work segment, alongside the stuck list.
19
+ - `/health` publishes the agent-identity mode, where that mode comes from, and how many calls were served on a typed agent name without a credential.
30
20
 
31
- ## 2.14.2 — 2026-06-30
21
+ ### Security and fixes
32
22
 
33
- - fix(oauth): DCR `/register` rejects empty/missing/malformed `redirect_uris` (RFC 7591 §3.2.2 `invalid_redirect_uri`). Closes zombie-client class — clients with empty `redirectUris` arrays can no longer be created. Defense-in-depth: same guard at Convex `registerPublicClient`. TDD-strict RED-then-GREEN.
23
+ - Agents act under the credential they present (`x-vantage-agent-credential`), not under a name typed into a tool argument. Names are compared after case and Unicode normalisation; accented and unaccented names stay distinct.
24
+ - A message's sender is checked against the verified caller: a caller from another organisation can no longer sign as one of your agents.
25
+ - `list_peers` surfaces a backend refusal as an explicit error instead of an empty list.
26
+ - A signed-in user with no organisation yet receives a typed refusal instead of the "invalid token" answer. An agent credential that does not resolve is refused as `AGENT_CREDENTIAL_INVALID` (HTTP 401), distinct from a lookup failure.
27
+ - Every refresh now returns a new refresh token, so a seat that keeps refreshing no longer expires at 30 days.
28
+ - Seat names are canonical and unique across organisations.
29
+ - The server no longer passes a privileged secret to the backend as a function argument; the backend authorises it by identity.
34
30
 
35
- ## [Unreleased]
31
+ ## Changes between 2.18.0 and 3.0.0 (some shipped in 2.19.0)
36
32
 
37
33
  ### Added
38
34
 
39
- - **B5 KB ingest MCP tools** — `store_document_chunked` and `soft_delete_document` registered via `mcp-server/src/tools/kbIngest.ts`. `store_document_chunked` accepts `storageId` + `mimeType` + `filename` (+ optional `docId`) and proxies to `kb:storeDocumentChunked`; returns `{ docId, chunkCount, storageId }`. `soft_delete_document` accepts `docId` and proxies to `kb:softDeleteDocument`; returns `{ docId, markedCount }`. Both tools require Clerk JWT with `org_id` — no anonymous access. Exported: `STORE_DOCUMENT_CHUNKED_TOOL_DESCRIPTION`, `storeDocumentChunkedArgsSchema`, `SOFT_DELETE_DOCUMENT_TOOL_DESCRIPTION`, `softDeleteDocumentArgsSchema`. Mission `k5779qbxhwrfjmj02t31yvehns8911jp`, task `k17bdmhr2hffhz2t96p65j70nh891wcp`.
35
+ - `fail_task`: a third terminal task state, `failed`, distinct from `done` and `cancelled`, with a mandatory failure note. `update_task` cannot set `failed` or `blocked`; use `fail_task` and `block_task`.
36
+ - `block_task` accepts an optional `blockedCause` (`peer_task`, `human`, `authorisation` or `other`, default `other`) naming what the task is waiting on, and always returns it.
40
37
 
41
- ## [Unreleased] — B4 RAG namespace team/<orgId> tenant enforcement
38
+ ### Fixed
42
39
 
43
- ### Added
44
-
45
- - **`team-member` scope profile** in `bearerAuthMiddleware` (layer 2.5): Clerk JWTs carrying an `org_id` claim are now verified against the Clerk JWKS (`CLERK_DOMAIN/.well-known/jwks.json`, cached 10 min) and resolve to `scopeProfile="team-member"` with `namespaceReadPrefixes=["team/<orgId>"]` and `namespaceWritePrefixes=["team/<orgId>"]`. Cross-tenant reads/writes are rejected by the existing `checkNamespaceRead` / `checkNamespaceWrite` predicates before any Convex call.
46
- - **`convex/memoriesScoped.ts`**: new `listMemoriesScoped` (query) and `storeMemoryScoped` (mutation) Convex functions that enforce `team/<orgId>` namespace isolation at the Convex layer using `ctx.auth.getUserIdentity()`. Clerk callers with `org_A` cannot read or write `team/org_B/*`.
47
- - **`jose`** (transitive, already present via `@modelcontextprotocol/sdk`) used for JWKS fetch and JWT verification. No new npm dep.
48
- - **`CLERK_DOMAIN` env var**: override the Clerk instance domain (default `https://sharp-sponge-67.clerk.accounts.dev`).
40
+ - `list_peers` and `list_mandates` no longer turn a backend refusal into an empty list. A refusal is returned as an error result that starts with `REFUSED (RBAC_DENIED)` and names the tool; a genuinely empty result is still `[]`.
41
+ - `check_messages` shows how many in-progress tasks are stuck past the configured threshold, and renders the stuck lists correctly against both older and newer backends.
49
42
 
50
43
  ### Security
51
44
 
52
- - Architectural choice: **Option A** (direct Clerk JWT verification in bearer middleware) over Option B (DCR→Clerk join via Convex query). Rationale: Clerk JWTs are self-contained — no extra Convex round-trip needed. Option B would be required only if DCR clients were the sole entry point.
53
- - Cross-tenant deny preserved for DCR `client-generic` (empty prefixes, unchanged) and unregistered orgs (fail-closed: `AUTH_NAMESPACE_DENIED`).
54
-
55
- ### Tests
45
+ - An identity named on a mission (pilot or agent), a mandate (requester or fulfiller) or a task (assignee) can read that record, while still being unable to read records it is not named on.
46
+ - Clerk session tokens are checked for the expected audience (`CLERK_JWT_AUDIENCE`, default `convex`), so a token minted for another audience is refused.
56
47
 
57
- - `mcp-server/test/team-namespace-cross-tenant.test.ts` — 16 predicate tests on `checkNamespaceRead/Write/isMasterScope` with team-member, master, and DCR-generic fixtures.
58
- - `convex/__tests__/auth-namespace-deny.test.ts` — 9 convex-test tests verifying `AUTH_NAMESPACE_DENIED` for cross-tenant access at the Convex layer.
59
-
60
- ## [2.12.0] — 2026-06-14
48
+ ## [2.18.0] — 2026-08-11
61
49
 
62
50
  ### Changed
63
- - `check_messages` now calls `messages:checkNewMessagesEnvelope` (Convex PR #759 mergeCommit `c03023fc85463fe16fc53948d3002420bc1c4547`) for bounded tool-response size. New optional `limit` arg (1-50, default 20). When the call is truncated, the text payload appends `— truncated. Resume with check_messages since=<nextSince>` so the orchestrator can page the backlog cleanly without busting Claude Code's tool-response cap.
64
- - `since` arg description amended with a "pair with `nextSince` from a previous truncated reply" hint.
65
-
66
- ### Notes
67
- - Closes Pi BLOCKER VP task `k1702xaahb` (Day 102 — sigma-vps cron crash on a 36-message / 53 KB backlog).
68
- - Legacy `messages:checkNewMessages` Convex query left intact for vp-mcp <2.12.0 callers (no break).
69
-
70
- ## [2.11.0] — 2026-06-14 — Day 102 CRUD baseline PR-C-bis option B: 3-entity Convex searchIndex (mission k575kc1ryps0n8br95jw3q7d0x88m2v9)
71
-
72
- Mission `mcp-crud-baseline-standard` PR-C-bis under T2. Pi-sequenced follow-up after PR-C (rename-only safe subset) — implements **option B SCOPED** per Pi arbitrage msg `jn7abynmghy5qdr9ga0b914wmh88n99w` ("GO option B SCOPED — démarre PR-C avec 3 entités prioritaires"): tasks + messages + briefingNotes get native Convex BM25 search via `.searchIndex()` schema additions + per-entity Convex queries + MCP tool wrappers.
73
-
74
- Backend choice (B over A): Convex native `.searchIndex()` is BM25-only, no embeddings, no RAG per-entity pipeline. Sub-linear scan stays in the same backend without spinning up an embedding pipeline per table. Hybrid/semantic per entity remains a future RFC.
75
-
76
- ### Added — Convex schema searchIndex (3 tables)
77
-
78
- - `tasks` → `searchIndex("search_title", { searchField: "title", filterFields: ["assignedTo", "status", "project", "missionId", "orgId"] })`
79
- - `messages` → `searchIndex("search_content", { searchField: "content", filterFields: ["from", "channel", "sessionDay", "tenantId"] })`
80
- - `briefingNotes` → `searchIndex("search_content", { searchField: "content", filterFields: ["topic", "createdBy", "orgId"] })`
81
-
82
- ### Added — Convex query functions
83
-
84
- - `tasks:searchTasksByKeyword` — BM25 over title with assignedTo/status/project/missionId filters + scope gate via `withOrgScope` + `filterByOrgScope` + `requireScope("view-own-tasks")`. Lite/full projection.
85
- - `messages:searchMessagesByKeyword` — BM25 over content with from/channel/sessionDay/tenantId filters.
86
- - `briefingNotes:searchBriefingNotesByKeyword` — BM25 over content with topic/createdBy filters.
87
-
88
- All three: 20-item default limit, 200 cap, lite projection on demand.
89
-
90
- ### Added — MCP tool wrappers (3 canonical)
91
-
92
- - **`search_tasks_by_keyword`** — wires to `tasks:searchTasksByKeyword`. `readOnlyHint=true`.
93
- - **`search_messages_by_keyword`** — wires to `messages:searchMessagesByKeyword`. `readOnlyHint=true`.
94
- - **`search_briefing_notes_by_keyword`** — wires to `briefingNotes:searchBriefingNotesByKeyword`. `readOnlyHint=true`.
95
-
96
- ### Why option B (and why scoped to 3)
97
-
98
- `grep searchIndex convex/schema.ts` previously returned zero hits; only `memories` had search infrastructure (via `@convex-dev/rag`). The original "13-entity cluster" full scope was deferred via PR-C (rename-only) after arbitrage timeout. Pi's arbitrage landed shortly after: **option B SCOPED to 3 priority entities** is the right blend of doctrine progress + bounded scope:
99
- - `tasks` — largest fleet audience (Eta T13 close-issue scan, dispatch-task-find, etc.).
100
- - `messages` — post-incident audit + messages-history skill demand.
101
- - `briefingNotes` — daily snapshot recall narrative.
102
-
103
- The remaining 10 entities (mission/mandate/fix_pattern/component/repo_mapping/bu/profile/deployment/diary/error/issue/recurring_task/summary) go to a per-entity RFC (mission walk-through scheduled Wed 17 June 15h with Laurent) — each entity decides B (searchIndex), A (RAG if semantic justified, e.g. episodes/diary), or N/A semantic documented (deployment/repo_mapping).
104
-
105
- ### Version sync
106
-
107
- - `mcp-server/server.ts:115` SERVER_VERSION 2.10.0 → 2.11.0
108
- - `mcp-server/package.json` → 2.11.0
109
- - README + 4 cloud docs bumped to 2.11.0 markers (`enforce-release-sync` v1.0.1 gate).
110
-
111
- ### Test fixture catch-up
112
-
113
- - `READ_ONLY_TOOLS` set in `mcp-server/src/__tests__/chatgpt-tool-annotations.test.ts` extended with the 3 new canonical tool names.
114
-
115
- ### Refs
116
-
117
- - Mission `k575kc1ryps0n8br95jw3q7d0x88m2v9`.
118
- - Pi sequencing dispatch: msg `jn76360ckrrkwpqbfwa6tst7k588mpsh` ("(1) T2 PR-C-bis option B SCOPED 3 entities").
119
- - Pi arbitrage that selected option B: msg `jn7abynmghy5qdr9ga0b914wmh88n99w`.
120
- - Audit T1: `analysis/mcp-crud-baseline-vp-audit-2026-06-14.md` rows 1 (task), 3 (message), 4 (briefing_note).
121
- - Doctrine memory: `j57dhrmkzjerjtssnr0z9ba57n88n7q7` (5 ops per entity).
122
- - Predecessors: PR-A 2.8.0 (memories canonical), PR-B 2.9.0 (episode 5-op), PR-C 2.10.0 (rename-only safe subset).
123
-
124
- ## [2.10.0] — 2026-06-14 — Day 102 CRUD baseline PR-C: rename-only safe subset (mission k575kc1ryps0n8br95jw3q7d0x88m2v9)
125
-
126
- Mission `mcp-crud-baseline-standard` PR-C under T2. Third of 4 sub-PRs aligning the MCP surface with the Day 101 doctrine `j57dhrmkzjerjtssnr0z9ba57n88n7q7`. Sigma autonomous default after arbitrage timeout on the original "13-entity search_by_keyword cluster" scope — that fuller scope requires a backend search-infrastructure decision (RAG-index per entity vs Convex `.searchIndex()` per table) that is NOT a thin-wrapper PR. PR-C ships the rename-only safe subset now to keep doctrine velocity; the full cluster is deferred to a backend-RFC mission.
127
-
128
- ### Added (2 canonical search tools)
129
-
130
- - **`search_components_by_keyword`** — BM25 / substring search over components by name or team. Wire-identical to `search_components` (same Convex query `components:search` 1:1, same scope filter, same defaults). `readOnlyHint=true`.
131
- - **`search_fix_patterns_by_semantic`** — semantic embedding-similarity search over fix patterns. Wire-identical to `search_fix_patterns` (same Convex action `search:searchFixPatterns` 1:1, same scope filter, same defaults). `readOnlyHint=true`. Note: the canonical suffix is `_by_semantic` (NOT `_by_keyword`) because the underlying ranker is embedding-cosine, not BM25 — naming follows behavior, not entity convention.
132
-
133
- ### Deprecated (alias-only, removal target 2.11.0)
134
-
135
- - **`search_components`** — alias of `search_components_by_keyword`. Description leads with `DEPRECATED ALIAS …`.
136
- - **`search_fix_patterns`** — alias of `search_fix_patterns_by_semantic`. Description leads with `DEPRECATED ALIAS …`.
137
-
138
- ### Re-targeted deprecations (FOLLOW-UP from Eta PR #750 review)
139
-
140
- - **`text_search`** — 2.8.0 originally targeted removal at 2.9.0; episode-only PR-B did not include the removal. Source comments + this entry re-target removal to **2.11.0**.
141
- - **`recall`** — same re-target rationale, removal now **2.11.0**.
142
-
143
- Both `text_search` and `recall` remain wire-identical to their canonical successors (`search_memories_by_keyword` / `search_memories_by_semantic`). Closes FOLLOW-UP task `k1754apqtcjpre2vd5ghbkcmzn88mhwf`.
144
-
145
- ### Scope NOT in this PR (deferred)
146
-
147
- The original PR-C "13-entity search_by_keyword cluster" required adding BM25 / search infrastructure to 10+ entities that currently have NO backend search index (`grep searchIndex convex/schema.ts` → zero hits; only `memories` is indexed, via `@convex-dev/rag`). Two backend paths exist:
148
-
149
- - **Path A** — extend RAG indexing to each entity (heavy: per-table embedding pipeline, RAG namespace per entity, vector cost; gets hybrid search for free).
150
- - **Path B** — Convex native `.searchIndex()` per table (lightweight: schema migration + one query per entity, BM25-only, no embeddings).
151
-
152
- Either path is a multi-day backend RFC, NOT a thin-wrapper PR. Sigma sent the arbitrage to Pi (msg `jn75zy4g7bhj95bhyz2zvv6n8d88na6s`) and defaulted to PR-C path C (rename-only) after 2 cron ticks of no reply. A follow-up mission to scope the backend search infrastructure is the next mission proposal.
153
-
154
- ### Version sync
155
-
156
- - `mcp-server/server.ts:115` SERVER_VERSION 2.9.0 → 2.10.0
157
- - `mcp-server/package.json` → 2.10.0
158
- - README + 4 cloud docs bumped to 2.10.0 markers (`enforce-release-sync` v1.0.1 gate).
159
-
160
- ### Test fixture catch-up
161
-
162
- - `READ_ONLY_TOOLS` set in `mcp-server/src/__tests__/chatgpt-tool-annotations.test.ts` extended with the 2 new canonical names.
163
-
164
- ### Refs
165
-
166
- - Mission `k575kc1ryps0n8br95jw3q7d0x88m2v9` (MCP CRUD Baseline Standard).
167
- - Pi authorization msg `jn74q7twhr3s1s8dvqxbzvky9588msdd` ("next: T2-PR-C 13-entity search_by_keyword cluster post #750 merge").
168
- - Sigma arbitrage msg to Pi: `jn75zy4g7bhj95bhyz2zvv6n8d88na6s` (3 paths A/B/C).
169
- - FOLLOW-UP task: `k1754apqtcjpre2vd5ghbkcmzn88mhwf` (text_search/recall deprecation slipped).
170
- - Audit T1: `analysis/mcp-crud-baseline-vp-audit-2026-06-14.md` § 4.
171
-
172
- ## [2.9.0] — 2026-06-14 — Day 102 CRUD baseline PR-B: episode entity 5-op surface (mission k575kc1ryps0n8br95jw3q7d0x88m2v9)
173
-
174
- Mission `mcp-crud-baseline-standard` PR-B under T2. Second of 4 sub-PRs aligning the MCP surface with the Day 101 doctrine `j57dhrmkzjerjtssnr0z9ba57n88n7q7` ("5 ops per entity"). PR-B adds the missing read/list/search facades for the `episode` entity, completing the 5-op surface (the write side `store_episode` already existed since the 8-Sins doctrine).
175
-
176
- Architectural note: episodes are NOT a separate Convex table — per hotfix `7f958d0`, episodes are stored as memories with `type='episode'` (context/goal/action/outcome/insight + severity). The 4 new tools are thin wrappers that force `type='episode'` on the existing `memories:*` / `search:*` actions, so callers get an ergonomic episode-scoped surface without introducing a new backend table or duplicating index logic.
177
-
178
- ### Added (4 canonical episode tools)
179
-
180
- - **`get_episode`** — fetch a single episode by memory ID. Calls `memories:getMemory` then asserts the returned row has `type='episode'`; otherwise returns a non-leaky "Episode not found" so wrong-type IDs do not leak existence of non-episode memories. Scope-aware via `scopeFilterGet`. Annotations: `readOnlyHint=true`, `openWorldHint=false`, `destructiveHint=false`.
181
- - **`list_episodes`** — list episodes ordered newest first. Calls `memories:listMemories` with `type='episode'` forced. Accepts `namespace?`, `createdBy?`, `limit?`, `fields?`, `cursor?` — same paging semantics as `list_memories`. Scope-aware via `scopeFilterList`. Envelope-capped via `capListResponseBytes("list_episodes")`.
182
- - **`search_episodes_by_keyword`** — BM25 search restricted to episodes. Calls `search:textSearch` with `type='episode'` forced. Same `guardRead` namespace gate, same 20-default / 200-cap limits.
183
- - **`search_episodes_by_semantic`** — semantic vector cosine search restricted to episodes. Calls `search:recall` with `type='episode'` forced. Same gate, same limits.
184
51
 
185
- All four are pure MCP-layer additions: no Convex schema change, no new index, no new action. tsc clean.
52
+ - The server advertises only its core tool set, listed in `tool-exposure.json`. The other tools stay in the code but are disabled: a client can neither list nor call them. The server refuses to start if that file names a tool that does not exist.
186
53
 
187
- ### Why
188
-
189
- Episode = the 8-Sins / orchestrator-introspection memory type (severity + context/goal/action/outcome/insight). Until 2.9.0, recalling past episodes required `recall query='...' type='episode'` — discoverable only to callers who already knew the memory-side filter trick. Surfacing dedicated wrappers makes the episode lifecycle (write via `store_episode`, read via `get_episode`, browse via `list_episodes`, recall via the two search ops) consistent with the doctrine and self-documenting in any MCP client's tool list.
190
-
191
- `hybrid_search` remains entity-agnostic and is NOT mirrored for episodes (cross-cutting RRF tool per audit § 4).
192
-
193
- ### Test fixture catch-up
194
-
195
- - `READ_ONLY_TOOLS` set in `mcp-server/src/__tests__/chatgpt-tool-annotations.test.ts` extended with the 4 new tool names.
196
-
197
- ### Refs
198
-
199
- - Mission `k575kc1ryps0n8br95jw3q7d0x88m2v9` (MCP CRUD Baseline Standard, pilot Sigma + agents Sigma + Eta).
200
- - Pi authorization msg `jn74v2pkfz08agex4nfm2yfvfd88nzdw` — "chain T2 PR-B episode entity en autonomie scope mission".
201
- - Audit T1 deliverable: `analysis/mcp-crud-baseline-vp-audit-2026-06-14.md` row 7 (episode entity recommendation: add façade wrappers).
202
- - Architecture: hotfix `7f958d0` — episodes are memories with metadata, not a separate table.
203
-
204
- ## [2.8.0] — 2026-06-14 — Day 101 CRUD baseline PR-A: search_memories_by_keyword + search_memories_by_semantic (mission k575kc1ryps0n8br95jw3q7d0x88m2v9, task k1735qk9kx6agjjyt3e38rdvvh88mk0p)
205
-
206
- Mission `mcp-crud-baseline-standard` PR-A under T2 `[CRUD-T2] Implémentation gaps VP MCP`. First of 4 sub-PRs aligning the MCP surface with the Day 101 doctrine `j57dhrmkzjerjtssnr0z9ba57n88n7q7` ("5 ops per entity: get / list / search_by_keyword / search_by_semantic / create-or-upsert"). PR-A handles the convention drift on the `memories` entity — the only entity that already had both keyword + semantic search wired, but under non-canonical names.
207
-
208
- ### Added (canonical names)
209
-
210
- - **`search_memories_by_keyword`** — BM25 full-text search over memories, identical wire to `text_search`. Calls `search:textSearch` Convex action 1:1, same params (`query`, `namespace?`, `type?`, `limit?`, `fields?`), same `guardRead` namespace gate, same 20-item default limit + 200 cap, same `mcpConvexError` error surface (2.7.1 sweep). Annotations: `readOnlyHint=true`, `openWorldHint=false`, `destructiveHint=false`, title `"Search memories by keyword (BM25)"`.
211
- - **`search_memories_by_semantic`** — semantic vector cosine search over memories, identical wire to `recall`. Calls `search:recall` Convex action 1:1, same params, same gate, same defaults. Annotations: `readOnlyHint=true`, `openWorldHint=false`, `destructiveHint=false`, title `"Search memories by semantic (vector cosine)"`.
212
-
213
- ### Deprecated (alias-only, one minor window)
214
-
215
- - **`text_search`** — alias of `search_memories_by_keyword`. Description now leads with `DEPRECATED ALIAS`, source comment marks it for removal in `2.9.0`. Wire unchanged — existing callers continue to work for one minor.
216
- - **`recall`** — alias of `search_memories_by_semantic`. Description now leads with `DEPRECATED ALIAS`, source comment marks it for removal in `2.9.0`. Wire unchanged.
217
-
218
- ### Why
219
-
220
- Per mission `k575kc1r` brief + Pi arbitrage `jn77rpx2msfy2v174sdqyjzp6n88m9bw` Q4 (RENAME CLEAN, optional one-minor dual-emit buffer if Sigma judges useful): the legacy `text_search` / `recall` pair predates the Day 101 CRUD baseline naming convention. Other entities will gain `search_<entity>s_by_keyword` / `search_<entity>s_by_semantic` in PR-C (cluster of 13) and PR-D (vectorIndex add for briefing_notes + diary). Aligning the `memories` entity FIRST means PR-C/D ship into a fleet that already understands the new naming, and skill / plugin / docs propagation (T-SKILLS, T-PLUGIN, T-DOC) has a single canonical truth to follow.
221
-
222
- `hybrid_search` is intentionally NOT renamed — it remains a cross-cutting RRF-fusion tool, not entity-scoped, per the audit `analysis/mcp-crud-baseline-vp-audit-2026-06-14.md` § 4.
223
-
224
- ### Refs
225
-
226
- - Mission `k575kc1ryps0n8br95jw3q7d0x88m2v9` (MCP CRUD Baseline Standard, pilot Sigma + agents Sigma + Eta).
227
- - Task T2 `k1735qk9kx6agjjyt3e38rdvvh88mk0p`.
228
- - Audit T1 deliverable: `analysis/mcp-crud-baseline-vp-audit-2026-06-14.md` (140 lines, 53 table rows).
229
- - Doctrine memory: `j57dhrmkzjerjtssnr0z9ba57n88n7q7` (5 ops per entity).
230
- - Pi Q4 arbitrage: msg `jn77rpx2msfy2v174sdqyjzp6n88m9bw`.
231
-
232
- ## [2.7.1] — 2026-06-14 — Day 101 FIX-B mcpError() → mcpConvexError() sweep (task k1744wk2gfgqt2gdqh41d4r91h88n410)
233
-
234
- Patch-level fix to make every tool wrapper surface structured ConvexError
235
- diagnostics instead of opaque `"Server Error [Request ID: ...]"` strings.
236
-
237
- **Problem (Day 101):** when a Convex mutation/query threw a `ConvexError`
238
- (e.g. `TASK_START_BLOCKED`, `COMPLETION_NOTE_REQUIRED`) or an
239
- `ArgumentValidationError`, the tool wrapper called
240
- `mcpError(error.message ?? String(error))` which returned a plain
241
- `Error: <message>` text payload. The MCP client (Claude Code) then often
242
- re-displayed this as a generic `Server Error [Request ID:...]`, masking the
243
- actual root cause and triggering misdiagnosis sprees (Pi msg
244
- `jn7c5tfj0347vaenyqgrezehk188mr11` mistakenly attributed the symptoms to
245
- a backend regression that did not exist — see Sigma report msg
246
- `jn773p8qnfp6ycb1f7gajhs8vn88m11a`).
247
-
248
- **Fix:** sweep all 99 occurrences of
249
- `return mcpError(error.message ?? String(error))` →
250
- `return mcpConvexError(error)`. The `mcpConvexError` helper (already
251
- present at `src/tools.ts:535`, shipped 2.4.x) parses ConvexError messages
252
- into a structured JSON `{ code, message, path, hint }` payload that
253
- surfaces the actual error code (`ArgumentValidationError`,
254
- `ConvexError`, `AuthorizationError`, `SchemaValidationError`, etc.)
255
- along with a path and a concise hint for ID-table mismatches.
256
-
257
- Total counts post-sweep: `grep mcpConvexError(` → 102 ; `grep
258
- mcpError(error.message` → 0.
259
-
260
- Type check: `npx tsc --noEmit` exits 0.
261
-
262
- Mission/refs: `k575kc1ryps0n8br95jw3q7d0x88m2v9` MCP CRUD Baseline Standard,
263
- task FIX-B `k1744wk2gfgqt2gdqh41d4r91h88n410`. Co-shipped with hook
264
- `enforce-friction-field.py` v1.1.0 STDERR clarification (Day 101 task
265
- FIX-A `k17ads7kh7qk7yxgfe0dh73ggx88ny9f`).
266
-
267
- ## [2.7.0] — 2026-06-13 — Day 100 get_by_id surface Phase 2b (task k172735brsw6bc3j2dkkkfxqrx88kkjq)
268
-
269
- Phase 2b wires 2 MCP wrappers calling the Phase 2a Convex queries deployed
270
- in commit 2ebdaba (PR #735 + hotfix 7f958d0):
271
-
272
- - **get_message** — `messages:getById` plumbing. Fetch full message row by
273
- Convex doc ID (channel, sender, sessionDay, tenant scope) for read-receipt
274
- audit, delete confirmation, or fix-pattern referencing.
275
- - **get_recurring_task** — `recurringTasks:getById` plumbing. Fetch
276
- recurring task definition (cron schedule, prompt, assignee, last-fire
277
- metadata) before pause/update/delete.
54
+ ## [2.17.0] — 2026-08-11
278
55
 
279
- Both follow the existing `get_memory` / `get_briefing_note` pattern:
280
- `scopeFilterGet(oauthCtx, row)` for scope-aware cross-tenant collapse,
281
- read-only annotations.
56
+ ### Removed
282
57
 
283
- **get_episode** was DROPPED from Phase 2b scope: episodes are stored as
284
- memories with episode metadata (no separate `episodes` table in
285
- `convex/schema.ts`). Use existing `get_memory` to fetch episode rows by
286
- their memory document ID. Hotfix 7f958d0 removed the invalid
287
- `episodes:getById` query that broke `convex deploy` typecheck.
58
+ - 14 duplicate alias tools were removed; the canonical tool of each pair remains.
288
59
 
289
- Phase 2a CHANGELOG entry deferred — Convex changes shipped in main repo
290
- CHANGELOG, not mcp-server.
60
+ ## Changes between 2.12.0 and 2.17.0
291
61
 
292
- Total MCP `get_*` tools after Phase 2b: 16 (was 14 after Phase 1, 10 before
293
- Day 100 task).
62
+ ### Added
294
63
 
295
- ## [2.6.0] — 2026-06-13 — Day 100 get_by_id surface Phase 1 (task k172735brsw6bc3j2dkkkfxqrx88kkjq)
64
+ - Knowledge-base ingest: `store_document_chunked` (chunk and index a file previously uploaded to storage; returns `{ docId, chunkCount, storageId }`) and `soft_delete_document`. Both require an organisation-scoped Clerk session.
65
+ - Clerk session tokens carrying an organisation claim are verified against Clerk's published keys and scoped to that organisation's `team/<orgId>` namespace for reads and writes. A token for an organisation that is not registered is refused.
296
66
 
297
- Pi reported get_<entity>_by_id MCP surface gaps observed during Day 100 fleet ops.
298
- Phase 1 adds 4 plumbing-only read tools mapping to pre-existing Convex queries:
67
+ ### Security
299
68
 
300
- - **get_task** — `tasks:getById` plumbing. Fetch full task record (description, dependsOn,
301
- missionId, completionNote, claimedByInstance, startedAt) by Convex doc ID.
302
- - **get_fix_pattern** — `fixPatterns:get` plumbing. Fetch fix pattern with full linked
303
- fix attempts history.
304
- - **get_mandate** — `mandates:get` plumbing. Fetch spending mandate with limits, current
305
- spend, approver chain for validateSpending/settleMandate pre-checks.
306
- - **get_repo_mapping** — `githubRepoMapping:getByRepo` plumbing. Fetch GitHub repo→VP project
307
- mapping by repo slug.
69
+ - `list_messages`, `search_messages_by_keyword`, `search_tasks_by_keyword`, `get_profile`, `list_peers`, `get_message`, `list_mandates` and `get_mandate` return only rows the caller owns or is a party to. Previously some of them refused every scoped caller, including the owner.
70
+ - Operations tools with no customer owner (error logs, issue tracking, repository mappings) are restricted to the service operator; other callers receive an explicit refusal instead of an empty list.
71
+ - Cross-organisation reads and writes in another team's namespace are refused.
308
72
 
309
- All 4 tools apply `scopeFilterGet(oauthCtx, row)` for scope-aware cross-tenant collapse,
310
- mirroring the existing `get_memory` / `get_briefing_note` pattern (Day 92 S3.1 wave).
73
+ ## 2.14.2 — 2026-06-30
311
74
 
312
- Annotations test (chatgpt-tool-annotations.test.ts) READ_ONLY_TOOLS set extended with
313
- the 4 new tools. Pre-existing 84/97 count mismatch in same test is unrelated (separate
314
- F-list track).
75
+ ### Fixed
315
76
 
316
- Phase 2 (follow-on PR) will add get_message / get_episode / get_recurring_task
317
- (Convex query additions required).
318
- Phase 3 (separate mission) will audit deployment entity (table+queries+tool) and the
319
- cross-backend cloud proxy redeploy cadence.
77
+ - OAuth dynamic client registration (`/register`) rejects a missing, empty or malformed `redirect_uris` with `invalid_redirect_uri` (RFC 7591).
320
78
 
321
- ## [2.5.0] — 2026-06-06 — Day 92 VP MCP quality overhaul (mission k57a36y8)
79
+ ## [2.12.0] — 2026-06-14
322
80
 
323
- Day 92 mission `k57a36y8w5t085bqr23dsmvb2d882506` ships a fleet-wide VP MCP quality bump
324
- across audit, docs, hooks, security, and consistency dimensions. 15 PRs merged to main.
325
-
326
- ### Phase A — Audit + new tools
327
- - **A1** Day 92 VP MCP tools audit matrix (85 tools, 14 P0 zero-auth gaps) — `docs/test-reports/day92-vp-mcp-audit-matrix.md`.
328
- - **A2** Consistency analysis report — `docs/test-reports/day92-vp-mcp-consistency-analysis.md`.
329
- - **A3** New `whoami` LECTURE tool — first per-tool `outputSchema` export precedent.
330
- - **A4** Consolidated gap matrix — `docs/test-reports/day92-vp-mcp-gap-matrix-consolidated.md`.
81
+ ### Changed
331
82
 
332
- ### Phase B — Documentation
333
- - **B1** `docs/cloud/security-multi-tenant.md` §4 scope-aware filter framework rewrite.
334
- - **B2** `docs/cloud/tools-quality-standard.md` (NEW) — 12-section bilingual quality standard.
335
- - **B3** `docs/cloud/onboarding-customer.md` (NEW) — customer onboarding guide (bilingual FR+EN).
336
-
337
- ### Phase C — Consistency
338
- - **C0** 14 P0 zero-auth write tools secured with `guardMasterOnly` (C0.1 → C0.6, 6 PRs).
339
- - **C1** 87 Zod `outputSchema` exports per per-family envelope standard (B2 §3).
340
- - **C2** Orchestrator-id NFC normalization + case-insensitive matching; idempotent prod migration `convex/migrations/c2-normalize-orchestrator-ids.ts` (7 tables).
341
- - **C3** 97 tool descriptions standardized + 10 canonical aliases gated through `guardMasterOnly` (security regression fixed in iter 2) + alias-c0-gate-coverage test (15/15 PASS).
342
- - **C4** Legacy `claude-peers` references removed repo-wide + `grep-gate` CI workflow.
83
+ - `check_messages` returns a bounded page of messages. New optional `limit` (1–50, default 20). When more messages are waiting, the reply ends with the `since` value to pass on the next call.
343
84
 
344
- ### Phase F — Hooks + plugin
345
- - **F1** New consolidated `validate_task_payload` MCP tool + TypeScript validator library (replaces 5 single-axis hooks).
346
- - **F2** Plugin propagation runbook + `plugin-vs-workspace-hooks.md` doctrine.
85
+ ## [2.11.0] — 2026-06-14
347
86
 
348
- ### Scope-aware filtering
349
- - `list_tasks` `fromAllowList[]` + case-insensitive matching (PR #654, #661).
350
- - 3 admin endpoints reinstated for Nadia cohort (prior session).
87
+ ### Added
351
88
 
352
- ### Tenant trio
353
- - Persistent test tenant trio (alpha/beta/gamma) seeded on prod with bearers, scope_profiles, and seed data for cross-orchestrator E2E.
89
+ - Keyword (BM25) search over tasks, messages and briefing notes: `search_tasks_by_keyword`, `search_messages_by_keyword`, `search_briefing_notes_by_keyword`. Default 20 results, maximum 200, compact projection available.
354
90
 
355
- ### Deploy authorization
356
- - `PI_AUTHORIZED_TASK_ID=k1751nfs27t9f9mpvg3ppd6xad884r59` (Day 82 doctrine).
357
- - Mission: `k57a36y8w5t085bqr23dsmvb2d882506`.
358
- - Branch: `release/v2.5.0` opened against `main` at HEAD `18a5530`.
91
+ ## [2.10.0] — 2026-06-14
359
92
 
360
- ## [2.4.13] — 2026-06-02 — Post-public republish: attribution + CHANGELOG day-numbers + RULE #7 narrative scrub
93
+ ### Added
361
94
 
362
- Repository visibility flip to PUBLIC on 2026-06-02 (mission D62 `k57e4t21sr55rhz8ng554eseb987wvh3`). This patch republishes the npm package so the published README + CHANGELOG + attribution match the now-public source.
95
+ - `search_components_by_keyword` and `search_fix_patterns_by_semantic` as the canonical names of `search_components` and `search_fix_patterns`.
363
96
 
364
- No runtime / API / schema changes. Documentation + metadata only.
97
+ ### Deprecated
365
98
 
366
- What changed since v2.4.12:
367
- - `mcp-server/package.json`: author restructured to "VantageOS AI Orchestrator Team" with contributors block (Pi, Laurent Perello, ElPi Corp). Dependency `@vantageos/mosaic@^0.1.2` added for Phase 1 Mosaic groundwork (PR #605, server-side createMosaicResource API ready for Phase 2 primitive swap).
368
- - `mcp-server/CHANGELOG.md`: version headers simplified to `X.Y.Z — YYYY-MM-DD` (Day N anchors dropped per Laurent verdict 2026-06-02 — dates are self-explanatory, day numbers added noise). Narrative client-name mentions (Nadia/<client-org>/Cédric Delport) genericized to "early-access RH cohort" / "self-host incident" per RULE #7 pre-public scrub.
369
- - Root README rework (PR #611 + PR #610 + PR #616 chain): TL;DR + Mermaid architecture diagram + 5 hero features + 22-features collapsed details + 84-tools 8-groups + Backend: Convex 3-paths + attribution Credits section. README /team 404 hotfix landed in PR #616.
99
+ - `search_components` and `search_fix_patterns`, kept as aliases of the canonical names. The removal of `text_search` and `recall` was moved to 2.11.0.
370
100
 
371
- Merged PRs in this republish window:
372
- - PR #611 (`9464f9a`) — T5ter README rework + CHANGELOG day-numbers + attribution
373
- - PR #615 (`c189a1d`) — Phase 1 RULE #7 pre-public scrub
374
- - PR #616 (`99eeae5`) — README /team 404 hotfix
101
+ ## [2.9.0] — 2026-06-14
375
102
 
376
- Mission: D62 pre-public cleanup `k57e4t21sr55rhz8ng554eseb987wvh3`.
377
- Friction capitalize: `post-public-flip-must-trigger-npm-republish-for-consistency-not-just-repo-visibility-flip` + `day-79-hook-should-validate-tree-not-commit-sha`.
103
+ ### Added
378
104
 
379
- ## [2.4.0] — 2026-05-29 — M3 iframeEmbedSessions + __VP_TOOL_RESULT__ stream marker + ack-checklist
105
+ - Episode tools: `get_episode`, `list_episodes`, `search_episodes_by_keyword`, `search_episodes_by_semantic`. Episodes are memories of type `episode`; these tools are shortcuts that apply that type for you. An ID that is not an episode returns "Episode not found".
380
106
 
381
- **Mission instance** : `sigma-vantage-peers-mcp-gui-iframe-embed-v1` (k5730xct6rvrwkvxhy5t5js12d87jwfw).
382
- **Pi sign-off** : PI_AUTHORIZED_TASK_ID=`k1793m1qgn0zaay6r87dhvsh7187kwya` (PROD-DEPLOY-AUTHORIZED).
383
- **Eta sign-off** : ETA_APPROVED_TASK_ID=`k171ep964sxabbrgmb21fk9axd87ka1n` at commit `338a7b9e6130ce69dc5fe7f3e2e9ecc4648b4f6a` (SHA-pinned).
384
- **Merge** : PR #545 squash `f509c8d92f0b142bc063a0e9dd070e1993cc729b`.
107
+ ## [2.8.0] — 2026-06-14
385
108
 
386
- M3 delivers the session registry and stream-marker protocol that connects the VP MCP server
387
- to the Gen UI iframe bridge. All marker emission is gated behind `VP_EMIT_UI_MARKERS=1`
388
- so production behaviour is unchanged until the bridge is deployed.
109
+ ### Added
389
110
 
390
- ### Convex schema — `iframeEmbedSessions` table
111
+ - `search_memories_by_keyword` (BM25) and `search_memories_by_semantic` (vector) as the canonical memory search tools.
391
112
 
392
- NEW table `iframeEmbedSessions` in `convex/schema.ts` :
393
- - Fields : `sessionId` (string), `tenantId` (optional string), `origin` (string),
394
- `userId` (optional string), `createdAt` (number), `lastSeenAt` (number),
395
- `expiresAt` (number), `revoked` (boolean).
396
- - Indexes : `by_session_id` on `["sessionId"]`, `by_origin_expires` on `["origin", "expiresAt"]`.
113
+ ### Deprecated
397
114
 
398
- NEW `convex/iframeEmbedSessions.ts` — 4 operations :
399
- - `createSession` mutation — inserts a new session row.
400
- - `getSession` query — returns session or null (null for expired / revoked).
401
- - `touchSession` mutation — bumps `lastSeenAt` to now; returns bool.
402
- - `revokeSession` mutation — sets `revoked=true`; returns bool.
115
+ - `text_search` and `recall`, kept as aliases of the two tools above with identical behaviour.
403
116
 
404
- ### Stream marker — `mcp-server/src/ui-resources/stream-marker.ts`
117
+ ## [2.7.1] — 2026-06-14
405
118
 
406
- NEW `MARKER_START = "__VP_TOOL_RESULT__"`, `MARKER_END = "__END__"`.
119
+ ### Fixed
407
120
 
408
- NEW `wrapToolResult(payload: VpToolResult): string` :
409
- - Validates via `VpToolResultSchema`, throws `TypeError` on schema failure.
410
- - Returns `__VP_TOOL_RESULT__<json>__END__`.
121
+ - Tool errors return a structured payload (`code`, `message`, `path`, `hint`) instead of an opaque "Server Error" string, so the real cause (for example a validation error) is visible to the client.
411
122
 
412
- NEW `parseToolResult(text: string): VpToolResult | null` :
413
- - Extracts marker substring (handles bare, embedded, surrounding text).
414
- - Returns validated `VpToolResult` or null on any failure (no-throw contract).
123
+ ## [2.7.0] — 2026-06-13
415
124
 
416
- ### MCP tools — marker emission gated by `VP_EMIT_UI_MARKERS=1`
125
+ ### Added
417
126
 
418
- `mcp-server/src/tools.ts` — 6 tools now append `wrapToolResult(...)` after the JSON payload
419
- when `VP_EMIT_UI_MARKERS=1` (default OFF) :
127
+ - `get_message` and `get_recurring_task`: fetch a single message or recurring task by ID, scoped to the caller.
420
128
 
421
- | Tool | kind |
422
- |-----------------------|--------------------|
423
- | `list_tasks` | `tasks-table` |
424
- | `list_messages` | `messages-feed` |
425
- | `get_diary` | `diary-entry` |
426
- | `list_missions` | `mission-timeline` |
427
- | `list_briefing_notes` | `briefing-note` |
428
- | `list_memories` | `memory-quote` |
129
+ ## [2.6.0] — 2026-06-13
429
130
 
430
- Change is surgical — existing return shape is preserved; marker is appended as a new line.
131
+ ### Added
431
132
 
432
- ### Ack checklist
133
+ - `get_task`, `get_fix_pattern`, `get_mandate` and `get_repo_mapping`: fetch a single record by ID, scoped to the caller.
433
134
 
434
- NEW `docs/M3-ACK-CHECKLIST.md` — bilingual FR/EN post-deploy verification checklist
435
- for the beta verifier cohort. Covers: package install, primitive reads, Shadow DOM scoping,
436
- stream marker emit + parse, bilingual spot check, WCAG AA (contrast + role attrs),
437
- default-OFF guard.
135
+ ## [2.5.0] — 2026-06-06
438
136
 
439
- ### Tests
137
+ ### Added
440
138
 
441
- 15+ new vitest cases (≥264 total after M3, baseline 253 after M2) :
442
- - `mcp-server/src/__tests__/m3-stream-marker.test.ts` — 14 cases:
443
- `wrapToolResult` ×6 valid kinds, ×2 throws on invalid, `parseToolResult` roundtrip,
444
- non-marker text ×2, embedded text, malformed JSON ×2, schema rejects unknown kind ×2.
445
- - `convex/iframeEmbedSessions.test.ts` — 7 cases:
446
- create+get, optional fields, getSession unknown, expired session null,
447
- touchSession updates lastSeenAt, touchSession unknown false,
448
- revokeSession marks revoked (getSession null), revokeSession unknown false.
139
+ - `whoami`: returns the identity attached to the current credential, so a client can discover its agent name instead of asking the user.
140
+ - `validate_task_payload`: checks a task or message payload against every validation rule at once and returns all failures together.
141
+ - Output schemas on tools, and standardised tool descriptions.
449
142
 
450
- 0 regression on M1+M2 suites (253/253 baseline).
143
+ ### Changed
451
144
 
452
- ---
145
+ - Agent names are Unicode-normalised and matched case-insensitively.
146
+ - `list_tasks` honours the caller's allowed agent names.
453
147
 
454
- ## [Unreleased] — M1 SEP-1865 ui:// resources backend + M2 primitives + Zod schemas
148
+ ### Security
455
149
 
456
- **Mission instance** : `sigma-vantage-peers-mcp-gui-iframe-embed-v1` (k5730xct6rvrwkvxhy5t5js12d87jwfw).
457
- **Template VR consumed** : `gui-iframe-embed-v1` v1.0.0 (jx7bzk0x1086tgwgj2zrssk2pn87k1ga).
150
+ - Write tools that previously required no authorisation are restricted to the service operator.
458
151
 
459
- M1 Foundation (adapted MCP-pure paradigm per Pi arbitrage 2026-05-28) :
460
- - NEW `mcp-server/src/ui-resources/index.ts` : URI parser `ui://vp/v1/<primitive>?<query>` + primitive registry + handler factory.
461
- - NEW `mcp-server/src/ui-resources/primitives/tasks-table.ts` : M1 MVP primitive returning HTML inline (Shadow DOM scoped CSS) — WCAG AA + bilingual FR+EN.
462
- - `mcp-server/server-http.ts` : wired `ListResourcesRequestSchema` + `ReadResourceRequestSchema` MCP handlers on the existing McpServer instance.
152
+ ## [2.4.13] — 2026-06-02
463
153
 
464
- Tests : 14 new vitest cases (`src/__tests__/ui-resources-sep-1865.test.ts`) — URI parsing, primitive registry, render variants (empty, populated, FR), backend arg forwarding, XSS escape, error fallback, limit clamping, unknown primitive rejection. 0 regression on existing suites.
154
+ ### Changed
465
155
 
466
- ### M2 — Resolve 5 Gaps + Bearer sha256 hardening (adapted MCP-pure paradigm)
156
+ - Documentation and package metadata only; no runtime change.
467
157
 
468
- 5 new ui:// primitives :
469
- - `messages-feed` (`messages:listMessages` backend — channel filter applied client-side)
470
- - `diary-entry` (`diary:get` single-entry + `diary:list` multi-entry backend)
471
- - `mission-timeline` (`missions:list` backend with fields=lite)
472
- - `briefing-note` (`briefingNotes:get` by noteId OR `briefingNotes:list` by topic backend)
473
- - `memory-quote` (`memories:listMemories` backend — supports both plain-array and paginated result shapes)
158
+ ## [2.4.0] — 2026-05-29
474
159
 
475
- Zod discriminated union schemas : `mcp-server/src/ui-resources/schemas.ts` exports `VpTaskPayloadSchema` + `VpMessagePayloadSchema` + `VpDiaryEntryPayloadSchema` + `VpMissionPayloadSchema` + `VpBriefingNotePayloadSchema` + `VpMemoryPayloadSchema` + `VpToolResultSchema` (discriminated union by `kind`). Cross-fleet ready for Mu vantage-bridge sidepanel S3 consumer.
160
+ ### Added
476
161
 
477
- Bearer sha256 validation : Already in place since v2.3.4 DCR security fix. `mcp-server/src/auth.ts` line 275 calls `sha256Hex(token)` before every Convex lookup (layers 2 and 4). Raw token never reaches Convex. No further hardening needed in M2.
162
+ - Optional UI result markers: with `VP_EMIT_UI_MARKERS=1` (off by default), `list_tasks`, `list_messages`, `get_diary`, `list_missions`, `list_briefing_notes` and `list_memories` append a machine-readable `__VP_TOOL_RESULT__…__END__` block after their normal output, for clients that render rich views. Output is unchanged when the variable is unset.
163
+ - Embedded-session registry backing those views.
478
164
 
479
- Tests : 42 new vitest cases in `src/__tests__/ui-resources-m2-primitives.test.ts` (target was ≥22). Covers : PRIMITIVES registry (6 entries), each of 5 new primitives (empty + populated + FR labels + XSS escape + error fallback = 5 cases each), Zod schema roundtrip (VpToolResultSchema all 6 variants accepted, malformed rejected, individual payload schema validations). 0 regression on M1 17 cases + 194 other MCP tests (253/253 total).
165
+ ## UI resources (released with 2.4.0)
480
166
 
481
- M3 next : Registry json-render + `__VP_TOOL_RESULT__<json>` stream marker + smoke E2E + ack-checklist + PI-SIGNED Convex prod deploy + visual ack from beta cohort verifiers.
167
+ ### Added
482
168
 
483
- ---
169
+ - `ui://vp/v1/<primitive>` MCP resources rendering tasks, messages, diary entries, missions, briefing notes and memories as accessible, bilingual (EN/FR) HTML fragments, with typed payload schemas.
484
170
 
485
171
  ## v2.3.5 — 2026-05-28
486
172
 
487
- **Critical hotfix** — v2.3.3 (PR #539) shipped the backend filters `createdBy` + `updatedSince` and the Zod schema exports but did NOT wire those params into the 4 list MCP tool args blocks. Pi pull-cycle quickstart `list_tasks createdBy="pi" status="review" fields="lite"` was silently dropping `createdBy` at the MCP boundary and returning all visible tasks. Auto-clamp safeguard (2026-05-27) also could not trigger because Zod `.default(50)` / `.default(20)` on `limit` overrode the absent-value signal before it reached the backend.
488
-
489
- Fixes:
490
- - `mcp-server/src/tools.ts` : 4 list tools now expose `createdBy` (`list_tasks` + `list_tasks_by_mission` only — `list_missions` + `list_briefing_notes` do not accept it backend-side) and `updatedSince` (all 4).
491
- - Removed `.default(50)` (3 tools) and `.default(20)` (1 tool) on `limit` so absent value reaches the backend, enabling the v2.3.3 auto-clamp safeguard.
492
-
493
- Tests : 8 new boundary-forwarding cases (`src/__tests__/list-queries-v2.3.5-wire-createdby-updatedsince.test.ts`) — verify MCP layer actually forwards new params to `convex.query` instead of dropping them. 0 regression on existing suites.
494
-
495
- Detection : Vantage-Bridge architecture review Sigma scope 2026-05-28 — direct `grep`/`sed` inspection of `tools.ts` confirmed the gap. Backend already correct since v2.3.3 (`convex/tasks.ts:354-357`).
496
-
497
- Fix-pattern (2026-05-28 capitalize) : when adding a new param across backend + MCP wrapper, the test suite MUST cover not only schema validation but also the tool-handler→convex.query forwarding boundary. Schema-only tests passed cleanly in v2.3.3 while the actual feature was broken in prod.
173
+ ### Fixed
498
174
 
499
- VP task : `k177tsvdxzase5sjy2qm9fdvp187kbwr`. Predecessor v2.3.3 PR #539 (`k1796s5j6jfkvkx0tn5n926ftd87jx9p`).
175
+ - `list_tasks` and `list_tasks_by_mission` forward `createdBy`, and all four list tools forward `updatedSince`; previously these filters were silently dropped. An omitted `limit` now reaches the backend so its automatic page-size cap applies.
500
176
 
501
177
  ## v2.3.4 — 2026-05-28
502
178
 
503
- **Security fix** — DCR (Dynamic Client Registration) self-registration now defaults to tenant-scope only. Master scope requires explicit admin authorization (`ADMIN_DCR_TOKEN` / `BEARER_SECRET_MASTER` env var). Closes beta blocker for early-access RH cohort onboarding identified in VP Cloud audit 2026-05-28.
504
-
505
- Changes:
506
- - `convex/oauth.ts`: `registerPublicClient` now explicitly rejects `scopeProfile="master"` with a `ScopeViolation` error. Previously only the HTTP server enforced this; the Convex-layer was bypassable via direct internal call.
507
- - `mcp-server/src/auth.ts`: bearer layer 3 (DCR token path) no longer maps `mcp:full` scope string to `scopeProfile="master"`. DCR tokens now always resolve to `client-generic` (deny-by-default). The `mcp:full` label in the legacy `oauthTokens` table was a scope label, not an authorization grant.
508
- - `convex/oauthDcr.ts`: added security documentation clarifying the legacy table is no longer an escalation path; the auth middleware fix is the primary gate.
509
-
510
- Tests: 5 new Convex security tests (`convex/oauth-dcr-security.test.ts`) + 5 new MCP scope enforcement tests (`mcp-server/src/__tests__/dcr-scope-enforcement.test.ts`), 0 regression on existing suites.
179
+ ### Security
511
180
 
512
- VP task: k17218rvqyncs1v6rwj3qdzfsn87jj4n. Beta unblock chain: DCR fix → 5 quick wins onboarding (seed-profiles + early-access RH cohort client + README VP Cloud + runbook + email).
181
+ - Dynamic client registration can no longer obtain operator scope; self-registered clients receive a tenant scope only.
513
182
 
514
183
  ## v2.3.3 — 2026-05-28
515
184
 
516
- **Follow-up to v2.3.2 (2026-05-28 scope élargi)** — Extend list queries with `createdBy` + `updatedSince` filters + auto-clamp safeguard.
517
-
518
- Backend (Convex) :
519
- - `tasks.list` + `tasks.listByMission` : + `createdBy` (filter by task creator) + `updatedSince` (Unix ms window) + auto-clamp limit=30 when `fields="full"` and no explicit limit
520
- - `missions.list` : + `updatedSince` + auto-clamp (30)
521
- - `briefingNotes.list` : + `updatedSince` + auto-clamp (15 when fields=full)
522
-
523
- MCP wrapper :
524
- - 4 list tools forward the new params
525
- - New export `updatedSinceSchema` (positive integer ms)
526
- - `limit` `.default()` removed on the 4 list tools so absent limit flows to backend → enables auto-clamp
527
-
528
- Tests : 15 new MCP schema cases (`src/__tests__/list-queries-v2.3.3-createdby-updatedsince.test.ts`) + 6 new Convex round-trip cases.
529
-
530
- Pi pull cycle unblocked : `list_tasks createdBy="pi" status="review" fields="lite"` returns only Pi-dispatched tasks recently moved to review, payload 5-10× smaller.
531
-
532
- Cap fleet : 0 overflow tolérance future (auto-clamp).
185
+ ### Added
533
186
 
534
- VP task: `k1796s5j6jfkvkx0tn5n926ftd87jx9p`. Successor of `k17e09ng1tf217n93z9m4tr0mx87hfe0` (v2.3.2 PR #537).
187
+ - `createdBy` and `updatedSince` filters on list queries, and an automatic page-size cap when full records are requested without a limit.
535
188
 
536
189
  ## v2.3.2 — 2026-05-28
537
190
 
538
- **Hotfix** — Expose `fields="lite"` + `status` array/aliases in MCP tool schemas (2026-05-26 sprint gap).
539
-
540
- Backend support for these params shipped in v2.3.1 but the MCP wrapper Zod schemas never exposed them, so MCP clients couldn't pass them. Fixed for 4 list tools:
541
-
542
- - `list_tasks`: + `fields`, status now accepts aliases (`"open"`, `"active"`, `"all"`) and arrays
543
- - `list_tasks_by_mission`: same
544
- - `list_missions`: + `fields`, status accepts aliases and arrays
545
- - `list_briefing_notes`: + `fields`
546
-
547
- Aliases NOT permitted inside arrays (matches backend rejection contract).
191
+ ### Fixed
548
192
 
549
- Tests: 14 new cases (`src/__tests__/list-queries-schema-v2.3.2.test.ts`), 0 regression on 295+ existing.
550
-
551
- Fix-pattern (fleet-wide): When backend query supports a new param, ALWAYS update the MCP wrapper tool schema in the SAME PR.
552
-
553
- VP task: `k17e09ng1tf217n93z9m4tr0mx87hfe0`.
193
+ - `list_tasks`, `list_tasks_by_mission`, `list_missions` and `list_briefing_notes` accept `fields="lite"`; the task and mission tools accept status arrays and aliases (`open`, `active`, `all`). Aliases are not allowed inside an array.
554
194
 
555
195
  ## 2.3.1 — 2026-05-26
556
196
 
557
- ### Fixed (Eta PR #530 delta-review)
558
- - `status="all"` now actually returns every row (no filter applied). Previously advertised in 2.3.0 docs but the Convex `expandTaskStatuses` / `expandMissionStatuses` helpers rejected it as invalid.
559
- - `status=["all"]` (alias inside an array) now correctly throws `ConvexError` — same conservative-rejection rule as `"open"` / `"active"`.
560
- - `setPendingAliasReleases` on the Convex backend converted from `mutation` to `internalMutation`. It was a public DoS surface against the auto-IRP pipeline; it is a lifecycle operation only and must not be reachable via MCP.
197
+ ### Fixed
198
+
199
+ - `status="all"` returns every row; `status=["all"]` is rejected like the other aliases inside an array.
561
200
 
562
201
  ## 2.3.0 — 2026-05-26
563
202
 
564
203
  ### Added
565
- - `list_tasks`, `list_missions`, `list_tasks_by_mission`, `list_briefing_notes` now accept `fields=lite` for compact payloads.
566
- - Status filters on `list_tasks`, `list_tasks_by_mission`, and `list_missions` now accept arrays and aliases:
567
- - `status=["todo","in_progress"]` — multi-value array
568
- - `status="open"` — expands to non-terminal statuses (tasks: todo+in_progress+review+blocked; missions: brainstorm+plan+execute+validate)
569
- - `status="active"` — in_progress only on tasks; plan+execute on missions
570
- - `status="all"` — no filter applied
571
-
572
- ### Backward compat
573
- - Single-string status still accepted unchanged.
574
- - Omitting `fields` defaults to `"full"` — existing callers unaffected.
575
204
 
576
- ---
205
+ - `fields=lite` on `list_tasks`, `list_missions`, `list_tasks_by_mission` and `list_briefing_notes` for compact payloads.
206
+ - Status filters accept arrays and the aliases `open` (non-terminal), `active` and `all`. A single status string and an omitted `fields` behave as before.
577
207
 
578
208
  ## 2.2.0 — 2026-05-07
579
209
 
580
- - 4 new fix-pattern tools: `create_fix_pattern`, `add_fix_attempt`, `validate_fix`, `link_issue_to_pattern`
581
- - Detailed per-tool docs with arg tables and example calls in README
582
- - New "Fix patterns cycle" section documenting the KB learning loop
583
- - 41 new Zod input-validation unit tests for fix-pattern tools
210
+ - New fix-pattern tools: `create_fix_pattern`, `add_fix_attempt`, `validate_fix`, `link_issue_to_pattern`.
211
+ - Per-tool documentation with argument tables and examples.
584
212
 
585
213
  ## 2.1.1 — 2026-05-04
586
214
 
587
- - Defense-in-depth `memoryIdSchema` validation for `create_briefing_note` and `update_briefing_note`
215
+ - Stricter memory ID validation on `create_briefing_note` and `update_briefing_note`.
588
216
 
589
217
  ## 2.1.0 — 2026-04-25
590
218
 
591
- - `update_briefing_note` MCP tool with RBAC
219
+ - `update_briefing_note` with role-based access control.
592
220
 
593
221
  ## 2.0.2 — 2026-04-14
594
222
 
595
- - Added badges (npm version, downloads, license, tool count) to the published README
596
- - Added Orchestrator Roles reference table including alpha, lambda, victor
597
- - Added note that any custom lowercase role name is accepted
598
- - Added `bugs` URL and additional keywords to `package.json`
223
+ - README badges, `bugs` URL and keywords in `package.json`. Any lowercase agent name is accepted.
599
224
 
600
225
  ## 2.0.1 — 2026-04-14
601
226
 
602
- - Docstring fix in server.ts (minor)
227
+ - Docstring fix.
603
228
 
604
229
  ## 2.0.0
605
230
 
606
- - Type-safe `api.ts` export for cross-deployment calls (`vantage-peers-mcp/api`)
607
- - Deploy key authentication guide
608
- - Mission Templates category (1 tool: `update_mission_template`)
609
- - Programmatic API section in README
231
+ - Typed function references for calling a deployment directly (`vantage-peers-mcp/api`).
232
+ - Deploy-key authentication guide.
233
+ - `update_mission_template`.
610
234
 
611
235
  ## 1.x
612
236
 
613
- - Initial public release with 82 MCP tools
237
+ - Initial public release.