[media-types] [IANA #1459946] text/vnd.openpredicate+json registration request
Amanda Baber via RT <iana-mime-comment@iana.org> Fri, 16 October 2026 04:04 UTC
Received: from smtp.lax.icann.org (smtp.lax.icann.org [192.0.33.81]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by mx.ietf.org (Postfix) with ESMTPS id ED04B46 for <media-types@ietf.org>; Fri, 16 Oct 2026 04:04:36 +0000 (UTC)
Authentication-Results: mx.ietf.org; dkim=pass header.d=iana.org header.s=202509s header.b=nMuLZBfs; spf=pass (mx.ietf.org: domain of iana-shared@iana.org designates 192.0.33.81 as permitted sender) smtp.mailfrom=iana-shared@iana.org; dmarc=pass (policy=none) header.from=iana.org
Received: from request7.lax.icann.org (request1.lax.icann.org [10.32.11.221]) by smtp.lax.icann.org (Postfix) with ESMTP id 59A52E0BF5; Fri, 16 Oct 2026 04:04:36 +0000 (UTC)
DKIM-Filter: OpenDKIM Filter v2.11.0 smtp.lax.icann.org 59A52E0BF5
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iana.org; s=202509s; t=1792123476; bh=Mgbw6lHZsMCC0g4ppncpX82Wv2hmOiTqK4SIC9KsdcA=; h=Subject:From:Reply-To:In-Reply-To:References:CC:Date:From; b=nMuLZBfssBZZDblIoRHB0cBILSM2JZQVyZTupYIAQ4bHXavmxg4HS7Od0xLGSoaRk 65ZZZVXHW3fhVKOFeBNTh0dtp4fxy+oTfUHnEW6t16hAWxZgY2Ch/hfX/Y32s/EbOY enCAI5G2NgAHEdCznuP6Of/QBRqV8UZ9VW6pB69E=
Received: by request7.lax.icann.org (Postfix, from userid 48) id 5685AC17B16A; Fri, 16 Oct 2026 04:04:36 +0000 (UTC)
RT-Owner: amanda.baber
From: Amanda Baber via RT <iana-mime-comment@iana.org>
In-Reply-To: <4gpkgdgw39-1@ppa2.lax.icann.org>
References: <RT-Ticket-1459946@icann.org> <4gpkgdgw39-1@ppa2.lax.icann.org>
Message-ID: <rt-5.0.3-760696-1792123476-536.1459946-9-0@icann.org>
X-RT-Loop-Prevention: IANA
X-RT-Ticket: IANA #1459946
X-Managed-BY: RT 5.0.3 (http://www.bestpractical.com/rt/)
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
X-RT-Original-Encoding: utf-8
Precedence: bulk
Date: Fri, 16 Oct 2026 04:04:36 +0000
MIME-Version: 1.0
X-Spamd-Bar: -----------------------
Message-ID-Hash: EA7ORQUKOG3AUHVOB5K7H7WZANUCBQXB
X-Message-ID-Hash: EA7ORQUKOG3AUHVOB5K7H7WZANUCBQXB
X-MailFrom: iana-shared@iana.org
X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-media-types.ietf.org-0; header-match-media-types.ietf.org-1; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header
CC: media-types@ietf.org, superuser@gmail.com
X-Mailman-Version: 3.3.10
Reply-To: iana-mime-comment@iana.org
Subject: [media-types] [IANA #1459946] text/vnd.openpredicate+json registration request
List-Id: "IANA mailing list for reviewing Media Type (MIME Type, Content Type) registration requests." <media-types.ietf.org>
Archived-At: <https://mailarchive.ietf.org/arch/msg/media-types/WgjK4pBKo4lsJMHaShPlCbsaTaQ>
List-Archive: <https://mailarchive.ietf.org/arch/browse/media-types>
List-Help: <mailto:media-types-request@ietf.org?subject=help>
List-Owner: <mailto:media-types-owner@ietf.org>
List-Post: <mailto:media-types@ietf.org>
List-Subscribe: <mailto:media-types-join@ietf.org>
List-Unsubscribe: <mailto:media-types-leave@ietf.org>
Hi Murray, Resending this request from September 17th. thanks, Amanda On Thu Sep 17 20:07:55 2026, amanda.baber wrote: > Hi Murray, > > Would you be able to review this new request by October 1st? > > thanks, > Amanda > > ===== > > Name: Christos Gkoros > > Email: contact@christosgkoros.com > > Media type name: text > > Media subtype name: vnd.openpredicate+json > > Required parameters: N/A > > Optional parameters: N/A > > Encoding considerations: binary > > Security considerations: This media type carries a declarative > predicate: a filter to be evaluated > against records. The points below follow RFC 6838, Section 4.6. > > (1) Active or executable content. > > None. The content is JSON data and contains no scripts, no code > references and > nothing that a recipient is expected to execute. It is not, however, > inert: a > predicate is untrusted input that a recipient turns into a query plan, > so the > cost of evaluation is chosen by the sender. The specification > therefore requires > every implementation to bound it (Section 7) and gives RECOMMENDED > defaults — > nesting depth 10, 100 clauses, 1000 members in a set operand, a 64 KiB > request > body, and 100 ms per regular expression per record. A filter exceeding > a limit > MUST be rejected with the "query-too-complex" condition of Section 8. > > Two prohibitions in the specification exist for security rather than > correctness, and an implementation that ignores them is unsafe even > though it > still parses every valid filter: > > - An implementation MUST reject an operator it does not support, and > MUST NOT > silently ignore the clause (Section 2.1). Dropping a predicate > *widens* the > result set. > - An implementation MUST NOT truncate an over-limit filter to fit it > (Section 7). A truncated predicate silently returns records the sender > did > not ask for. > > Both failure modes return more data than the filter describes, which > is an > authorization bypass wherever a filter carries tenancy or visibility. > For the > same reason, a recipient that composes a caller-supplied predicate > with its own > authorization predicate must do so by conjunction, and must never let > the > caller-supplied part relax or replace it. > > Regular expressions are the principal denial-of-service surface. The > "$regex" > operator is optional; the specification strongly RECOMMENDS a linear- > time engine > (for example RE2, Rust's regex crate, or Go's regexp) and advises that > where only > a backtracking engine is available the operator SHOULD NOT be offered > at all, > directing callers to "$like", whose worst case is bounded. The array > quantifiers > "$some" and "$every" are the next most expensive: each is a traversal, > and nested > quantifiers multiply. Fields backed by unindexed storage are a further > surface, > and the specification advises restricting expensive operators to > indexed fields. > > The specification does not address how a predicate is compiled for a > backend. > An implementation that builds a backend query by interpolating operand > values > into a query string is vulnerable to injection; operands are caller- > controlled > and MUST be passed as bound parameters, or otherwise escaped by the > backend's own > facilities, never concatenated. > > (2) and (3) Privacy and integrity. > > Yes, both are generally needed, and this media type provides neither. > Operands > are caller-supplied values and routinely contain exactly the data > worth > protecting — identifiers, names, addresses, account numbers, search > terms that > reveal intent. A predicate is therefore as sensitive as the records it > selects > and should be protected in transit by TLS, and treated as personal > data at rest > wherever request bodies are logged. Integrity matters as much as > confidentiality: altering a single operand changes which records are > returned, > so an unprotected predicate is a tampering target, not merely a > disclosure one. > > Two deployment notes follow from where this type is carried. > Transporting the > predicate in a request body, as the QUERY method of RFC 10008 permits, > keeps it > out of request-target logs, Referer headers and browser history, where > a query > string would land; this is a privacy improvement over encoding the > same filter > in a URI. Conversely, responses to QUERY are cacheable, and RFC 10008 > requires > the request content to form part of the cache key. A cache that keys > only on the > request target will serve one caller's filtered records to another, > which is a > disclosure defect created by the transport rather than by this format. > > The error model of Section 8 discloses information deliberately, and > deployments > should be aware of it. To let a caller converge on a valid filter, the > specification RECOMMENDS that an "unknown-field" response carry the > list of > paths the endpoint does expose, that "invalid-operand" describe the > accepted > domain of the field — which can include its full set of permitted > values — and > that errors locate the offending clause with a JSON Pointer into the > request > body. On an endpoint reachable without authorization, these responses > together > describe the queryable surface and can enumerate closed value domains. > They are > RECOMMENDED, not REQUIRED, and an endpoint whose schema or value > domains are > themselves sensitive should reduce what it returns. > > (4) Use of an existing format. > > The content is JSON, so the security considerations of RFC 8259, > Section 12 > apply in full. Three issues specific to using JSON for a predicate are > worth > naming: > > - JSON permits duplicate object member names and leaves the outcome > unspecified (RFC 8259, Section 4). A filter such as > {"age": {"$gt": 18, "$gt": 65}} may be read differently by a validator > and > by an evaluator, so a filter could be approved on one reading and > executed > on another. An implementation SHOULD reject duplicate member names > rather > than resolve them. > - The nesting limits of Section 7 protect evaluation, not parsing. A > parser > runs first and can be exhausted by depth before any limit is applied, > so a > recipient should bound input size and nesting at the parser, > independently. > - JSON does not constrain number precision. An operand may not survive > a > round trip through a recipient's number type, which can change which > records > match a comparison. The interoperability guidance of RFC 7493 is > relevant. > > Field paths are strings and may contain confusable or bidirectional > Unicode. A > recipient that resolves a path against its own schema should compare > exactly and > reject anything it does not recognise, using the "unknown-field" > condition, > rather than normalising toward a near match. > > (4a) Compression. > > This media type does not employ compression. Where a transport applies > a > content coding, the body-size limit of Section 7 must be enforced > against the > decoded size and the decoding must itself be bounded; a small > compressed body > can expand past any limit applied only to what arrived on the wire. > > (4b) Container format. > > None. The content is a single JSON value and embeds no other format. > > (5) Links that must be resolved to interpret the content. > > None: a predicate is self-contained and a recipient needs to fetch > nothing to > interpret it. The grammar is described by a JSON Schema whose > identifier is a > URI, and some tooling resolves that identifier over the network at > validation > time. That is a convenience, not a requirement of this media type: > doing so > makes validation depend on a third-party host's availability and on > whatever > that host returns. Published schema versions are immutable, so > implementations > SHOULD vendor the schema or pin a versioned identifier rather than > fetch it at > run time, and SHOULD NOT dereference identifiers supplied by a caller. > > Interoperability considerations: The syntax of a predicate is defined > by a single JSON Schema, so independent > implementations can share one validator and agree on what is well- > formed. What > follows concerns everything that validation does not settle, in the > order most > likely to cause two conforming implementations to disagree. > > Maturity, stated plainly. > > Interoperability has not yet been demonstrated between independent > implementations, because as of this registration there are none. One > implementation exists, written to test the design rather than to be > used. The > published test suite is 60 filters that check well-formedness against > the > schema; it carries no records and no expected results, so it cannot > establish > that two evaluators agree. The grammar is pre-1.0 and, per Section 9 > of the > specification, a minor release may break compatibility before 1.0. > > Version agreement is out of band. > > The grammar version is carried in the schema identifier, not in the > predicate. > A filter is a bare JSON object with no version marker, and this > registration > defines no version parameter, so a sender and a recipient must agree > on a > version by other means — an OpenAPI description, the capability > document of > Section 2.2, or prior arrangement. Recipients cannot infer the version > from the > content, and senders should not assume the latest. > > Partial implementation is designed in, and is the main practical > limitation. > > Operators are grouped into profiles (Section 2.1). Only the "core" > profile is > required; every other profile is optional and must be implemented in > full or not > advertised at all. A filter that one conforming implementation accepts > may > therefore be rejected by another with an "unsupported-operator" error. > This is > intended — it lets an implementation be honest about a subset rather > than > mistranslate — but it means a filter is portable only across endpoints > that > advertise the profiles it uses. > > The mechanism for discovering that is weaker than the mechanism for > declaring > it, and this is a known gap: the capability document of Section 2.2 is > RECOMMENDED rather than REQUIRED, and the specification does not > mandate a > location for it. A client therefore has no guaranteed way to learn an > endpoint's > limits except by sending a filter and reading the error. The project > tracks this > as an open issue against 1.0. > > Behaviour the specification deliberately leaves to the server. > > Two operators are interoperable in name only, and callers should treat > them as > such: > > - "$search" (Section 5.12). Tokenisation, stemming, stop-words, phrase > handling and relevance are entirely server-defined. The specification > reserves the operator name so that implementations do not each invent > one, > and defines nothing about what it matches. Two conforming > implementations > will return different records for the same "$search" clause, and this > is > conforming behaviour. > - "$ilike" (Section 5.5). Collation is server-defined. Unicode simple > case > folding is RECOMMENDED and servers are advised to state their > collation, > because case folding for non-ASCII text differs materially between > engines. > ASCII-only text is portable; anything else is not. > > Regular expressions are the known conformance gap. > > Section 5.7 defines the "$regex" operand as an ECMA-262 regular > expression. > Section 7 separately recommends a linear-time engine — RE2, Rust's > regex crate, > Go's regexp — because backtracking engines are the format's largest > denial-of-service surface. Those two recommendations are in tension: > linear-time > engines deliberately omit ECMA-262 constructs that require > backtracking, such as > backreferences and lookaround, so a pattern that is valid ECMA-262 may > fail to > compile. Engines that expose POSIX semantics diverge differently > again: "." > matches a newline, "\\d" and "\\w" become locale-dependent classes, > and > "\\p{...}" does not exist. > > This is observed rather than theorised. The project's own filter-to- > SQL > implementation emits a warning to exactly this effect when it compiles > "$regex" > to a POSIX operator, and another when a requested "$flags" value has > no > equivalent in the target engine. > > Consequently: a pattern beyond the portable core of ECMA-262 syntax — > literals, character classes, alternation, grouping, greedy and lazy > quantifiers, and the anchors — should not be assumed to behave > identically > across implementations, or to be accepted at all. An implementation > that cannot > offer ECMA-262 semantics is advised by Section 7 to omit the "regex" > profile > entirely and direct callers to "$like", whose semantics are fully > specified by > this specification rather than delegated to an engine. > > Three-valued logic is the most likely source of silent divergence. > > Evaluation is three-valued: a comparison against a field that is null > or absent > is neither TRUE nor FALSE but UNKNOWN, and only TRUE matches (Section > 4.1). An > implementation that maps a filter onto two-valued semantics — a naive > in-memory > evaluator using a language's own inequality operator, for instance — > will return > a different set of records for the same filter, with no error raised > on either > side. Of every interoperability issue listed here this is the one that > fails > silently, and it is why the "$unknownAs" modifier exists: it records > the > intended treatment of UNKNOWN in the filter rather than leaving it to > the > recipient. > > The asymmetry in Section 4.3 is easy to implement inconsistently and > should be > read closely: a type mismatch is FALSE for the equality family, > because equality > is structural, but UNKNOWN for the ordering and string families, > because no > ordering is defined across types. The difference is observable under > negation. > > Coercion, and where an out-of-domain operand surfaces. > > There is no implicit coercion (Section 4.3). A recipient that needs it > — a date > column queried with a string — is advised to coerce once at the > boundary, into > the field's declared type, and is required to reject an operand it > cannot map > with an "invalid-operand" error rather than evaluating it as UNKNOWN. > Both > behaviours are conforming, so for an operand of the wrong type one > implementation may return an error while another returns no records. > Callers > should send operands in the field's declared type and not rely on > either > outcome. > > A related divergence has the same shape. Per-field value domains are > not > expressible in the schema, so a filter naming a real field with a > value outside > that field's domain is well-formed. An implementation that publishes > the domain > may reject it with "invalid-operand"; one that does not will simply > match > nothing. An empty result set and an error are both conforming answers > to the > same filter. > > Ordering of dates and numbers. > > Strings compare by Unicode code point (Section 5.2), which coincides > with > chronological order for RFC 3339 timestamps only when the operands > share an > offset: comparing a "Z"-suffixed timestamp against a "+02:00" one > lexicographically gives the wrong answer, and differing fractional- > second > precision compares as text. Implementations storing timestamps as > strings are > advised to normalise to UTC before comparing, and those storing > instants to > parse the operand. An implementation doing neither will disagree with > one that > does. > > JSON does not constrain number precision, so an operand may not > survive a round > trip through a recipient's number type, which can change which records > match a > comparison. The restrictions in RFC 7493 are relevant to senders that > need > predictable results. > > Extensions. > > The bare "$" namespace is reserved to the specification (Section 6). > An > implementation adding an operator must prefix it distinctly and must > not > advertise the unmodified schema identifier, so an extended endpoint is > identifiable as such. Crucially, a recipient must reject an operator > it does not > recognise rather than ignore the clause (Section 2.1): silently > dropping a > predicate widens the result set, so the failure mode of sending an > extended > filter to a plain implementation is a clean error rather than the > wrong records. > > Previously undefined, now settled. > > Duplicate object member names were left undefined by this > specification, as they > are by RFC 8259. Because a filter is validated by one component and > evaluated by > another, a duplicate could be approved on one parser's reading and > executed on > another's. Section 2.3 now requires an implementation to reject a > duplicate > member name with "malformed-query" rather than resolve it. > > Published specification: Published specification: > > OpenPredicate — Specification (grammar v0.4.0), as published in > release > v0.6.3 of the OpenPredicate repository: > > https://github.com/OpenPredicate/open-predicate/blob/v0.6.3/SPEC.md > > The same text is rendered at https://openpredicate.tech/spec/ (current > release) and concatenated with the operator reference at > https://openpredicate.tech/llms-full.txt. > > The JSON Schema that defines the well-formedness of a filter document > is > published at its own immutable versioned URL, and is normatively > referenced by the specification above: > > https://openpredicate.tech/schema/v0.4.0/open-predicate-schema.json > > The specification is stewarded by the OpenPredicate organisation and > published under the MIT licence, which permits IANA to copy this > registration template into the registry and to quote the > specification. > > This subtype uses the "+json" structured syntax suffix: RFC 8259 > (JSON) > and RFC 6839, Section 3.1 ("+json") apply, as does RFC 6838, > Section 4.2.8. > > Applications which use this media: Applications that use this media > type: > > OpenPredicate filter documents are used by HTTP APIs that accept a > structured search predicate in a request body, and by the tooling > that produces, validates and compiles such predicates. > > The following use this media type: > > o The OpenPredicate reference distribution > (https://github.com/OpenPredicate/open-predicate) which publishes > the JSON Schema defining the grammar, a fixture-based conformance > suite, and a generator that derives a per-resource filter schema > from a resource's JSON Schema. > > o Example API descriptions in that distribution: an OpenAPI 3.1 > description in which a filter document is the body of a > "POST /{collection}/search" request, and an OpenAPI 3.2 > description in which it is the body of an HTTP QUERY request > (RFC 10008). > > o An example Model Context Protocol server in that distribution, > which uses the grammar as a tool's input schema so that a language > model emits filter documents, and compiles each accepted document > to parameterised SQL. > > Anticipated uses are HTTP APIs exposing a filterable collection that > wish to label the predicate itself -- as the body of an HTTP QUERY or > POST request, as a saved or transmitted filter definition, or as an > authorization or subscription predicate evaluated against individual > records -- so that a filter is identifiable independently of any > envelope carrying it, and distinguishable by content negotiation from > an unlabelled "application/json" body. > > Fragment identifier considerations: The "+json" structured syntax > suffix applies, per Section 4.11 of > [RFC6838] and the "+json" registration in Section 3.1 of [RFC6839]: > the syntax and semantics of fragment identifiers are as specified > for "application/json", for which no fragment identifier syntax is > defined. This media type defines none of its own. In particular, > JSON Pointer [RFC6901] is not the fragment identifier syntax for > this media type; see Section 6 of [RFC6901]. Representations of > this media type are carried as a request payload rather than > retrieved by URI reference, so no fragment identifier semantics are > required. > > Restrictions on usage: Restrictions on usage: none > > application/vnd.openpredicate+json is not intended for limited use in > the §4.9 sense. Nothing in SPEC.md ties it to one protocol, one > enclosing format, or one deployment: it is a JSON document describing > a predicate, and any protocol that can carry a JSON payload can carry > it. Being in the vendor tree does not itself constitute a restriction > — the vendor tree governs who controls the name, not where the type > may appear. > > Provisional registration? (standards tree only): No > > Additional information: > > 1. Deprecated alias names for this type: n/a > 2. Magic number(s): n/a > 3. File extension(s): .json > 4. Macintosh file type code: n/a > 5. Object Identifiers: n/a > > General Comments: > > Person to contact for further information: > > 1. Name: Christos Gkoros > 2. Email: contact@christosgkoros.com > > Intended usage: COMMON > > Author/Change controller: Christos Gkoros
- [media-types] [IANA #1459946] text/vnd.openpredic… Amanda Baber via RT