v5.2.0 - Retrieval (RAG), MCP Subscriptions & Elicitation, Agent Hardening
Feature Release
Adds a safe-by-default retrieval (RAG) layer with an agent semantic_search tool, MCP resource subscriptions bridged to LiveQuery, human-in-the-loop approval for destructive tool calls via MCP elicitation, agent impersonation and prompt hardening, bounded idempotency-aware client retries, and a fully isolated Docker integration stack. Also corrects pointer/relation targetClass resolution for built-in system classes.
Changes
Retrieval layer: Parse::Retrieval (Parse::RAG)
- NEW:
Parse::Retrieval.retrieve(query:, klass:, field:, k:, filter:, vector_filter:, chunker:, tenant_scope:, score_quantize:, **scope_opts)embeds a query, runs Atlas$vectorSearchthrough the ACL/CLP-enforcingfind_similar, and splits each retrieved document into scored, citableParse::Retrieval::Chunks. Embedding stays one-vector-per-record; chunking is a post-retrieval presentation step. A merged tenant scope closes the cross-tenant existence side channel. - NEW:
Parse::Retrieval::Chunker::FixedSizeOverlap(size:, overlap:, by:, max_chunks_per_document:)sliding-window chunker (by: :charsdefault, or:tokens), subclassable fromChunker::Base. The per-document cap truncates with a signal rather than raising. - NEW:
agent_searchable field:, filter_fields:model macro opts a class into the agent retrieval tool and declares the fields an agent may filter on. - NEW:
semantic_searchagent tool (permission: :readonly,client_safe: true) with the full security envelope — searchable-class allowlist, recursive underscore-key refusal, filter-field allowlist,field_allowlistprojection, tenant-scope re-assertion on every returned record, and score quantization in non-admin contexts.text_field:disambiguates multi-embed models, constrained to the class's declaredembedsources. - NEW:
Parse::RAGdiscoverability alias;rerank:/hybrid:reserved onretrieve(raiseNotImplementedError) to lock the API shape.
MCP elicitation: human-in-the-loop approval for destructive operations
- NEW:
Parse::Agent.require_approval_for = [:write, :admin]opts tiers into approval (off by default). A pluggableParse::Agent#approval_gateis consulted by#executewith the dry-run diff;NullGateis the default andMCPElicitationGatethe spec-native (MCP 2025-06-18elicitation/create) implementation. - NEW:
call_methodresolves the effective tier from the target method's declared permission, so write/admin methods invoked through the readonlycall_methodtool are gated correctly. - SECURITY: Fails closed — a missing client capability, no open listening stream, a non-streaming transport, or an approver timeout all refuse the operation rather than executing it. Replies are session-bound so one session cannot answer another's prompt.
MCP resource subscriptions bridged to LiveQuery
- NEW: Opt-in MCP resource subscriptions backed by Parse LiveQuery.
- SECURITY: Class authorization (
agent_hidden/ per-agent allowlist + CLP) is enforced before any socket opens;AccessDeniedmaps to JSON-RPC-32602. A master-key (admin) LiveQuery branch requires the agent's own client to present a usable master key. Subscription state is re-checked and stored under a lock to avoid resurrecting torn-down sessions, duplicates, or cap breaches. A process-wide session cap and a listening-stream soft cap bound resource growth.
Agent roadmap: impersonation, prompt hardening, telemetry, provenance
- NEW: Agent impersonation —
Parse::Agent.new(impersonate_user:, impersonate_mint:, impersonation_label:)andagent.impersonate(user)/stop_impersonating!resolve a real_Sessiontoken for a_User(reusing an active session or minting a restricted one). Fails closed: requires a master-key client, rejects non-_Userpointers, and refuses rather than widening to master-key posture when no session resolves. The audit label surfaces on theparse.agent.tool_callpayload. - SECURITY: Aggregate tools (
aggregate,group_by,distinct, pipeline export) route through the ACL-enforcing mongo-direct path for ANY non-master identity — session-token and impersonated agents included — closing the unenforced REST-aggregate gap. - NEW:
Parse::Agent::PromptHardening—sanitize_schema_for_llm(drops non-identifier field names, strips control/zero-width chars, caps and marker-wraps descriptions),scrub_marker_injectionwith aprompt_marker_strictrefuse mode, operator-curatedprompt_injection_canaries(emit telemetry or refuse), a surfacedPROMPT_VERSION, and anallowed_llm_endpointsorigin allowlist with a one-time unrestricted-endpoint warning. Adds embedding-cost telemetry and optional per-row source provenance.
unique_index_on: declarative correctness floor for first_or_create!
- NEW: Model-level
unique_index_onhelper (non-sparse by default) as the correctness floor forfirst_or_create!/create_or_update!. - IMPROVED: Mutex-guarded index registry refactor avoids duplicate
createIndexdeclarations under concurrent class loading.
Fix wrong pointer/relation targetClass for built-in system-class associations
- FIXED: Built-in class associations now resolve correctly regardless of load order.
SYSTEM_CLASS_MAPand aString#to_parse_classfallback to underscored storage names (e.g._User) prevent pointer/relationtargetClassfrom freezing the literal"User"and correct the emitted schema. - CHANGED:
_InstallationCLP advisory is operation-aware — warns only for server-ignored operations (find/create/update/delete) and stays silent for effective ops.
Hardened constraint and $relatedTo handling
- IMPROVED: Per-key operator validation, explicit
$relatedToowning-class accessibility checks on the agent and mongo-direct paths, and clearer errors for mongo-direct$relatedTo.
Schema migration: correct wire-column names and convergence check
- FIXED:
type_mismatchesiterates the model'sfield_mapto resolve custom wire names instead of camelizing property names; transient schema-fetch failures no longer cache a fallback. - NEW: One-way
server_covers_local?convergence check.
Aggregation and connectivity probes
- NEW:
group_byclass-method delegators and operation-aware table headers. - CHANGED:
Parse.connected?probes the health endpoint by default (reports reachable even under hardened CLP); addsParse.reachable?and an endpoint parameter for data-class credential validation.
Parse::Client#request: bounded, idempotency-aware retries
- FIXED: Infinite retry loop removed; retry budget is hoisted and exponential-backoff math is correct (positive backoff with jitter) when callers override the retry count.
- CHANGED: Retries are idempotency-aware — GET/DELETE always, PUT only without an atomic
__op, POST never for ambiguous failures, 429 always. Adds an opt-in idempotent-retry mode with a stableX-Parse-Request-Id,Parse::Error::DuplicateRequestError, and replay recovery infirst_or_create/create_or_update. Also retries onFaraday::TimeoutError.
Token economy and integration coverage
- IMPROVED: Leaner tool surface, responses, and retrieval payloads; new integration coverage for retrieval, elicitation/approval, subscription authorization, retry/idempotency/connectivity, prompt hardening, and resource caps.
bundler-auditadded to the development/test bundle.
Test infrastructure
- CHANGED: The integration stack moved to a dedicated
29xxxhost-port block and is namespaced viaPSNEXT_PREFIX(defaultpsnext-it) — Compose project, container names, and volumes — so it never collides with another Parse instance on the host. Adds.env.testdefaults and README usage/troubleshooting notes.
Commit: 476a181
Author: Adrian Curtin
Date: June 4, 2026