[media-types] [IANA #1459946] text/vnd.openpredicate+json registration request

Amanda Baber via RT <iana-mime-comment@iana.org> Wed, 07 October 2026 23:05 UTC

Received: from smtp.lax.icann.org (smtp.lax.icann.org [IPv6:2620:0:2d0:201::1: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 63D7130 for <media-types@ietf.org>; Wed, 07 Oct 2026 23:05:41 +0000 (UTC)
Authentication-Results: mx.ietf.org; dkim=pass header.d=iana.org header.s=202509s header.b=AGj8CEq5; spf=pass (mx.ietf.org: domain of iana-shared@iana.org designates 2620:0:2d0:201::1: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 9901FE1A6E; Wed, 7 Oct 2026 23:05:09 +0000 (UTC)
DKIM-Filter: OpenDKIM Filter v2.11.0 smtp.lax.icann.org 9901FE1A6E
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=iana.org; s=202509s; t=1791414309; bh=Mgbw6lHZsMCC0g4ppncpX82Wv2hmOiTqK4SIC9KsdcA=; h=Subject:From:Reply-To:In-Reply-To:References:CC:Date:From; b=AGj8CEq54oMIwEHFPey1NOMa2RzyXhADV+jRI0XHQdMMJ6b028hp/iO49W9nTYRtT 5WZGYFulLEs/0weugPWOfaRCbziYqFHuRnU7SikBRF02IrcPjCgabKlYAoVpNubgUc 6B5rfd0Qwh9oljRLOE5HYEc4ovMxIXiQQ+W/R3Ro=
Received: by request7.lax.icann.org (Postfix, from userid 48) id 787E6C13516D; Wed, 7 Oct 2026 23:05:09 +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-612506-1791414309-682.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: Wed, 07 Oct 2026 23:05:09 +0000
MIME-Version: 1.0
X-Spamd-Bar: --------------
Message-ID-Hash: B7KEZFFXSXGY7MSVTEPT46BMVBIIBPMB
X-Message-ID-Hash: B7KEZFFXSXGY7MSVTEPT46BMVBIIBPMB
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/JC13BuIvQ6n-8yrO2O7DNpSBIYs>
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