{
  "schemaVersion": 1,
  "name": "PostgreSQL-style SQL",
  "oracle": {
    "engine": "PGlite",
    "version": "0.5.5",
    "role": "PostgreSQL parser and result oracle used by the differential test suite"
  },
  "scope": {
    "includes": "The single-database SQL syntax accepted by Minnow and its observable results for each checked example.",
    "excludes": [
      "server lifecycle and connections",
      "catalogs and schemas",
      "roles, ownership, and privileges",
      "replication and server extensions",
      "PostgreSQL storage and administration commands"
    ]
  },
  "classifications": {
    "compatible": "The checked example uses PostgreSQL syntax. Deterministic reads and mutations match PostgreSQL's result and resulting row state; DDL compatibility is PostgreSQL parser acceptance plus Minnow catalog assertions.",
    "different": "Minnow supports the concept, but a spelling, type rule, or observable result deliberately differs.",
    "extension": "Minnow accepts syntax PostgreSQL does not; this is a listed value addition, not PostgreSQL compatibility.",
    "unsupported": "The feature is meaningful for an embedded database but Minnow does not implement it.",
    "inapplicable": "The feature belongs to a server capability that an embedded, single-database engine does not expose."
  },
  "defaults": {
    "supported": "compatible",
    "unsupported": "unsupported"
  },
  "overrides": [
    {
      "id": "expression.arithmetic",
      "classification": "different",
      "reason": "Division by zero returns NULL instead of raising PostgreSQL's error. Integer division itself follows PostgreSQL: two integer operands truncate toward zero."
    },
    {
      "id": "expression.round",
      "classification": "different",
      "reason": "Minnow accepts ROUND(double precision, digits); PostgreSQL requires numeric for the two-argument form."
    },
    {
      "id": "parameter.positional",
      "classification": "extension",
      "reason": "PostgreSQL uses $n parameters. Minnow also accepts ? as adapter-friendly shorthand."
    },
    {
      "id": "mutation.truncate",
      "classification": "different",
      "reason": "TRUNCATE reports the number of rows it removed, where PostgreSQL's command tag carries no count. The resulting table state is identical."
    },
    {
      "id": "mutation.upsert-replace",
      "classification": "extension",
      "reason": "DO REPLACE is Minnow shorthand for replacing every non-key value from EXCLUDED."
    },
    {
      "id": "predicate.match",
      "classification": "extension",
      "reason": "MATCH is Minnow's index-transparent full-text predicate rather than a PostgreSQL operator."
    },
    {
      "id": "predicate.match-star",
      "classification": "extension",
      "reason": "MATCH(*) searches every text column and is a Minnow full-text extension."
    },
    {
      "id": "predicate.match-parameter",
      "classification": "extension",
      "reason": "Parameterized MATCH uses Minnow's index-transparent full-text predicate."
    },
    {
      "id": "function.bm25",
      "classification": "extension",
      "reason": "BM25 exposes Minnow's full-text score; PostgreSQL uses its own text-search types and ranking functions."
    },
    {
      "id": "mutation.upsert",
      "classification": "compatible",
      "reason": "ON CONFLICT ... DO UPDATE follows PostgreSQL syntax."
    },
    {
      "id": "mutation.insert-do-nothing",
      "classification": "compatible",
      "reason": "ON CONFLICT ... DO NOTHING follows PostgreSQL syntax."
    },
    {
      "id": "mutation.upsert-partial",
      "classification": "compatible",
      "reason": "A partial SET list with EXCLUDED follows PostgreSQL syntax."
    },
    {
      "id": "predicate.ilike",
      "classification": "compatible",
      "reason": "ILIKE follows PostgreSQL syntax and case-insensitive matching semantics."
    },
    {
      "id": "expression.modulo",
      "classification": "different",
      "reason": "Minnow permits % on double precision values; PostgreSQL has no % operator for double precision."
    },
    {
      "id": "expression.date-trunc",
      "classification": "compatible",
      "reason": "DATE_TRUNC follows PostgreSQL syntax; Minnow evaluates datetimes in UTC because it has no session time zone."
    },
    {
      "id": "function.numeric-core",
      "classification": "different",
      "reason": "Minnow's numeric functions accept integer, exact, and double-precision arguments interchangeably, where PostgreSQL's distinct integer, numeric, and double-precision overloads do not."
    },
    {
      "id": "function.string-extended",
      "classification": "different",
      "reason": "The bundled form includes INSTR; PostgreSQL has no INSTR and spells the same (string, substring) lookup STRPOS, with the arguments in the same order."
    },
    {
      "id": "function.trim-multi-character",
      "classification": "different",
      "reason": "Minnow removes the trim string as a repeated unit; PostgreSQL treats its characters as a set."
    },
    {
      "id": "aggregate.any-value",
      "classification": "compatible",
      "verification": "acceptance",
      "reason": "PostgreSQL may choose any non-null group member; Minnow documents the minimum. This cross-engine profile checks acceptance rather than row equality, while the native browser behavior probe asserts Minnow's minimum."
    },
    {
      "id": "aggregate.json",
      "classification": "different",
      "reason": "Minnow returns JSON text; PostgreSQL returns a native JSON value, and member order is unspecified without aggregate-local ORDER BY."
    },
    {
      "id": "subquery.correlated-json-aggregate",
      "classification": "different",
      "reason": "Both engines accept the correlated JSON aggregate and agree on its JSON value, but Minnow returns JSON text while PostgreSQL returns a native JSON value."
    },
    {
      "id": "literal.scientific",
      "classification": "different",
      "reason": "PostgreSQL types every scientific-notation constant NUMERIC and renders it as text. Minnow evaluates it exactly but returns a number whenever the value reads back identically from one, keeping ordinary constants number-typed at the JavaScript boundary; a constant that stays exact renders fully expanded, as PostgreSQL renders it."
    },
    {
      "id": "type.exact-numeric",
      "classification": "different",
      "reason": "Minnow preserves exact decimals at the JavaScript boundary as strings, as PGlite's default decoder also does. A declared scale renders at exactly that scale as PostgreSQL does; a bare NUMERIC column, a derived arithmetic result, and a value cast or concatenated to text render canonically, without the trailing fractional zeros PostgreSQL preserves. Division and AVG select their result scale the way PostgreSQL does, so quotient digits agree \u2014 including AVG over a column whose declared scale exceeds the selection. The canonical encoding does drop a stored value's display scale, so an explicit arithmetic quotient (such as SUM(v) / COUNT(v)) over a column declared with more than about twenty fractional digits can carry fewer digits than PostgreSQL, which floors the selection at the operand's display scale. An arithmetic or comparison expression mixing a float column with a constant Float64 cannot represent stays exact, where PostgreSQL casts the constant to float8 and rounds it before evaluating."
    },
    {
      "id": "type.json-jsonb",
      "classification": "different",
      "reason": "Minnow returns canonical JSON text at the JavaScript boundary while PostgreSQL clients commonly decode JSONB to a native object."
    },
    {
      "id": "type.interval",
      "classification": "different",
      "reason": "Minnow returns a canonical months/days/microseconds string; PostgreSQL clients use their own interval representation and formatting."
    },
    {
      "id": "type.array",
      "classification": "different",
      "reason": "Minnow returns arrays as canonical JSON text at the JavaScript boundary while PostgreSQL clients commonly return native arrays."
    },
    {
      "id": "function.to-date-timestamp",
      "classification": "different",
      "reason": "TO_DATE returns a zoneless DATE rendered as YYYY-MM-DD text at the JavaScript boundary, where PostgreSQL clients commonly materialize a midnight Date; TO_TIMESTAMP values agree."
    },
    {
      "id": "function.make-date",
      "classification": "different",
      "reason": "MAKE_DATE returns a zoneless DATE rendered as YYYY-MM-DD text at the JavaScript boundary, where PostgreSQL clients commonly materialize a midnight Date; MAKE_TIMESTAMP values agree."
    },
    {
      "id": "function.age",
      "classification": "different",
      "reason": "AGE computes PostgreSQL's calendar difference but returns Minnow's canonical months/days/usecs interval text rather than PostgreSQL's '1 mon 14 days 12:00:00' rendering."
    },
    {
      "id": "type.date",
      "classification": "different",
      "reason": "Minnow returns zoneless DATE values as canonical YYYY-MM-DD text while PostgreSQL clients commonly materialize them as midnight Date objects."
    },
    {
      "id": "json.query",
      "classification": "different",
      "reason": "The JSON value agrees, but Minnow returns compact JSON text while PostgreSQL's text rendering includes spaces."
    },
    {
      "id": "json.arrow",
      "classification": "different",
      "reason": "The JSON value agrees, but Minnow returns compact JSON text at the JavaScript boundary while PostgreSQL clients commonly decode the json result natively. Minnow's parameters carry JavaScript types, so an integer parameter key selects an array element directly where an untyped PostgreSQL placeholder resolves to the text-key operator and needs an explicit ::int cast. Minnow's JSON values also compare as their canonical text, so -> results are valid comparison operands where PostgreSQL has no json = json operator."
    },
    {
      "id": "json.arrow-untyped",
      "classification": "extension",
      "reason": "PostgreSQL requires a json-typed document for -> and ->>; Minnow also accepts ordinary JSON text directly, as its SQL/JSON functions do."
    },
    {
      "id": "json.object",
      "classification": "different",
      "reason": "The JSON value agrees, but Minnow returns compact JSON text while PostgreSQL's text rendering includes spaces."
    },
    {
      "id": "json.array",
      "classification": "different",
      "reason": "Minnow defaults JSON_ARRAY to NULL ON NULL, so a NULL argument becomes a JSON null where PostgreSQL's ABSENT ON NULL default drops it; Minnow also returns compact JSON text while PostgreSQL's rendering includes spaces."
    },
    {
      "id": "trigger.create-after",
      "classification": "different",
      "reason": "Minnow uses an embedded BEGIN ... END trigger body; PostgreSQL triggers call a separately declared function."
    },
    {
      "id": "trigger.create-before",
      "classification": "different",
      "reason": "Minnow uses an embedded BEGIN ... END trigger body; PostgreSQL triggers call a separately declared function."
    },
    {
      "id": "trigger.body-update-delete",
      "classification": "different",
      "reason": "Minnow uses an embedded BEGIN ... END trigger body; PostgreSQL triggers call a separately declared function."
    },
    {
      "id": "trigger.drop",
      "classification": "different",
      "reason": "PostgreSQL requires DROP TRIGGER name ON table; Minnow's trigger names are database-wide."
    },
    {
      "id": "ddl.secondary-index",
      "classification": "compatible",
      "reason": "CREATE INDEX follows PostgreSQL syntax."
    },
    {
      "id": "ddl.drop-secondary-index",
      "classification": "compatible",
      "reason": "DROP INDEX follows PostgreSQL syntax."
    },
    {
      "id": "ddl.composite-secondary-index",
      "classification": "compatible",
      "reason": "Composite CREATE INDEX follows PostgreSQL syntax."
    },
    {
      "id": "ddl.unique-secondary-index",
      "classification": "compatible",
      "reason": "CREATE UNIQUE INDEX follows PostgreSQL syntax."
    },
    {
      "id": "mutation.upsert-expression",
      "classification": "different",
      "reason": "Minnow resolves an unqualified target column in DO UPDATE; PostgreSQL treats score beside EXCLUDED.score as ambiguous unless the target is qualified."
    },
    {
      "id": "transaction.isolation-level",
      "classification": "inapplicable",
      "reason": "Every transaction reads one snapshot and commits atomically, which satisfies READ UNCOMMITTED, READ COMMITTED, and REPEATABLE READ, so those levels are accepted and ignored. SERIALIZABLE promises more than one snapshot can, and is refused rather than silently downgraded."
    },
    {
      "id": "privileges.grant",
      "classification": "inapplicable",
      "reason": "An embedded database has no server roles, owners, or GRANT boundary."
    },
    {
      "id": "aggregate.array-agg",
      "classification": "different",
      "reason": "Minnow returns arrays as canonical JSON text at the JavaScript boundary; PostgreSQL clients return native arrays. ARRAY_AGG supports DISTINCT and ordering, but not FILTER or window use."
    }
  ]
}
