Skip to main content
Glama
smeet666

mcp-stashbox

mcp-stashbox

npm CI license MCP Registry M8ven LobeHub Install in Cursor Install in VS Code

A stash-box is a shared metadata catalogue: it records scenes, the performers credited on them, the studios that released them, and the tags they are filed under, each curated by submission and review. A catalogue holds no media — a record names where something was published and carries nothing of it — and it identifies a file by the fingerprints computed from it. Five such catalogues run independently, each issuing its own key to a registered account.

This server connects a chat client to all of them at once. You can search the scenes, performers, studios and tags of every catalogue you hold a key for, read one record as a single card assembled from every catalogue that holds it, identify a file from its fingerprints, and ask what each catalogue was measured answering. It needs a key per catalogue, and reads only the catalogues it has one for.

Version française


Install

One-click install

Install in Cursor Install in VS Code

Claude Code

claude mcp add stashbox --env STASHBOX_STASHDB_KEY=your-key -- npx -y mcp-stashbox

Claude Desktop, Cursor, and any client using the standard config format

{
  "mcpServers": {
    "stashbox": {
      "command": "npx",
      "args": ["-y", "mcp-stashbox"],
      "env": {
        "STASHBOX_STASHDB_KEY": "your-key"
      }
    }
  }
}

Node 24 or later is required. Set a key for each catalogue you want read; the others are named as absent from every answer.

With Docker

{
  "mcpServers": {
    "stashbox": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "-e",
        "STASHBOX_STASHDB_KEY",
        "ghcr.io/smeet666/mcp-stashbox:2.1.0"
      ]
    }
  }
}

-i keeps stdin open, which is where the protocol travels, and -t is left out because a TTY rewrites the stream. The container needs outbound HTTPS to the catalogues you hold keys for, and the keys from your environment: no volume, no port.

Bundle, without npm

Download mcp-stashbox-2.1.0.mcpb from the latest release and open it. A client that supports MCP bundles installs it on its own, with no npm to run. The keys are still set in the client's configuration.

Related MCP server: MusicBrainz MCP Server

What you can ask

  • "Which catalogues am I actually reading?"

  • "Find the performers credited under that name."

  • "Read me that studio's record."

  • "What is this file? Here is its MD5."

  • "Which scenes did those two perform in together?"

The ordinary path runs from a search to a card: a row carries an id written instance:uuid, and the record tool reads it on every catalogue that holds it.

The catalogues

Catalogue

Address

Key

StashDB

stashdb.org

STASHBOX_STASHDB_KEY

TPDB

theporndb.net

STASHBOX_TPDB_KEY

FansDB

fansdb.cc

STASHBOX_FANSDB_KEY

PMV Stash

pmvstash.org

STASHBOX_PMV_KEY

JAVStash

javstash.org

STASHBOX_JAVSTASH_KEY

They answer different surfaces: StashDB answers every route this server knows, and the others answer fewer. get_sources states what each was measured answering and the day it was measured. A catalogue with no key is named as absent from every answer, so an answer holding rows from some of them is never read as the whole.

Tools

Tool

What it does

get_sources

States what each catalogue answers, and which keys are held.

search_scenes

Searches the scenes of every configured catalogue.

search_performers

Searches the performers.

search_studios

Searches the studios.

search_tags

Searches the tags.

get_scene

Reads one scene as a single card.

get_performer

Reads one performer as a single card.

get_studio

Reads one studio as a single card.

get_tag

Reads one tag as a single card.

find_by_fingerprint

Identifies a file from the hashes held for it.

Every search takes two exclusive paths. query runs each catalogue's own text index, which reads the words as a union. The typed arguments narrow as an intersection. Writing both is refused.

get_sources

States what each configured catalogue was measured answering, and the day its surface was read. It reaches no catalogue and takes no argument.

In return: one entry per catalogue with its name, its identifier prefix, whether a key is held for it in this install, the variable to set when none is, and the routes it answers. Whether a key is held is a fact about this install and changes nothing about what the catalogue does.

search_scenes

Searches the scenes.

Argument

Type

Required

What it does

query

string

no

Words for each catalogue's own text index.

title

string

no

Words a title carries.

code

string

no

The studio's own reference for the release.

alias

string

no

Another title the release is known by.

date

a calendar day

no

The release date to compare against.

date_compare

on, before or after

no

How that date is read.

performer_ids

list of identifiers

no

Performers credited on it.

studio_ids

list of identifiers

no

Studios that released it.

parent_studio_id

an identifier

no

A studio the releasing studio sits under.

tag_ids

list of identifiers

no

Tags it is filed under.

match

all or any

no

How a list of identifiers is read.

sort

title, date, duration, trending, popularity, created_at or updated_at

no

The order the catalogue applies.

direction

asc or desc

no

Which way that order runs.

page

integer, 1 to 1000

no

Which page of each catalogue's own order.

limit

integer, 1 to 100

no

Rows one page of one catalogue carries.

sources

list of catalogues

no

Read these catalogues alone.

In return: rows carrying the id written instance:uuid, which get_scene takes, and what names the record. A row leaves the synopsis, the link lists and the editing stamps to the card, since none of those separates two releases. The answer says per catalogue which of three it met: a failure, a catalogue nobody asked, or an emptiness it established. Counts are never added across catalogues. A search written with words alone reads the first rows each text index answers with, since those routes take no page.

search_performers

Searches the performers.

Argument

Type

Required

What it does

query

string

no

Words for each catalogue's own text index.

name

string

no

Words a name carries.

alias

string

no

Another name they are known by.

disambiguation

string

no

What the catalogue adds to tell two apart.

gender

one of the values the catalogue records

no

The gender the catalogue records.

country

a two-letter country code

no

The country the catalogue records.

ethnicity

one of the values the catalogue records

no

The ethnicity the catalogue records.

birth_year

integer, 1800 to 2200

no

The year of birth.

career_start_year

integer, 1800 to 2200

no

The year a career opened.

career_end_year

integer, 1800 to 2200

no

The year a career closed.

performed_with

an identifier

no

Someone they are credited alongside.

studio_id

an identifier

no

A studio they are credited on.

sort

name, birthdate, deathdate, scene_count, career_start_year, debut, last_scene, popularity, created_at or updated_at

no

The order the catalogue applies.

direction

asc or desc

no

Which way that order runs.

page

integer, 1 to 1000

no

Which page.

limit

integer, 1 to 100

no

Rows one page of one catalogue carries.

sources

list of catalogues

no

Read these catalogues alone.

alias is declared and never sent. No catalogue's faceted route applies it: a request carrying it answers as wide as one carrying none, so it is left out and the answer names it as a narrowing nobody received.

In return: the rows and the per-catalogue accounting search_scenes returns.

search_studios

Searches the studios.

Argument

Type

Required

What it does

query

string

no

Words for each catalogue's own text index.

name

string

no

Words a name carries.

parent_id

an identifier

no

A studio it sits under.

has_parent

boolean

no

Whether it sits under another at all.

sort

name, created_at or updated_at

no

The order the catalogue applies.

direction

asc or desc

no

Which way that order runs.

page

integer, 1 to 1000

no

Which page.

limit

integer, 1 to 100

no

Rows one page of one catalogue carries.

sources

list of catalogues

no

Read these catalogues alone.

In return: the rows and the per-catalogue accounting search_scenes returns.

search_tags

Searches the tags.

Argument

Type

Required

What it does

query

string

no

Words for each catalogue's own text index.

name

string

no

Words a name carries.

category_id

an identifier

no

A category the tag belongs to.

sort

name, created_at or updated_at

no

The order the catalogue applies.

direction

asc or desc

no

Which way that order runs.

page

integer, 1 to 1000

no

Which page.

limit

integer, 1 to 100

no

Rows one page of one catalogue carries.

sources

list of catalogues

no

Read these catalogues alone.

In return: the rows and the per-catalogue accounting search_scenes returns.

get_scene

Reads one scene as a single card.

Argument

Type

Required

What it does

id

an identifier written instance:uuid

yes

The record to read.

sections

any of basic, fingerprints, images

no

The blocks read beside the card.

sources

list of catalogues

no

Read these catalogues alone.

prefer

list of catalogues

no

The order preferred where they disagree.

In return: one card, read on every catalogue that holds the record and reached by the link each of them publishes to the same record elsewhere. Every value names the catalogues that said it, and where they disagree the reading nobody preferred is published beside the one that won. Left out, the registry's own order stands, and every card states the order applied.

get_performer

Reads one performer as a single card.

Argument

Type

Required

What it does

id

an identifier written instance:uuid

yes

The record to read.

sections

any of basic, appearance, images, studios

no

The blocks read beside the card.

sources

list of catalogues

no

Read these catalogues alone.

prefer

list of catalogues

no

The order preferred where they disagree.

studios is the whole table of studios they are credited on, which runs to hundreds of rows.

In return: the card get_scene returns, for a performer.

get_studio

Reads one studio as a single card.

Argument

Type

Required

What it does

id

an identifier written instance:uuid

yes

The record to read.

sources

list of catalogues

no

Read these catalogues alone.

prefer

list of catalogues

no

The order preferred where they disagree.

In return: the card get_scene returns, for a studio.

get_tag

Reads one tag as a single card.

Argument

Type

Required

What it does

id

an identifier written instance:uuid

yes

The record to read.

sources

list of catalogues

no

Read these catalogues alone.

prefer

list of catalogues

no

The order preferred where they disagree.

In return: the card get_scene returns, for a tag.

find_by_fingerprint

Identifies a file from the hashes held for it.

Argument

Type

Required

What it does

fingerprints

a list of { hash, algorithm }, the algorithm MD5, OSHASH or PHASH

yes

The hashes to look up.

sections

any of basic, fingerprints, images

no

The blocks read beside each card. One call answers a card per record reached, so a block asked for here reaches a reader once per match.

sources

list of catalogues

no

Read these catalogues alone.

prefer

list of catalogues

no

The order preferred where they disagree.

MD5 and OSHASH name the bytes of a file. PHASH states a likeness, which a re-encode, a crop or another scene from the same shoot can satisfy: read a PHASH match as a resemblance rather than as an identity.

In return: each record reached, answered as one card read on every catalogue that holds it.

What an answer states about the catalogues

Every answer accounts for each catalogue separately, because merging them would lose what a caller needs. A catalogue that failed, one nobody asked, and one that answered with nothing are three different things, and they are reported as three. Counts stay beside the catalogue that produced them and are never added up. On a card, each value names the catalogues that said it, and a disagreement is published rather than resolved silently.

Configuration

A key per catalogue, and everything else optional. All of it goes in the env block of your client config.

Variable

Default

What it does

STASHBOX_STASHDB_KEY

none

The key StashDB issues to your account.

STASHBOX_TPDB_KEY

none

The key TPDB issues to your account.

STASHBOX_FANSDB_KEY

none

The key FansDB issues to your account.

STASHBOX_PMV_KEY

none

The key PMV Stash issues to your account.

STASHBOX_JAVSTASH_KEY

none

The key JAVStash issues to your account.

SB_USER_AGENT

the project identity

Names your application to the catalogues, with an address where a person can be reached.

SB_MIN_INTERVAL_MS

1000

Gap between two requests, from 1000 to 60000.

SB_TIMEOUT_MS

20000

Deadline for one request, from 1 to 600000.

SB_MAX_RETRIES

3

Attempts after a transient failure, from 0 to 10.

SB_CACHE_TTL_MS

300000

How long an answer stays in memory, from 0 to 86400000.

SB_CACHE_MAX_ENTRIES

500

Answers held in memory at once, from 1 to 100000.

SB_LOG_LEVEL

error

silent, error, info or debug, written to stderr.

Each catalogue issues its key to a registered account, in that account's settings. This server ships no key of its own, and each user brings their own. A value outside its range falls back to the default, and the reason is written to stderr.

Errors

Every failure carries one of six codes, a message, and where it helps a hint naming the next move.

Code

What happened

What to do

not_found

A catalogue answered, and holds no such record.

Check the identifier with a search.

invalid_input

The arguments were refused before any request went out.

Read the message, which names the argument.

rate_limited

A catalogue asked this client to slow down.

Wait, then call again with the same arguments. The record is still there.

parse_failure

An answer arrived in a shape this client cannot read.

Report it at the issue tracker.

network_error

The request did not complete.

Try again shortly.

timeout

The request passed its deadline.

Raise SB_TIMEOUT_MS, or ask for fewer rows.

A catalogue that failed is reported per catalogue rather than failing the whole answer, so one silent catalogue never hides the others.

As a library

The layer reading the catalogues is published on its own, with its pacing, its cache and its errors, and with no protocol attached.

import { Catalogues } from "mcp-stashbox/client";

const client = new Catalogues();
const read = await client.searchPerformers({ name: "example", limit: 5 });
console.log(read.data.rows.length, read.cached);

Each read answers { data, cached }, and throws an error carrying one of the six codes. The one-second floor between two requests holds here as well.

Pacing and attribution

Requests go out one at a time with at least a second between them, and that floor holds however the server is configured. The User-Agent always ends with the project identity and an address where a person can be reached.

Every record carries the address of its page on the catalogue it came from, and a card carries the link each catalogue publishes to the same record elsewhere. The catalogues are built by the people who submit and review their records.

This MCP server is an unofficial project, with no affiliation to any of the catalogues it reads.

Privacy

This server collects nothing about you and sends nothing to its author. It runs on your machine, contacts only the catalogues you hold a key for, holds its answers in memory while it runs, and writes nothing to disk. Your keys are read from the environment and sent to their own catalogue alone. PRIVACY.md states what a request carries and which settings change any of it.

Development

npm install
npm run build:fixtures
npm test
npm run check

Tests run against generated fixtures and make no network request. The live suite, npm run test:live, makes one request per route and runs nightly against the catalogues themselves.

Contributing

Bugs, questions and ideas belong in the issue tracker. Pull requests are welcome; opening an issue first helps agree on the shape of the change. See CONTRIBUTING.md.

License

MIT, see LICENSE. The records belong to the catalogues and to the people who built them.


mcp-stashbox (français)

English version

Un stash-box est un catalogue de métadonnées partagé : il enregistre des scènes, les interprètes qui y sont crédités, les studios qui les ont publiées, et les étiquettes sous lesquelles elles sont rangées, le tout tenu par soumission et relecture. Un catalogue ne contient aucun média — une fiche nomme où quelque chose a été publié et n'en emporte rien — et il identifie un fichier par les empreintes calculées dessus. Cinq catalogues de ce type fonctionnent indépendamment, chacun délivrant sa propre clé à un compte enregistré.

Ce serveur relie un client de conversation à tous à la fois. On peut chercher les scènes, les interprètes, les studios et les étiquettes de chaque catalogue dont on détient une clé, lire une fiche sous forme d'une carte unique assemblée depuis tous les catalogues qui la détiennent, identifier un fichier par ses empreintes, et demander ce que chaque catalogue a été mesuré répondant. Il demande une clé par catalogue, et ne lit que ceux dont il en a une.

Installation

Installation en un clic

Install in Cursor Install in VS Code

Claude Code

claude mcp add stashbox --env STASHBOX_STASHDB_KEY=votre-cle -- npx -y mcp-stashbox

Claude Desktop, Cursor, et tout client au format de configuration standard

{
  "mcpServers": {
    "stashbox": {
      "command": "npx",
      "args": ["-y", "mcp-stashbox"],
      "env": {
        "STASHBOX_STASHDB_KEY": "votre-cle"
      }
    }
  }
}

Node 24 ou plus récent est nécessaire. Posez une clé par catalogue à lire ; les autres sont nommés comme absents de chaque réponse.

Avec Docker

{
  "mcpServers": {
    "stashbox": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "-e",
        "STASHBOX_STASHDB_KEY",
        "ghcr.io/smeet666/mcp-stashbox:2.1.0"
      ]
    }
  }
}

-i garde l'entrée standard ouverte, qui est le canal du protocole, et -t est omis parce qu'un TTY réécrit le flux. Le conteneur a besoin d'un accès HTTPS sortant vers les catalogues dont vous détenez les clés, et de ces clés prises dans votre environnement : aucun volume, aucun port.

Bundle, sans npm

Téléchargez mcp-stashbox-2.1.0.mcpb depuis la dernière publication et ouvrez-le. Un client qui gère les bundles MCP l'installe seul, sans npm à lancer. Les clés se posent toujours dans la configuration du client.

Ce qu'on peut demander

  • « Quels catalogues est-ce que je lis réellement ? »

  • « Trouve les interprètes crédités sous ce nom. »

  • « Lis-moi la fiche de ce studio. »

  • « Qu'est-ce que ce fichier ? Voici son MD5. »

  • « Dans quelles scènes ces deux-là ont-ils joué ensemble ? »

Le chemin ordinaire va d'une recherche à une carte : une ligne porte un id écrit instance:uuid, et l'outil de fiche le lit sur chaque catalogue qui le détient.

Les catalogues

Catalogue

Adresse

Clé

StashDB

stashdb.org

STASHBOX_STASHDB_KEY

TPDB

theporndb.net

STASHBOX_TPDB_KEY

FansDB

fansdb.cc

STASHBOX_FANSDB_KEY

PMV Stash

pmvstash.org

STASHBOX_PMV_KEY

JAVStash

javstash.org

STASHBOX_JAVSTASH_KEY

Ils répondent des surfaces différentes : StashDB répond à toutes les routes que ce serveur connaît, les autres à moins. get_sources dit ce que chacun a été mesuré répondant et le jour de la mesure. Un catalogue sans clé est nommé comme absent de chaque réponse, si bien qu'une réponse portant les lignes de certains ne se lit jamais comme l'ensemble.

Les outils

Outil

Ce qu'il fait

get_sources

Dit ce que chaque catalogue répond, et quelles clés sont posées.

search_scenes

Cherche les scènes de chaque catalogue configuré.

search_performers

Cherche les interprètes.

search_studios

Cherche les studios.

search_tags

Cherche les étiquettes.

get_scene

Lit une scène sous forme d'une carte unique.

get_performer

Lit un interprète sous forme d'une carte unique.

get_studio

Lit un studio sous forme d'une carte unique.

get_tag

Lit une étiquette sous forme d'une carte unique.

find_by_fingerprint

Identifie un fichier par les empreintes qu'on en détient.

Chaque recherche prend deux chemins exclusifs. query interroge l'index textuel de chaque catalogue, qui lit les mots comme une union. Les arguments typés resserrent comme une intersection. Écrire les deux est refusé.

get_sources

Dit ce que chaque catalogue configuré a été mesuré répondant, et le jour où sa surface a été lue. Il ne joint aucun catalogue et ne prend aucun argument.

En retour : une entrée par catalogue avec son nom, son préfixe d'identifiant, la présence d'une clé dans cette installation, la variable à poser quand il n'y en a pas, et les routes auxquelles il répond. La présence d'une clé est un fait sur cette installation et ne change rien à ce que le catalogue fait.

search_scenes

Cherche les scènes.

Argument

Type

Requis

Ce qu'il fait

query

chaîne

non

Des mots pour l'index textuel de chaque catalogue.

title

chaîne

non

Des mots que porte un titre.

code

chaîne

non

La référence propre du studio pour la publication.

alias

chaîne

non

Un autre titre sous lequel elle est connue.

date

un jour de calendrier

non

La date de publication à comparer.

date_compare

on, before ou after

non

Comment cette date est lue.

performer_ids

liste d'identifiants

non

Les interprètes qui y sont crédités.

studio_ids

liste d'identifiants

non

Les studios qui l'ont publiée.

parent_studio_id

un identifiant

non

Un studio sous lequel le studio éditeur se range.

tag_ids

liste d'identifiants

non

Les étiquettes sous lesquelles elle est rangée.

match

all ou any

non

Comment une liste d'identifiants est lue.

sort

title, date, duration, trending, popularity, created_at ou updated_at

non

L'ordre qu'applique le catalogue.

direction

asc ou desc

non

Le sens de cet ordre.

page

entier, 1 à 1000

non

Quelle page de l'ordre propre à chaque catalogue.

limit

entier, 1 à 100

non

Lignes que porte une page d'un catalogue.

sources

liste de catalogues

non

Ne lire que ces catalogues.

En retour : des lignes portant l'id écrit instance:uuid, que get_scene reprend, et ce qui nomme la fiche. Une ligne laisse à la carte le synopsis, les listes de liens et les horodatages d'édition, dont aucun ne distingue deux publications. La réponse dit par catalogue laquelle des trois il a rencontrées : un échec, un catalogue que personne n'a interrogé, ou un vide qu'il a établi. Les comptes ne sont jamais additionnés entre catalogues. Une recherche écrite avec des mots seuls lit les premières lignes que rend chaque index textuel, ces routes ne prenant aucune page.

search_performers

Cherche les interprètes.

Argument

Type

Requis

Ce qu'il fait

query

chaîne

non

Des mots pour l'index textuel.

name

chaîne

non

Des mots que porte un nom.

alias

chaîne

non

Un autre nom sous lequel ils sont connus.

disambiguation

chaîne

non

Ce que le catalogue ajoute pour en distinguer deux.

gender

une des valeurs que le catalogue enregistre

non

Le genre que le catalogue enregistre.

country

un code pays à deux lettres

non

Le pays que le catalogue enregistre.

ethnicity

une des valeurs que le catalogue enregistre

non

L'ethnicité que le catalogue enregistre.

birth_year

entier, 1800 à 2200

non

L'année de naissance.

career_start_year

entier, 1800 à 2200

non

L'année où une carrière s'est ouverte.

career_end_year

entier, 1800 à 2200

non

L'année où une carrière s'est close.

performed_with

un identifiant

non

Quelqu'un à côté de qui ils sont crédités.

studio_id

un identifiant

non

Un studio sur lequel ils sont crédités.

sort

name, birthdate, deathdate, scene_count, career_start_year, debut, last_scene, popularity, created_at ou updated_at

non

L'ordre qu'applique le catalogue.

direction

asc ou desc

non

Le sens de cet ordre.

page

entier, 1 à 1000

non

Quelle page.

limit

entier, 1 à 100

non

Lignes que porte une page d'un catalogue.

sources

liste de catalogues

non

Ne lire que ces catalogues.

alias est déclaré et jamais envoyé. Aucune route à facettes ne l'applique : une requête qui le porte répond aussi large qu'une requête sans lui, donc il est laissé de côté et la réponse le nomme comme un resserrement que personne n'a reçu.

En retour : les lignes et la comptabilité par catalogue que rend search_scenes.

search_studios

Cherche les studios.

Argument

Type

Requis

Ce qu'il fait

query

chaîne

non

Des mots pour l'index textuel.

name

chaîne

non

Des mots que porte un nom.

parent_id

un identifiant

non

Un studio sous lequel il se range.

has_parent

booléen

non

S'il se range sous un autre.

sort

name, created_at ou updated_at

non

L'ordre qu'applique le catalogue.

direction

asc ou desc

non

Le sens de cet ordre.

page

entier, 1 à 1000

non

Quelle page.

limit

entier, 1 à 100

non

Lignes que porte une page d'un catalogue.

sources

liste de catalogues

non

Ne lire que ces catalogues.

En retour : les lignes et la comptabilité par catalogue de search_scenes.

search_tags

Cherche les étiquettes.

Argument

Type

Requis

Ce qu'il fait

query

chaîne

non

Des mots pour l'index textuel.

name

chaîne

non

Des mots que porte un nom.

category_id

un identifiant

non

Une catégorie dont l'étiquette relève.

sort

name, created_at ou updated_at

non

L'ordre qu'applique le catalogue.

direction

asc ou desc

non

Le sens de cet ordre.

page

entier, 1 à 1000

non

Quelle page.

limit

entier, 1 à 100

non

Lignes que porte une page d'un catalogue.

sources

liste de catalogues

non

Ne lire que ces catalogues.

En retour : les lignes et la comptabilité par catalogue de search_scenes.

get_scene

Lit une scène sous forme d'une carte unique.

Argument

Type

Requis

Ce qu'il fait

id

un identifiant écrit instance:uuid

oui

La fiche à lire.

sections

parmi basic, fingerprints, images

non

Les blocs lus à côté de la carte.

sources

liste de catalogues

non

Ne lire que ces catalogues.

prefer

liste de catalogues

non

L'ordre préféré là où ils divergent.

En retour : une carte, lue sur chaque catalogue qui détient la fiche et atteinte par le lien que chacun publie vers la même fiche ailleurs. Chaque valeur nomme les catalogues qui l'ont dite, et là où ils divergent, la lecture que personne n'a préférée est publiée à côté de celle qui l'emporte. Omis, l'ordre propre du registre s'applique, et chaque carte énonce l'ordre appliqué.

get_performer

Lit un interprète sous forme d'une carte unique.

Argument

Type

Requis

Ce qu'il fait

id

un identifiant écrit instance:uuid

oui

La fiche à lire.

sections

parmi basic, appearance, images, studios

non

Les blocs lus à côté de la carte.

sources

liste de catalogues

non

Ne lire que ces catalogues.

prefer

liste de catalogues

non

L'ordre préféré là où ils divergent.

studios est la table entière des studios sur lesquels ils sont crédités, qui fait des centaines de lignes.

En retour : la carte que rend get_scene, pour un interprète.

get_studio

Lit un studio sous forme d'une carte unique.

Argument

Type

Requis

Ce qu'il fait

id

un identifiant écrit instance:uuid

oui

La fiche à lire.

sources

liste de catalogues

non

Ne lire que ces catalogues.

prefer

liste de catalogues

non

L'ordre préféré là où ils divergent.

En retour : la carte que rend get_scene, pour un studio.

get_tag

Lit une étiquette sous forme d'une carte unique.

Argument

Type

Requis

Ce qu'il fait

id

un identifiant écrit instance:uuid

oui

La fiche à lire.

sources

liste de catalogues

non

Ne lire que ces catalogues.

prefer

liste de catalogues

non

L'ordre préféré là où ils divergent.

En retour : la carte que rend get_scene, pour une étiquette.

find_by_fingerprint

Identifie un fichier par les empreintes qu'on en détient.

Argument

Type

Requis

Ce qu'il fait

fingerprints

une liste de { hash, algorithm }, l'algorithme MD5, OSHASH ou PHASH

oui

Les empreintes à chercher.

sections

parmi basic, fingerprints, images

non

Les blocs lus à côté de chaque carte. Un appel rend une carte par fiche atteinte, donc un bloc demandé ici parvient au lecteur une fois par correspondance.

sources

liste de catalogues

non

Ne lire que ces catalogues.

prefer

liste de catalogues

non

L'ordre préféré là où ils divergent.

MD5 et OSHASH nomment les octets d'un fichier. PHASH énonce une ressemblance, qu'un ré-encodage, un recadrage ou une autre scène du même tournage peuvent satisfaire : lisez une correspondance PHASH comme une ressemblance plutôt que comme une identité.

En retour : chaque fiche atteinte, rendue comme une carte lue sur chaque catalogue qui la détient.

Ce qu'une réponse dit des catalogues

Chaque réponse rend compte de chaque catalogue séparément, parce que les fondre perdrait ce dont un appelant a besoin. Un catalogue qui a échoué, un que personne n'a interrogé et un qui a répondu vide sont trois choses différentes, et elles sont rapportées comme trois. Les comptes restent à côté du catalogue qui les a produits et ne sont jamais additionnés. Sur une carte, chaque valeur nomme les catalogues qui l'ont dite, et un désaccord est publié plutôt que tranché en silence.

Configuration

Une clé par catalogue, et tout le reste facultatif. Tout se pose dans le bloc env de la configuration du client.

Variable

Défaut

Ce qu'elle fait

STASHBOX_STASHDB_KEY

aucun

La clé que StashDB délivre à votre compte.

STASHBOX_TPDB_KEY

aucun

La clé que TPDB délivre à votre compte.

STASHBOX_FANSDB_KEY

aucun

La clé que FansDB délivre à votre compte.

STASHBOX_PMV_KEY

aucun

La clé que PMV Stash délivre à votre compte.

STASHBOX_JAVSTASH_KEY

aucun

La clé que JAVStash délivre à votre compte.

SB_USER_AGENT

l'identité du projet

Nomme votre application auprès des catalogues, avec une adresse où joindre une personne.

SB_MIN_INTERVAL_MS

1000

Écart entre deux requêtes, de 1000 à 60000.

SB_TIMEOUT_MS

20000

Délai d'une requête, de 1 à 600000.

SB_MAX_RETRIES

3

Tentatives après un échec passager, de 0 à 10.

SB_CACHE_TTL_MS

300000

Durée pendant laquelle une réponse reste en mémoire, de 0 à 86400000.

SB_CACHE_MAX_ENTRIES

500

Réponses gardées en mémoire à la fois, de 1 à 100000.

SB_LOG_LEVEL

error

silent, error, info ou debug, écrit sur la sortie d'erreur.

Chaque catalogue délivre sa clé à un compte enregistré, dans les réglages de ce compte. Ce serveur n'embarque aucune clé, et chacun apporte les siennes. Une valeur hors de sa plage retombe sur le défaut, et la raison est écrite sur la sortie d'erreur.

Erreurs

Chaque échec porte un des six codes, un message, et quand cela aide une indication du geste suivant.

Code

Ce qui s'est passé

Que faire

not_found

Un catalogue a répondu, et n'a pas cette fiche.

Vérifiez l'identifiant avec une recherche.

invalid_input

Les arguments ont été refusés avant toute requête.

Lisez le message, qui nomme l'argument.

rate_limited

Un catalogue demande à ce client de ralentir.

Attendez, puis rappelez avec les mêmes arguments. La fiche est toujours là.

parse_failure

Une réponse est arrivée dans une forme illisible ici.

Signalez-le sur le suivi d'incidents.

network_error

La requête n'a pas abouti.

Réessayez sous peu.

timeout

La requête a dépassé son délai.

Augmentez SB_TIMEOUT_MS, ou demandez moins de lignes.

Un catalogue qui échoue est rapporté catalogue par catalogue plutôt que de faire échouer toute la réponse, donc un catalogue silencieux n'en cache jamais d'autres.

Comme bibliothèque

La couche qui lit les catalogues est publiée seule, avec son rythme, son cache et ses erreurs, sans protocole attaché.

import { Catalogues } from "mcp-stashbox/client";

const client = new Catalogues();
const read = await client.searchPerformers({ name: "example", limit: 5 });
console.log(read.data.rows.length, read.cached);

Chaque lecture répond { data, cached }, et lève une erreur portant un des six codes. Le plancher d'une seconde entre deux requêtes tient également ici.

Rythme et attribution

Les requêtes partent une à une avec au moins une seconde entre elles, et ce plancher tient quelle que soit la configuration. Le User-Agent se termine toujours par l'identité du projet et une adresse où joindre une personne.

Chaque fiche porte l'adresse de sa page sur le catalogue d'où elle vient, et une carte porte le lien que chaque catalogue publie vers la même fiche ailleurs. Les catalogues sont bâtis par ceux qui soumettent et relisent leurs fiches.

Ce MCP est un projet non officiel, sans affiliation à aucun des catalogues qu'il lit.

Confidentialité

Ce serveur ne collecte rien sur vous et n'envoie rien à son auteur. Il tourne sur votre machine, ne joint que les catalogues dont vous détenez une clé, garde ses réponses en mémoire le temps qu'il tourne, et n'écrit rien sur le disque. Vos clés sont lues dans l'environnement et envoyées à leur seul catalogue. PRIVACY.md dit ce qu'une requête emporte et quels réglages changent cela.

Développement

npm install
npm run build:fixtures
npm test
npm run check

Les tests s'exécutent sur des fixtures engendrées et n'émettent aucune requête. La suite en direct, npm run test:live, émet une requête par route et tourne chaque nuit contre les catalogues eux-mêmes.

Contribuer

Les anomalies, les questions et les idées ont leur place dans le suivi d'incidents. Les propositions de modification sont bienvenues ; ouvrir un ticket d'abord aide à s'accorder sur la forme du changement. Voir CONTRIBUTING.md.

Licence

MIT, voir LICENSE. Les fiches appartiennent aux catalogues et à ceux qui les ont bâties.

Available Tools

10 tools
find_by_fingerprintFind scenes by fingerprintA
Read-only

Identify a file from the hashes held for it, across every configured stash-box catalogue. MD5 and OSHASH name the bytes of a file; PHASH states a likeness a re-encode, a crop or another scene from one shoot can satisfy. Each record reached is answered as one card, read on every catalogue that holds it.

NameRequiredDescriptionDefault
preferNoThe order the catalogues are preferred in where they disagree on a field. Left out, the registry's own order stands, and every card states the order applied.
sourcesNo
sectionsNoThe blocks read beside the record's own fields, which come back whatever is written here. Each name adds a block, and 'basic' asks for those fields alone.
fingerprintsYes

Output Schema

NameRequiredDescription
askedYes
notesYes
cachedNo
matchesYes
unmatchedYesThe hashes put to a catalogue that answered, which reached no record there. A catalogue named as unasked says nothing about them either way.
per_sourceYes
match_countYesOne per card here. Every hash that reached a record names it on one card, and a record reached both by an exact hash and by a perceptual one stands as two, since the two claim different things about it. Read records_named for how many files were named, which counts each once.
not_searchedYesHashes and the catalogues that answered without searching their algorithm, so they were never put to those. Nobody looked there, which is no evidence about the files behind them.
resemblancesYesMatches a perceptual hash reached, each a likeness and no claim about any file's bytes.
unattributedYesRecords the catalogues answered with that carry none of the hashes asked. Which hash reached them is unknown, so they stand as no match and are counted apart.
records_namedYesDistinct records an exact hash named. Two hashes reaching one record count once, and a perceptual match names no record.

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With readOnlyHint and openWorldHint already declared, the description adds real context: the query fans out to every configured catalogue, results come back as aggregated cards, and where catalogues disagree on a field the preference order decides. It does not address failure modes when a catalogue is unreachable, but the cross-catalogue merge behavior is well disclosed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, each doing distinct work — purpose, hash semantics, result shape — with the core action front-loaded. The phrasing is ornate and the closing sentence ('answered as one card, read on every catalogue that holds it') is convoluted enough to cost a point, but there is no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return-value detail is not required, and the description still conveys the aggregate-card shape and preference ordering. The main gap is the sources parameter, which is never explained beyond the implicit 'every configured catalogue' default, and no guidance on empty results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

At 50% schema coverage, the description carries meaningful weight: the fingerprints items have no schema documentation at all, and the description supplies the exact semantics of all three algorithms, including the fuzzy nature of PHASH. It also implies that omitting sources queries every configured catalogue, which compensates for that field having no schema description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: identify a file from its hashes across all configured stash-box catalogues. It is clearly distinct from the text-based search_scenes sibling, though the drift between the title ('Find scenes') and the description ('Identify a file') leaves a small ambiguity about what exactly is returned.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives genuinely useful guidance on which hash type to supply — MD5/OSHASH for exact byte identity, PHASH for perceptual likeness across re-encodes and crops — which is effectively a when-to-use rule per algorithm. However, it never says when to reach for this tool over search_scenes, nor what to do when nothing matches.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_performerGet one performerA
Read-only

Read one performer from the catalogue its identifier names, written instance:uuid. The answer is one card, read on every catalogue that holds the record and reached by the link each of them publishes to the same record elsewhere. Every value names the catalogues that said it, and where they disagree the reading nobody preferred is published beside the one that won. Name 'sources' to read one catalogue alone.

NameRequiredDescriptionDefault
idYes
preferNoThe order the catalogues are preferred in where they disagree on a field. Left out, the registry's own order stands, and every card states the order applied.
sourcesNo
sectionsNoThe blocks read beside the record's own fields, which come back whatever is written here. Each name adds a block, and 'basic' asks for those fields alone. 'studios' is the whole table of studios they are credited on, which runs to hundreds of rows.

Output Schema

NameRequiredDescription
cardYes
cachedNo

TDQS

A3.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only cover readOnly/openWorld, so the description carries the interesting load: the record is aggregated across every catalogue holding it, each value carries its sources, and disagreements publish both the winning and non-preferred readings. That is genuinely useful behavior an agent could not infer. It omits not-found behavior and defaults for sections.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the purpose, which is good. But the prose is ornamental and oblique ('the reading nobody preferred is published beside the one that won') where a plain sentence about merged records with source attribution would be shorter and clearer.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema and readOnly annotations present, the description only needs to explain the cross-catalogue merge model, which it does. Gaps remain around error/miss behavior and what the default response contains when neither 'sources' nor 'sections' is supplied.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 50%: 'prefer' and 'sections' are documented in the schema, 'sources' is not. The description partially compensates by explaining sources ('read one catalogue alone') and the disagreement/preference model, but it never addresses 'sections' blocks or the id format beyond a cryptic 'instance:uuid'.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Read one performer from the catalogue its identifier names,' which separates it from search_performers. The phrasing is convoluted ('written instance:uuid', 'catalogue its identifier names') and never names the sibling it contrasts with, so it stops short of a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: an agent infers this is the single-record lookup by identifier versus the search_* siblings, but the description never says so. The one conditional it does give ('Name sources to read one catalogue alone') is parameter guidance rather than tool-selection guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_sceneGet one sceneA
Read-only

Read one scene from the catalogue its identifier names, written instance:uuid. The answer is one card, read on every catalogue that holds the record and reached by the link each of them publishes to the same record elsewhere. Every value names the catalogues that said it, and where they disagree the reading nobody preferred is published beside the one that won. Name 'sources' to read one catalogue alone.

NameRequiredDescriptionDefault
idYes
preferNoThe order the catalogues are preferred in where they disagree on a field. Left out, the registry's own order stands, and every card states the order applied.
sourcesNo
sectionsNoThe blocks read beside the record's own fields, which come back whatever is written here. Each name adds a block, and 'basic' asks for those fields alone.

Output Schema

NameRequiredDescription
cardYes
cachedNo

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond readOnlyHint/openWorldHint, the description discloses the core behavior: the card is assembled across every catalogue holding the record, each value carries provenance, and losing values are surfaced next to winners. That is substantive context an agent could not get from annotations, though the phrasing about "the link each of them publishes" is hard to parse.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded, but the middle sentences are circuitous ("reached by the link each of them publishes to the same record elsewhere") and spend words on federated detail without crisp structure. It is not bloated, but it is harder to skim than it needs to be.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-record read with an output schema and read-only annotations, the description covers the essential behavior: cross-catalogue aggregation, provenance, and conflict display. Minor gaps remain around missing-record handling and what 'prefer' defaults to beyond the schema's own note.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 50% schema coverage, the description compensates by explaining the id form ("instance:uuid") and the effect of 'sources' (read one catalogue alone), plus how disagreement resolution relates to preference. It leaves 'sections' and 'prefer' largely to their schema descriptions, which do exist.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

"Read one scene from the catalogue its identifier names" gives a specific verb and resource, and the mention of "one scene" versus the federated lookup implicitly separates it from search_scenes. It never names a sibling outright, so differentiation rests on inference.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The only selection guidance is the closing clause "Name 'sources' to read one catalogue alone," which tells the agent how to narrow scope. There is no explicit statement of when to call this instead of search_scenes or get_sources, or what to do when the id is unknown.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_sourcesWhat each catalogue answersA
Read-only

What each configured stash-box catalogue was measured answering, and the day its surface was read from it. Whether a key is held for a catalogue is a fact about this install and changes nothing about what the catalogue does. Reaches no catalogue and takes no argument.

NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription
notesYes
sourcesYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds valuable context beyond the readOnlyHint: it states 'Reaches no catalogue,' clarifying that the tool performs no network calls to external sources. It also explains that the key-holding fact is local and does not affect catalogue behavior, which is useful behavioral transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences, front-loads the purpose, and every sentence adds value. The second sentence clarifies an important nuance about key holding without being verbose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter tool with an output schema, the description covers the semantic meaning of the data (what catalogues answer, reading date, location of configuration facts) and explicitly states it reaches no catalogue. This is complete for the tool's complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, and the description explicitly confirms 'takes no argument.' While there's no parameter detail to add, this meets the baseline for a zero-parameter tool.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states what the tool does: it reports what each configured stash-box catalogue was measured answering and the date its surface was read. This is distinct from the sibling search/get tools, which operate on specific entities. The verb and resource are evident.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage (e.g., to inspect catalogue capabilities and reading dates) but does not explicitly say when to use this tool versus alternatives. It mentions 'Reaches no catalogue' which hints at safety but lacks explicit exclusions or alternative references.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_studioGet one studioA
Read-only

Read one studio from the catalogue its identifier names, written instance:uuid. The answer is one card, read on every catalogue that holds the record and reached by the link each of them publishes to the same record elsewhere. Every value names the catalogues that said it, and where they disagree the reading nobody preferred is published beside the one that won. Name 'sources' to read one catalogue alone.

NameRequiredDescriptionDefault
idYes
preferNoThe order the catalogues are preferred in where they disagree on a field. Left out, the registry's own order stands, and every card states the order applied.
sourcesNo

Output Schema

NameRequiredDescription
cardYes
cachedNo

TDQS

A3.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover readOnly and openWorld, so the added value is the federation behavior: the record is read across every catalogue holding it, values are attributed to their source, and disagreements surface the non-preferred reading beside the winner. That is genuine behavioral context beyond annotations, though the wording is dense and the response shape is left vague (covered by the output schema).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is appropriately short in sentence count, but the sentences are ornate and front-loading suffers — 'one card, read on every catalogue that holds the record and reached by the link each of them publishes to the same record elsewhere' takes effort to parse. Content mostly earns its place; the phrasing does not.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The output schema means return shape needn't be explained, yet the description spends effort gesturing at the card rather than crisply covering the merge/ordering semantics. For a federated-read tool with a partially documented schema, the essentials are present but not fully nailed down.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 33%: 'prefer' is documented in the schema, but 'sources' has no schema description and 'id' only has a pattern. The description compensates by explaining the id format (instance:uuid) and that 'sources' restricts reading to a single named catalogue, adding meaning the schema lacks.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource: 'Read one studio from the catalogue its identifier names,' which clearly separates it from search_studios. The purpose is discernible but wrapped in ornate phrasing ('the catalogue its identifier names') that slows comprehension versus a plain 'fetch a single studio record by ID.'

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when to use 'sources' (to read one catalogue alone) and mentions 'prefer' for ordering, which is useful conditional guidance. However, it never explicitly contrasts with search_studios (listing) or get_sources (catalogue listing), so the agent must infer the routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_tagGet one tagB
Read-only

Read one tag from the catalogue its identifier names, written instance:uuid. The answer is one card, read on every catalogue that holds the record and reached by the link each of them publishes to the same record elsewhere. Every value names the catalogues that said it, and where they disagree the reading nobody preferred is published beside the one that won. Name 'sources' to read one catalogue alone.

NameRequiredDescriptionDefault
idYes
preferNoThe order the catalogues are preferred in where they disagree on a field. Left out, the registry's own order stands, and every card states the order applied.
sourcesNo

Output Schema

NameRequiredDescription
cardYes
cachedNo

TDQS

B3.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint and openWorldHint, so the description's added value is the federation model: the card is assembled across every catalogue holding the record, each value is attributed to the catalogues that asserted it, and disagreements expose both the winning and non-preferred readings. That is genuine behavioral context an agent cannot get from the structured fields, though the not-found / partial-failure behavior is unstated.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded and the four sentences all carry content, but the phrasing is needlessly riddling — "the reading nobody preferred is published beside the one that won" must be decoded, and "instance:uuid" is imprecise where a catalogue prefix is what is actually required.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, return shape need not be explained (though the description does sketch the card). Missing pieces remain: behavior when the id resolves to nothing, which prefix to supply, and how this relates to get_sources, which is directly relevant given the 'sources' parameter overlap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 33%: 'id' has a pattern but no prose and 'sources' has no description at all. The description partially compensates by explaining that naming 'sources' restricts to one catalogue and by gesturing at preference ordering ("the reading nobody preferred"), but it never ties that explicitly to 'prefer' and leaves the id prefix format ambiguous.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

"Read one tag from the catalogue its identifier names" states the verb and resource, but the qualifier "written instance:uuid" is cryptic and does not match the schema's actual '<catalogue>:<uuid>' prefixes. Nothing distinguishes it from search_tags or get_sources, so the agent must infer it is the single-record lookup for tags.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The only guidance is "Name 'sources' to read one catalogue alone," which is a conditional usage hint for one parameter rather than a when-to-use-this-vs-alternatives statement. No mention of search_tags for discovery or get_sources for catalogue metadata, so usage is implied at best.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_performersSearch performersA
Read-only

Search performers across every configured stash-box catalogue. Two exclusive paths: 'query' runs each catalogue's own text index, which reads the words as a union, and the typed arguments narrow as an intersection. Writing both is refused. The answer says per catalogue which of three it met: a failure, a catalogue nobody asked, and an emptiness it established. Counts are never added across them.

NameRequiredDescriptionDefault
nameNo
pageNoWhich page of its own order every catalogue asked is read at, counted from 1. A search written with words alone reads the first rows each text index answers with, since those routes take no page.
sortNo
aliasNoNo catalogue's faceted route applies it, though every faceted input declares it: a request carrying it answers as wide as one carrying none, so it is never sent and the answer names it as a narrowing nobody received.
limitNoHow many rows one page of one catalogue carries. An answer holding several carries up to this many from each: their pages are their own and nothing here interleaves them into one.
queryNoWords for the catalogue's own text index, which reads them as a union. It is exclusive with the typed arguments, which narrow as an intersection.
genderNo
countryNo
sourcesNo
directionNo
ethnicityNo
studio_idNo
birth_yearNo
disambiguationNo
performed_withNo
career_end_yearNoNo catalogue's faceted route applies it, though every faceted input declares it: a request carrying it answers as wide as one carrying none, so it is never sent and the answer names it as a narrowing nobody received.
career_start_yearNoNo catalogue's faceted route applies it, though every faceted input declares it: a request carrying it answers as wide as one carrying none, so it is never sent and the answer names it as a narrowing nobody received.

Output Schema

NameRequiredDescription
notesYes
cachedNoReplayed from this client's store.
windowNoThe page and the row limit this answer was read at, absent where no catalogue answered.
resultsYes
orderingYesHow the rows were laid out, which a reader needs before reading the first.
per_sourceYes
result_countYesHow many rows this page carries.

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond readOnlyHint/openWorldHint it discloses substantive behaviour: results are per-catalogue, counts are never aggregated, pagination is per-catalogue and nothing is interleaved, and each catalogue returns one of three outcome states. That is genuine value the annotations do not provide. Deduction because the wording is oblique ('an emptiness it established') and never states what a partial catalogue failure means for the overall response.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is front-loaded and only four sentences, so it is not bloated, but the prose is heavily circumlocuted — 'the answer says per catalogue which of three it met' and 'a narrowing nobody received' force the reader to decode rather than absorb. Plain phrasing would deliver the same content in half the space.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With 17 optional parameters at 35% description coverage and no required fields, the description carries real weight and does cover the query/typed split and cross-catalogue result semantics. It still leaves uncovered defaults such as which catalogues are searched when 'sources' is omitted, what sort/direction default to, and whether partial catalogue failures are surfaced as errors.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 35%, but the description does add the single most important semantic: query is a union-mode text search that is mutually exclusive with the intersection-style typed filters. However, roughly a dozen filters (sort, direction, sources, gender, country, studio_id, birth_year, performed_with, disambiguation) get no guidance at all, and the note about ignored parameters merely restates what the schema already says.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

"Search performers across every configured stash-box catalogue" gives a specific verb and resource plus the scope (all configured catalogues), which clearly separates it from search_scenes/search_studios and from get_performer. It stops short of naming those siblings as alternatives, but the purpose itself is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly frames two mutually exclusive invocation paths ('query' for text index vs typed arguments for intersection) and states that supplying both 'is refused', which is real routing guidance. It says nothing about when to call this versus get_performer or the other search_* siblings, so it is not a full 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_scenesSearch scenesA
Read-only

Search scenes across every configured stash-box catalogue. Two exclusive paths: 'query' runs each catalogue's own text index, which reads the words as a union, and the typed arguments narrow as an intersection. Writing both is refused. The answer says per catalogue which of three it met: a failure, a catalogue nobody asked, and an emptiness it established. Counts are never added across them.

NameRequiredDescriptionDefault
codeNo
dateNo
pageNoWhich page of its own order every catalogue asked is read at, counted from 1. A search written with words alone reads the first rows each text index answers with, since those routes take no page.
sortNo
aliasNoNo catalogue's faceted route applies it, though every faceted input declares it: a request carrying it answers as wide as one carrying none, so it is never sent and the answer names it as a narrowing nobody received.
limitNoHow many rows one page of one catalogue carries. An answer holding several carries up to this many from each: their pages are their own and nothing here interleaves them into one.
matchNoHow performer_ids and tag_ids are read, which are the only arguments it governs. 'all', the default, asks for scenes carrying every identifier of a list; 'any' for scenes carrying at least one, which answers counts an order of magnitude wider. A scene names one studio, so studio_ids asks for any of its identifiers under both readings. The lists narrow against each other as an intersection either way.
queryNoWords for the catalogue's own text index, which reads them as a union. It is exclusive with the typed arguments, which narrow as an intersection.
titleNo
sourcesNo
tag_idsNo
directionNo
studio_idsNo
date_compareNoThese catalogues compare a date against one bound and answer no range, so the comparison is written rather than assumed.
performer_idsNo
parent_studio_idNo

Output Schema

NameRequiredDescription
notesYes
cachedNoReplayed from this client's store.
windowNoThe page and the row limit this answer was read at, absent where no catalogue answered.
resultsYes
orderingYesHow the rows were laid out, which a reader needs before reading the first.
per_sourceYes
result_countYesHow many rows this page carries.

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint and openWorldHint, so the safety profile is covered. The description adds real value about the response model: per-catalogue statuses and counts that are never summed across catalogues. But the phrasing ('an emptiness it established') is so indirect that the behavioral value is diluted and partially obscured.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded in the first sentence, but the remainder is written in dense, cryptic prose that reads more like riddles than specification. Every sentence does carry information, yet the obscurity costs parsing effort, so conciseness is undercut by unclarity rather than verbosity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With 16 parameters, an output schema, and read-only annotations, the description covers the key complexity (mode exclusivity, per-catalogue result handling). Yet with 10 parameters undocumented and coverage at 38%, an agent is left guessing at the semantics of significant filters, so it is only minimally complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 38%, so the description must compensate. It does explain the union-vs-intersection logic distinguishing 'query' from typed arguments and reasserts the alias exclusion, but several parameters (code, date, title, sort, direction, sources, parent_studio_id) get no treatment and are undocumented in the schema as well.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource with scope: 'Search scenes across every configured stash-box catalogue.' This distinguishes it from the single-object sibling get_scene and from the other search_* tools by resource. However, the following sentences drift into opaque phrasing rather than sharpening the differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly defines two mutually exclusive modes ('query' vs typed arguments) and states that writing both 'is refused', which is a clear when/when-not rule. It does not route the agent toward siblings like get_scene for single lookups, so it stops short of full alternative guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_studiosSearch studiosA
Read-only

Search studios across every configured stash-box catalogue. Two exclusive paths: 'query' runs each catalogue's own text index, which reads the words as a union, and the typed arguments narrow as an intersection. Writing both is refused. The answer says per catalogue which of three it met: a failure, a catalogue nobody asked, and an emptiness it established. Counts are never added across them.

NameRequiredDescriptionDefault
nameNo
pageNoWhich page of its own order every catalogue asked is read at, counted from 1. A search written with words alone reads the first rows each text index answers with, since those routes take no page.
sortNo
limitNoHow many rows one page of one catalogue carries. An answer holding several carries up to this many from each: their pages are their own and nothing here interleaves them into one.
queryNoWords for the catalogue's own text index, which reads them as a union. It is exclusive with the typed arguments, which narrow as an intersection.
sourcesNo
directionNo
parent_idNo
has_parentNo

Output Schema

NameRequiredDescription
notesYes
cachedNoReplayed from this client's store.
windowNoThe page and the row limit this answer was read at, absent where no catalogue answered.
resultsYes
orderingYesHow the rows were laid out, which a reader needs before reading the first.
per_sourceYes
result_countYesHow many rows this page carries.

TDQS

A3.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover read-only and open-world, and the description adds genuinely non-obvious behavior: per-catalogue results in three distinct states, no cross-catalogue aggregation of counts, and rejection of combined query+typed-args requests. The phrasing of the three states is oblique ('a catalogue nobody asked') but the disclosure is substantive.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded and free of filler, but the prose turns oracular in places ('an emptiness it established', 'which of three it met'), forcing the reader to decode rather than read. The exclusivity rule, arguably the most important constraint, is buried mid-paragraph.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so explaining return format is optional, yet the description chooses to describe result semantics while omitting how sources default and whether any filters are mandatory. For a 9-parameter multi-catalogue search this leaves meaningful gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With only 33% schema coverage across 9 parameters, the description needs to compensate; it explains query versus typed-argument semantics well but says nothing about name, sources (defaulting, selection), sort/direction per catalogue, or parent_id/has_parent filtering. Schema handles page and limit; the rest is left thin.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence names a specific verb (search) and resource (studios) and scopes it to stash-box catalogues, which differentiates it from the scene/performer/tag search siblings by resource alone. It stops short of explicitly contrasting itself with get_studio or naming which sibling handles what.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly states the mutual exclusivity of 'query' and the typed arguments and that writing both is refused, which is real usage guidance. It gives no guidance on when to prefer this tool over search_scenes or get_studio, nor when each path is the better choice beyond the union/intersection hint.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_tagsSearch tagsA
Read-only

Search tags across every configured stash-box catalogue. Two exclusive paths: 'query' runs each catalogue's own text index, which reads the words as a union, and the typed arguments narrow as an intersection. Writing both is refused. The answer says per catalogue which of three it met: a failure, a catalogue nobody asked, and an emptiness it established. Counts are never added across them.

NameRequiredDescriptionDefault
nameNo
pageNoWhich page of its own order every catalogue asked is read at, counted from 1. A search written with words alone reads the first rows each text index answers with, since those routes take no page.
sortNo
limitNoHow many rows one page of one catalogue carries. An answer holding several carries up to this many from each: their pages are their own and nothing here interleaves them into one.
queryNoWords for the catalogue's own text index, which reads them as a union. It is exclusive with the typed arguments, which narrow as an intersection.
sourcesNo
directionNo
category_idNo

Output Schema

NameRequiredDescription
notesYes
cachedNoReplayed from this client's store.
windowNoThe page and the row limit this answer was read at, absent where no catalogue answered.
resultsYes
orderingYesHow the rows were laid out, which a reader needs before reading the first.
per_sourceYes
result_countYesHow many rows this page carries.

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover readOnly and open-world, so the bar is lower, and the description still adds substantive behavior: results are reported per catalogue with three distinct outcomes (failure, unasked catalogue, established emptiness) and 'Counts are never added across them.' The phrasing is cryptic, but the semantics are there.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded and there is no filler, but the deliberately oblique phrasing ('an emptiness it established', 'a catalogue nobody asked') makes an already dense passage harder to parse than plain wording would. The style costs clarity without adding information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Output schema exists, so return values needn't be spelled out, and the description usefully explains per-catalogue outcome semantics and mode exclusivity. It still omits what sources defaults to, how sort/direction interact with the text-index path, and what category_id constrains — gaps that matter for an 8-parameter tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 38% schema coverage, the description compensates for the most important gap by explaining that 'query' is a union text search exclusive with the intersection-style typed arguments. However, name, sources, sort, direction, and category_id receive no explanation anywhere, leaving half the surface undocumented.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence gives a specific verb and resource ('Search tags across every configured stash-box catalogue'), which is enough to separate it from get_tag and the search_scenes/performers/studios siblings. It does not explicitly name an alternative or exclusion, so it stops short of a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly states the two modes of use — 'query' for a catalogue's own text index versus typed arguments as an intersection — and that 'Writing both is refused.' This is real when-to-use guidance for the parameter modes, though it never contrasts the tool against get_tag for single-record lookup.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 9 tool updatesv2.1.0
    • Changedfind_by_fingerprint2 fields changed
      • removedOutput schema / properties / matches / items / properties / scene / properties / counts / additionalProperties / items / properties / value / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / matches / items / properties / scene / properties / counts / additionalProperties / items / properties / value / type
        Added value: +[
        +  "number",
        +  "null"
        +]
    • Changedget_performer2 fields changed
      • removedOutput schema / properties / card / properties / counts / additionalProperties / items / properties / value / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / card / properties / counts / additionalProperties / items / properties / value / type
        Added value: +[
        +  "number",
        +  "null"
        +]
    • Changedget_scene2 fields changed
      • removedOutput schema / properties / card / properties / counts / additionalProperties / items / properties / value / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / card / properties / counts / additionalProperties / items / properties / value / type
        Added value: +[
        +  "number",
        +  "null"
        +]
    • Changedget_studio2 fields changed
      • removedOutput schema / properties / card / properties / counts / additionalProperties / items / properties / value / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / card / properties / counts / additionalProperties / items / properties / value / type
        Added value: +[
        +  "number",
        +  "null"
        +]
    • Changedget_tag2 fields changed
      • removedOutput schema / properties / card / properties / counts / additionalProperties / items / properties / value / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / card / properties / counts / additionalProperties / items / properties / value / type
        Added value: +[
        +  "number",
        +  "null"
        +]
    • Changedsearch_performers18 fields changed
      • removedOutput schema / properties / results / items / properties / career_end_year / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / career_end_year / type
        Added value: +[
        +  "number",
        +  "null"
        +]
      • removedOutput schema / properties / results / items / properties / career_start_year / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / career_start_year / type
        Added value: +[
        +  "number",
        +  "null"
        +]
      • removedOutput schema / properties / results / items / properties / country / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / country / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / results / items / properties / disambiguation / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / disambiguation / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / results / items / properties / gender / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / gender / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / results / items / properties / merged_into / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / merged_into / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / results / items / properties / name / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / name / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / results / items / properties / pending_edits / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / pending_edits / type
        Added value: +[
        +  "number",
        +  "null"
        +]
      • removedOutput schema / properties / results / items / properties / scene_count / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / scene_count / type
        Added value: +[
        +  "number",
        +  "null"
        +]
    • Changedsearch_scenes17 fields changed
      • removedOutput schema / properties / results / items / properties / code / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / code / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / results / items / properties / duration_seconds / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / duration_seconds / type
        Added value: +[
        +  "number",
        +  "null"
        +]
      • removedOutput schema / properties / results / items / properties / pending_edits / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / pending_edits / type
        Added value: +[
        +  "number",
        +  "null"
        +]
      • removedOutput schema / properties / results / items / properties / performers / items / properties / creditedAs / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / performers / items / properties / creditedAs / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / results / items / properties / performers / items / properties / disambiguation / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / performers / items / properties / disambiguation / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / results / items / properties / performers / items / properties / name / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / performers / items / properties / name / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • changedOutput schema / properties / results / items / properties / studio / anyOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "id": {
        -        "type": "string"
        -      },
        -      "name": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "parent": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "parentWithdrawn": {
        -        "type": "boolean"
        -      },
        -      "status": {
        -        "enum": [
        -          "established",
        -          "merged",
        -          "deleted"
        -        ],
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "id",
        -      "name",
        -      "parent",
        -      "status"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "id": {
        +        "type": "string"
        +      },
        +      "name": {
        +        "type": [
        +          "string",
        +          "null"
        +        ]
        +      },
        +      "parent": {
        +        "type": [
        +          "string",
        +          "null"
        +        ]
        +      },
        +      "parentWithdrawn": {
        +        "type": "boolean"
        +      },
        +      "status": {
        +        "enum": [
        +          "established",
        +          "merged",
        +          "deleted"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "id",
        +      "name",
        +      "parent",
        +      "status"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedOutput schema / properties / results / items / properties / tags / items / properties / name / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / tags / items / properties / name / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / results / items / properties / title / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / title / type
        Added value: +[
        +  "string",
        +  "null"
        +]
    • Changedsearch_studios7 fields changed
      • removedOutput schema / properties / results / items / properties / name / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / name / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • changedOutput schema / properties / results / items / properties / parent / anyOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "id": {
        -        "type": "string"
        -      },
        -      "name": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "status": {
        -        "enum": [
        -          "established",
        -          "merged",
        -          "deleted"
        -        ],
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "id",
        -      "name",
        -      "status"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "id": {
        +        "type": "string"
        +      },
        +      "name": {
        +        "type": [
        +          "string",
        +          "null"
        +        ]
        +      },
        +      "status": {
        +        "enum": [
        +          "established",
        +          "merged",
        +          "deleted"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "id",
        +      "name",
        +      "status"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedOutput schema / properties / results / items / properties / pending_edits / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / pending_edits / type
        Added value: +[
        +  "number",
        +  "null"
        +]
      • removedOutput schema / properties / results / items / properties / scene_count / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / scene_count / type
        Added value: +[
        +  "number",
        +  "null"
        +]
    • Changedsearch_tags7 fields changed
      • changedOutput schema / properties / results / items / properties / category / anyOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "group": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "id": {
        -        "type": "string"
        -      },
        -      "name": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      }
        -    },
        -    "required": [
        -      "id",
        -      "name",
        -      "group"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "group": {
        +        "type": [
        +          "string",
        +          "null"
        +        ]
        +      },
        +      "id": {
        +        "type": "string"
        +      },
        +      "name": {
        +        "type": [
        +          "string",
        +          "null"
        +        ]
        +      }
        +    },
        +    "required": [
        +      "id",
        +      "name",
        +      "group"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedOutput schema / properties / results / items / properties / description / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / description / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / results / items / properties / name / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / name / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / results / items / properties / pending_edits / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / results / items / properties / pending_edits / type
        Added value: +[
        +  "number",
        +  "null"
        +]
  2. 9 tool updatesv1.0.0
    • Changedfind_by_fingerprint6 fields changed
      • changedInput schema / properties / prefer / description
        Previous value: -"The order the catalogues are preferred in where they disagree on a field. Left out, the order the registry declares stands. Every card states the order that was applied."New value: +"The order the catalogues are preferred in where they disagree on a field. Left out, the registry's own order stands, and every card states the order applied."
      • changedOutput schema / properties / match_count / description
        Previous value: -"One per record reached, whatever number of hashes reached it."New value: +"One per card here. Every hash that reached a record names it on one card, and a record reached both by an exact hash and by a perceptual one stands as two, since the two claim different things about it. Read records_named for how many files were named, which counts each once."
      • changedOutput schema / properties / matches / items / properties / scene / properties / held_by / description
        Previous value: -"Every catalogue asked, with the identifier the record carries there."New value: +"Every catalogue asked, with the identifier the record carries there. This is where what each of them did with the record is read: the state says which of the three it met, and the reason says why it was not asked or what went wrong."
      • changedOutput schema / properties / per_source / items / properties / index_total / description
        Previous value: -"What its own index holds for this question, the rows on this page included."New value: +"What its own index holds for the question it received, the rows on this page included. A narrowing it could not receive, or received in part, leaves that question wider than the one written."
      • changedOutput schema / properties / per_source / items / properties / narrowings_not_received / description
        Previous value: -"Narrowings this catalogue cannot receive. This is the one field that says a catalogue cannot do something."New value: +"Narrowings that shaped no part of the request this catalogue received, whether its route declares no field for one or nothing written was left for one to decide."
      • addedOutput schema / properties / per_source / items / properties / narrowings_received_in_part / description
        Added value: +"Narrowings it received short of what was written, the rest of the list naming records another catalogue minted. It answered a wider question than the one asked."
    • Changedget_performer3 fields changed
      • changedInput schema / properties / prefer / description
        Previous value: -"The order the catalogues are preferred in where they disagree on a field. Left out, the order the registry declares stands. Every card states the order that was applied."New value: +"The order the catalogues are preferred in where they disagree on a field. Left out, the registry's own order stands, and every card states the order applied."
      • changedOutput schema / properties / card / properties / held_by / description
        Previous value: -"Every catalogue asked, with the identifier the record carries there."New value: +"Every catalogue asked, with the identifier the record carries there. This is where what each of them did with the record is read: the state says which of the three it met, and the reason says why it was not asked or what went wrong."
      • removedOutput schema / properties / per_source
        Removed value: -{
        -  "items": {
        -    "additionalProperties": false,
        -    "properties": {
        -      "algorithms_not_searched": {
        -        "description": "Fingerprint algorithms its lookup does not search, so they were never put to it.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "count": {
        -        "description": "Rows it contributed. Never added to another catalogue's: they index corpora that overlap by an amount none of them publishes.",
        -        "type": "number"
        -      },
        -      "error": {
        -        "enum": [
        -          "not_found",
        -          "invalid_input",
        -          "rate_limited",
        -          "parse_failure",
        -          "network_error",
        -          "timeout"
        -        ],
        -        "type": "string"
        -      },
        -      "index_total": {
        -        "description": "What its own index holds for this question, the rows on this page included.",
        -        "type": "number"
        -      },
        -      "index_total_over_any_word": {
        -        "description": "The total counts rows carrying any word of the query, its text index reading them apart.",
        -        "type": "boolean"
        -      },
        -      "moment": {
        -        "description": "Which moment failed.",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "The name that catalogue calls itself.",
        -        "type": "string"
        -      },
        -      "narrowings_naming_no_record": {
        -        "description": "Narrowings written only with identifiers another catalogue minted.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "narrowings_not_received": {
        -        "description": "Narrowings this catalogue cannot receive. This is the one field that says a catalogue cannot do something.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "narrowings_received_in_part": {
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "reason": {
        -        "description": "Why it was not asked, or what went wrong.",
        -        "type": "string"
        -      },
        -      "records": {
        -        "description": "Distinct records behind its rows.",
        -        "type": "number"
        -      },
        -      "skipped": {
        -        "description": "Rows it answered with that this client could not read and left out.",
        -        "type": "number"
        -      },
        -      "source": {
        -        "description": "The catalogue this row is about.",
        -        "type": "string"
        -      },
        -      "state": {
        -        "description": "'answered' looked, and a count of zero means it found nothing. 'failed' could not answer, and states nothing about what it holds. 'absent' was never asked. Only the first is evidence about the world.",
        -        "enum": [
        -          "answered",
        -          "failed",
        -          "absent"
        -        ],
        -        "type": "string"
        -      },
        -      "unattributed": {
        -        "description": "Records it answered with while carrying none of what was asked about.",
        -        "type": "number"
        -      }
        -    },
        -    "required": [
        -      "source",
        -      "state"
        -    ],
        -    "type": "object"
        -  },
        -  "type": "array"
        -}
    • Changedget_scene3 fields changed
      • changedInput schema / properties / prefer / description
        Previous value: -"The order the catalogues are preferred in where they disagree on a field. Left out, the order the registry declares stands. Every card states the order that was applied."New value: +"The order the catalogues are preferred in where they disagree on a field. Left out, the registry's own order stands, and every card states the order applied."
      • changedOutput schema / properties / card / properties / held_by / description
        Previous value: -"Every catalogue asked, with the identifier the record carries there."New value: +"Every catalogue asked, with the identifier the record carries there. This is where what each of them did with the record is read: the state says which of the three it met, and the reason says why it was not asked or what went wrong."
      • removedOutput schema / properties / per_source
        Removed value: -{
        -  "items": {
        -    "additionalProperties": false,
        -    "properties": {
        -      "algorithms_not_searched": {
        -        "description": "Fingerprint algorithms its lookup does not search, so they were never put to it.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "count": {
        -        "description": "Rows it contributed. Never added to another catalogue's: they index corpora that overlap by an amount none of them publishes.",
        -        "type": "number"
        -      },
        -      "error": {
        -        "enum": [
        -          "not_found",
        -          "invalid_input",
        -          "rate_limited",
        -          "parse_failure",
        -          "network_error",
        -          "timeout"
        -        ],
        -        "type": "string"
        -      },
        -      "index_total": {
        -        "description": "What its own index holds for this question, the rows on this page included.",
        -        "type": "number"
        -      },
        -      "index_total_over_any_word": {
        -        "description": "The total counts rows carrying any word of the query, its text index reading them apart.",
        -        "type": "boolean"
        -      },
        -      "moment": {
        -        "description": "Which moment failed.",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "The name that catalogue calls itself.",
        -        "type": "string"
        -      },
        -      "narrowings_naming_no_record": {
        -        "description": "Narrowings written only with identifiers another catalogue minted.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "narrowings_not_received": {
        -        "description": "Narrowings this catalogue cannot receive. This is the one field that says a catalogue cannot do something.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "narrowings_received_in_part": {
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "reason": {
        -        "description": "Why it was not asked, or what went wrong.",
        -        "type": "string"
        -      },
        -      "records": {
        -        "description": "Distinct records behind its rows.",
        -        "type": "number"
        -      },
        -      "skipped": {
        -        "description": "Rows it answered with that this client could not read and left out.",
        -        "type": "number"
        -      },
        -      "source": {
        -        "description": "The catalogue this row is about.",
        -        "type": "string"
        -      },
        -      "state": {
        -        "description": "'answered' looked, and a count of zero means it found nothing. 'failed' could not answer, and states nothing about what it holds. 'absent' was never asked. Only the first is evidence about the world.",
        -        "enum": [
        -          "answered",
        -          "failed",
        -          "absent"
        -        ],
        -        "type": "string"
        -      },
        -      "unattributed": {
        -        "description": "Records it answered with while carrying none of what was asked about.",
        -        "type": "number"
        -      }
        -    },
        -    "required": [
        -      "source",
        -      "state"
        -    ],
        -    "type": "object"
        -  },
        -  "type": "array"
        -}
    • Changedget_studio3 fields changed
      • changedInput schema / properties / prefer / description
        Previous value: -"The order the catalogues are preferred in where they disagree on a field. Left out, the order the registry declares stands. Every card states the order that was applied."New value: +"The order the catalogues are preferred in where they disagree on a field. Left out, the registry's own order stands, and every card states the order applied."
      • changedOutput schema / properties / card / properties / held_by / description
        Previous value: -"Every catalogue asked, with the identifier the record carries there."New value: +"Every catalogue asked, with the identifier the record carries there. This is where what each of them did with the record is read: the state says which of the three it met, and the reason says why it was not asked or what went wrong."
      • removedOutput schema / properties / per_source
        Removed value: -{
        -  "items": {
        -    "additionalProperties": false,
        -    "properties": {
        -      "algorithms_not_searched": {
        -        "description": "Fingerprint algorithms its lookup does not search, so they were never put to it.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "count": {
        -        "description": "Rows it contributed. Never added to another catalogue's: they index corpora that overlap by an amount none of them publishes.",
        -        "type": "number"
        -      },
        -      "error": {
        -        "enum": [
        -          "not_found",
        -          "invalid_input",
        -          "rate_limited",
        -          "parse_failure",
        -          "network_error",
        -          "timeout"
        -        ],
        -        "type": "string"
        -      },
        -      "index_total": {
        -        "description": "What its own index holds for this question, the rows on this page included.",
        -        "type": "number"
        -      },
        -      "index_total_over_any_word": {
        -        "description": "The total counts rows carrying any word of the query, its text index reading them apart.",
        -        "type": "boolean"
        -      },
        -      "moment": {
        -        "description": "Which moment failed.",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "The name that catalogue calls itself.",
        -        "type": "string"
        -      },
        -      "narrowings_naming_no_record": {
        -        "description": "Narrowings written only with identifiers another catalogue minted.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "narrowings_not_received": {
        -        "description": "Narrowings this catalogue cannot receive. This is the one field that says a catalogue cannot do something.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "narrowings_received_in_part": {
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "reason": {
        -        "description": "Why it was not asked, or what went wrong.",
        -        "type": "string"
        -      },
        -      "records": {
        -        "description": "Distinct records behind its rows.",
        -        "type": "number"
        -      },
        -      "skipped": {
        -        "description": "Rows it answered with that this client could not read and left out.",
        -        "type": "number"
        -      },
        -      "source": {
        -        "description": "The catalogue this row is about.",
        -        "type": "string"
        -      },
        -      "state": {
        -        "description": "'answered' looked, and a count of zero means it found nothing. 'failed' could not answer, and states nothing about what it holds. 'absent' was never asked. Only the first is evidence about the world.",
        -        "enum": [
        -          "answered",
        -          "failed",
        -          "absent"
        -        ],
        -        "type": "string"
        -      },
        -      "unattributed": {
        -        "description": "Records it answered with while carrying none of what was asked about.",
        -        "type": "number"
        -      }
        -    },
        -    "required": [
        -      "source",
        -      "state"
        -    ],
        -    "type": "object"
        -  },
        -  "type": "array"
        -}
    • Changedget_tag3 fields changed
      • changedInput schema / properties / prefer / description
        Previous value: -"The order the catalogues are preferred in where they disagree on a field. Left out, the order the registry declares stands. Every card states the order that was applied."New value: +"The order the catalogues are preferred in where they disagree on a field. Left out, the registry's own order stands, and every card states the order applied."
      • changedOutput schema / properties / card / properties / held_by / description
        Previous value: -"Every catalogue asked, with the identifier the record carries there."New value: +"Every catalogue asked, with the identifier the record carries there. This is where what each of them did with the record is read: the state says which of the three it met, and the reason says why it was not asked or what went wrong."
      • removedOutput schema / properties / per_source
        Removed value: -{
        -  "items": {
        -    "additionalProperties": false,
        -    "properties": {
        -      "algorithms_not_searched": {
        -        "description": "Fingerprint algorithms its lookup does not search, so they were never put to it.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "count": {
        -        "description": "Rows it contributed. Never added to another catalogue's: they index corpora that overlap by an amount none of them publishes.",
        -        "type": "number"
        -      },
        -      "error": {
        -        "enum": [
        -          "not_found",
        -          "invalid_input",
        -          "rate_limited",
        -          "parse_failure",
        -          "network_error",
        -          "timeout"
        -        ],
        -        "type": "string"
        -      },
        -      "index_total": {
        -        "description": "What its own index holds for this question, the rows on this page included.",
        -        "type": "number"
        -      },
        -      "index_total_over_any_word": {
        -        "description": "The total counts rows carrying any word of the query, its text index reading them apart.",
        -        "type": "boolean"
        -      },
        -      "moment": {
        -        "description": "Which moment failed.",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "The name that catalogue calls itself.",
        -        "type": "string"
        -      },
        -      "narrowings_naming_no_record": {
        -        "description": "Narrowings written only with identifiers another catalogue minted.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "narrowings_not_received": {
        -        "description": "Narrowings this catalogue cannot receive. This is the one field that says a catalogue cannot do something.",
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "narrowings_received_in_part": {
        -        "items": {
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "reason": {
        -        "description": "Why it was not asked, or what went wrong.",
        -        "type": "string"
        -      },
        -      "records": {
        -        "description": "Distinct records behind its rows.",
        -        "type": "number"
        -      },
        -      "skipped": {
        -        "description": "Rows it answered with that this client could not read and left out.",
        -        "type": "number"
        -      },
        -      "source": {
        -        "description": "The catalogue this row is about.",
        -        "type": "string"
        -      },
        -      "state": {
        -        "description": "'answered' looked, and a count of zero means it found nothing. 'failed' could not answer, and states nothing about what it holds. 'absent' was never asked. Only the first is evidence about the world.",
        -        "enum": [
        -          "answered",
        -          "failed",
        -          "absent"
        -        ],
        -        "type": "string"
        -      },
        -      "unattributed": {
        -        "description": "Records it answered with while carrying none of what was asked about.",
        -        "type": "number"
        -      }
        -    },
        -    "required": [
        -      "source",
        -      "state"
        -    ],
        -    "type": "object"
        -  },
        -  "type": "array"
        -}
    • Changedsearch_performers32 fields changed
      • addedInput schema / properties / alias / description
        Added value: +"No catalogue's faceted route applies it, though every faceted input declares it: a request carrying it answers as wide as one carrying none, so it is never sent and the answer names it as a narrowing nobody received."
      • addedInput schema / properties / career_end_year / description
        Added value: +"No catalogue's faceted route applies it, though every faceted input declares it: a request carrying it answers as wide as one carrying none, so it is never sent and the answer names it as a narrowing nobody received."
      • addedInput schema / properties / career_start_year / description
        Added value: +"No catalogue's faceted route applies it, though every faceted input declares it: a request carrying it answers as wide as one carrying none, so it is never sent and the answer names it as a narrowing nobody received."
      • changedInput schema / properties / limit / description
        Previous value: -"How many rows one page of one catalogue carries. An answer holding several catalogues carries up to this many from each of them, since their pages are their own and nothing here interleaves them into one."New value: +"How many rows one page of one catalogue carries. An answer holding several carries up to this many from each: their pages are their own and nothing here interleaves them into one."
      • changedInput schema / properties / page / description
        Previous value: -"The page of each catalogue's own order. A route that reads words alone takes no page, and the answer reports it as one that catalogue did not receive."New value: +"Which page of its own order every catalogue asked is read at, counted from 1. A search written with words alone reads the first rows each text index answers with, since those routes take no page."
      • changedOutput schema / properties / per_source / items / properties / index_total / description
        Previous value: -"What its own index holds for this question, the rows on this page included."New value: +"What its own index holds for the question it received, the rows on this page included. A narrowing it could not receive, or received in part, leaves that question wider than the one written."
      • changedOutput schema / properties / per_source / items / properties / narrowings_not_received / description
        Previous value: -"Narrowings this catalogue cannot receive. This is the one field that says a catalogue cannot do something."New value: +"Narrowings that shaped no part of the request this catalogue received, whether its route declares no field for one or nothing written was left for one to decide."
      • addedOutput schema / properties / per_source / items / properties / narrowings_received_in_part / description
        Added value: +"Narrowings it received short of what was written, the rest of the list naming records another catalogue minted. It answered a wider question than the one asked."
      • addedOutput schema / properties / results / items / properties / aliases
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / also_held_at
        Added value: +{
        +  "description": "The same record on another catalogue, read from a link this one publishes to it. A shared name is no join.",
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "id": {
        +        "type": "string"
        +      },
        +      "source": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "source",
        +      "id"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / birth_date
        Added value: +{
        +  "anyOf": [
        +    {
        +      "additionalProperties": false,
        +      "properties": {
        +        "precision": {
        +          "description": "How much of the date the catalogue holds: a month or a year can be all of it.",
        +          "enum": [
        +            "day",
        +            "month",
        +            "year"
        +          ],
        +          "type": "string"
        +        },
        +        "value": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "value",
        +        "precision"
        +      ],
        +      "type": "object"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ]
        +}
      • addedOutput schema / properties / results / items / properties / birth_date_unreadable
        Added value: +{
        +  "description": "A birth date was published in a shape this client could not read, so the null above is a reading that failed rather than a date nobody entered.",
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / results / items / properties / career_end_year
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "number"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ]
        +}
      • addedOutput schema / properties / results / items / properties / career_start_year
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "number"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ]
        +}
      • addedOutput schema / properties / results / items / properties / country
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ]
        +}
      • addedOutput schema / properties / results / items / properties / death_date
        Added value: +{
        +  "anyOf": [
        +    {
        +      "additionalProperties": false,
        +      "properties": {
        +        "precision": {
        +          "description": "How much of the date the catalogue holds: a month or a year can be all of it.",
        +          "enum": [
        +            "day",
        +            "month",
        +            "year"
        +          ],
        +          "type": "string"
        +        },
        +        "value": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "value",
        +        "precision"
        +      ],
        +      "type": "object"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ]
        +}
      • addedOutput schema / properties / results / items / properties / death_date_unreadable
        Added value: +{
        +  "description": "The same, for the date of death.",
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / results / items / properties / disambiguation
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "What its catalogue tells two people of one name apart by."
        +}
      • addedOutput schema / properties / results / items / properties / gender
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ]
        +}
      • addedOutput schema / properties / results / items / properties / linked_unfollowed
        Added value: +{
        +  "description": "A link to another catalogue naming the record by something this client cannot address. The link is written, and following it is what failed.",
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "source": {
        +        "type": "string"
        +      },
        +      "url": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "source",
        +      "url"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / merged_ids
        Added value: +{
        +  "description": "Identifiers folded into this record, each of which still addresses it.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / merged_into
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "The record this one was folded into, where its catalogue publishes one."
        +}
      • addedOutput schema / properties / results / items / properties / name
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ]
        +}
      • addedOutput schema / properties / results / items / properties / pending_edits
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "number"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Edits open against it, null where its catalogue publishes no such count."
        +}
      • addedOutput schema / properties / results / items / properties / pending_edits_unreadable
        Added value: +{
        +  "description": "The count of open edits came back in a shape this client could not read.",
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / results / items / properties / retrieved_at
        Added value: +{
        +  "description": "The moment this client read it there.",
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / rows_skipped
        Added value: +{
        +  "description": "Entries of this record's own lists that could not be read and are left out.",
        +  "type": "number"
        +}
      • addedOutput schema / properties / results / items / properties / rows_skipped_in
        Added value: +{
        +  "description": "Which of its lists lost them.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / scene_count
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "number"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Scenes this one catalogue indexes them on, which measures its coverage and no career. Never added to another catalogue's."
        +}
      • addedOutput schema / properties / results / items / properties / status / description
        Added value: +"What the identifier addresses on that catalogue now. A folded record answers with a marker, which describes the record and never what it once named."
      • changedOutput schema / properties / results / items / required
        Previous value: -[
        -  "id",
        -  "source",
        -  "source_url",
        -  "status"
        -]New value: +[
        +  "id",
        +  "source",
        +  "source_url",
        +  "retrieved_at",
        +  "status",
        +  "also_held_at",
        +  "linked_unfollowed",
        +  "name",
        +  "disambiguation",
        +  "aliases",
        +  "gender",
        +  "country",
        +  "birth_date",
        +  "death_date",
        +  "career_start_year",
        +  "career_end_year",
        +  "scene_count",
        +  "merged_into",
        +  "merged_ids"
        +]
      • changedOutput schema / properties / window / description
        Previous value: -"The page a catalogue paged through, absent where none was given one."New value: +"The page and the row limit this answer was read at, absent where no catalogue answered."
    • Changedsearch_scenes26 fields changed
      • addedInput schema / properties / alias / description
        Added value: +"No catalogue's faceted route applies it, though every faceted input declares it: a request carrying it answers as wide as one carrying none, so it is never sent and the answer names it as a narrowing nobody received."
      • changedInput schema / properties / limit / description
        Previous value: -"How many rows one page of one catalogue carries. An answer holding several catalogues carries up to this many from each of them, since their pages are their own and nothing here interleaves them into one."New value: +"How many rows one page of one catalogue carries. An answer holding several carries up to this many from each: their pages are their own and nothing here interleaves them into one."
      • addedInput schema / properties / match / description
        Added value: +"How performer_ids and tag_ids are read, which are the only arguments it governs. 'all', the default, asks for scenes carrying every identifier of a list; 'any' for scenes carrying at least one, which answers counts an order of magnitude wider. A scene names one studio, so studio_ids asks for any of its identifiers under both readings. The lists narrow against each other as an intersection either way."
      • changedInput schema / properties / page / description
        Previous value: -"The page of each catalogue's own order. A route that reads words alone takes no page, and the answer reports it as one that catalogue did not receive."New value: +"Which page of its own order every catalogue asked is read at, counted from 1. A search written with words alone reads the first rows each text index answers with, since those routes take no page."
      • changedOutput schema / properties / per_source / items / properties / index_total / description
        Previous value: -"What its own index holds for this question, the rows on this page included."New value: +"What its own index holds for the question it received, the rows on this page included. A narrowing it could not receive, or received in part, leaves that question wider than the one written."
      • changedOutput schema / properties / per_source / items / properties / narrowings_not_received / description
        Previous value: -"Narrowings this catalogue cannot receive. This is the one field that says a catalogue cannot do something."New value: +"Narrowings that shaped no part of the request this catalogue received, whether its route declares no field for one or nothing written was left for one to decide."
      • addedOutput schema / properties / per_source / items / properties / narrowings_received_in_part / description
        Added value: +"Narrowings it received short of what was written, the rest of the list naming records another catalogue minted. It answered a wider question than the one asked."
      • addedOutput schema / properties / results / items / properties / also_held_at
        Added value: +{
        +  "description": "The same record on another catalogue, read from a link this one publishes to it. A shared name is no join.",
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "id": {
        +        "type": "string"
        +      },
        +      "source": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "source",
        +      "id"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / code
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "The studio's own reference for the release."
        +}
      • addedOutput schema / properties / results / items / properties / duration_seconds
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "number"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "The runtime that catalogue holds, which is what separates two cuts of one title."
        +}
      • addedOutput schema / properties / results / items / properties / linked_unfollowed
        Added value: +{
        +  "description": "A link to another catalogue naming the record by something this client cannot address. The link is written, and following it is what failed.",
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "source": {
        +        "type": "string"
        +      },
        +      "url": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "source",
        +      "url"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / pending_edits
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "number"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Edits open against it, null where its catalogue publishes no such count."
        +}
      • addedOutput schema / properties / results / items / properties / pending_edits_unreadable
        Added value: +{
        +  "description": "The count of open edits came back in a shape this client could not read.",
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / results / items / properties / performers
        Added value: +{
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "creditedAs": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "The name this release printed, where it differs."
        +      },
        +      "disambiguation": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "id": {
        +        "type": "string"
        +      },
        +      "name": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "status": {
        +        "enum": [
        +          "established",
        +          "merged",
        +          "deleted"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "id",
        +      "name",
        +      "creditedAs",
        +      "disambiguation",
        +      "status"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / production_date_unreadable
        Added value: +{
        +  "description": "The same, for the production date, which get_scene answers with.",
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / results / items / properties / release_date
        Added value: +{
        +  "anyOf": [
        +    {
        +      "additionalProperties": false,
        +      "properties": {
        +        "precision": {
        +          "description": "How much of the date the catalogue holds: a month or a year can be all of it.",
        +          "enum": [
        +            "day",
        +            "month",
        +            "year"
        +          ],
        +          "type": "string"
        +        },
        +        "value": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "value",
        +        "precision"
        +      ],
        +      "type": "object"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ]
        +}
      • addedOutput schema / properties / results / items / properties / release_date_unreadable
        Added value: +{
        +  "description": "A release date was published in a shape this client could not read, so the null above is a reading that failed rather than a date nobody entered.",
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / results / items / properties / retrieved_at
        Added value: +{
        +  "description": "The moment this client read it there.",
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / rows_skipped
        Added value: +{
        +  "description": "Entries of this record's own lists that could not be read and are left out.",
        +  "type": "number"
        +}
      • addedOutput schema / properties / results / items / properties / rows_skipped_in
        Added value: +{
        +  "description": "Which of its lists lost them.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / status / description
        Added value: +"What the identifier addresses on that catalogue now. A folded record answers with a marker, which describes the record and never what it once named."
      • addedOutput schema / properties / results / items / properties / studio
        Added value: +{
        +  "anyOf": [
        +    {
        +      "additionalProperties": false,
        +      "properties": {
        +        "id": {
        +          "type": "string"
        +        },
        +        "name": {
        +          "anyOf": [
        +            {
        +              "type": "string"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ]
        +        },
        +        "parent": {
        +          "anyOf": [
        +            {
        +              "type": "string"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ]
        +        },
        +        "parentWithdrawn": {
        +          "type": "boolean"
        +        },
        +        "status": {
        +          "enum": [
        +            "established",
        +            "merged",
        +            "deleted"
        +          ],
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "id",
        +        "name",
        +        "parent",
        +        "status"
        +      ],
        +      "type": "object"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ]
        +}
      • addedOutput schema / properties / results / items / properties / tags
        Added value: +{
        +  "description": "Each tag with the identifier the next call takes. What its catalogue filed it under is a fact about the tag, which get_tag answers.",
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "id": {
        +        "type": "string"
        +      },
        +      "name": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      }
        +    },
        +    "required": [
        +      "id",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / title
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ]
        +}
      • changedOutput schema / properties / results / items / required
        Previous value: -[
        -  "id",
        -  "source",
        -  "source_url",
        -  "status"
        -]New value: +[
        +  "id",
        +  "source",
        +  "source_url",
        +  "retrieved_at",
        +  "status",
        +  "also_held_at",
        +  "linked_unfollowed",
        +  "title",
        +  "code",
        +  "duration_seconds",
        +  "release_date",
        +  "studio",
        +  "performers",
        +  "tags"
        +]
      • changedOutput schema / properties / window / description
        Previous value: -"The page a catalogue paged through, absent where none was given one."New value: +"The page and the row limit this answer was read at, absent where no catalogue answered."
    • Changedsearch_studios19 fields changed
      • changedInput schema / properties / limit / description
        Previous value: -"How many rows one page of one catalogue carries. An answer holding several catalogues carries up to this many from each of them, since their pages are their own and nothing here interleaves them into one."New value: +"How many rows one page of one catalogue carries. An answer holding several carries up to this many from each: their pages are their own and nothing here interleaves them into one."
      • changedInput schema / properties / page / description
        Previous value: -"The page of each catalogue's own order. A route that reads words alone takes no page, and the answer reports it as one that catalogue did not receive."New value: +"Which page of its own order every catalogue asked is read at, counted from 1. A search written with words alone reads the first rows each text index answers with, since those routes take no page."
      • changedOutput schema / properties / per_source / items / properties / index_total / description
        Previous value: -"What its own index holds for this question, the rows on this page included."New value: +"What its own index holds for the question it received, the rows on this page included. A narrowing it could not receive, or received in part, leaves that question wider than the one written."
      • changedOutput schema / properties / per_source / items / properties / narrowings_not_received / description
        Previous value: -"Narrowings this catalogue cannot receive. This is the one field that says a catalogue cannot do something."New value: +"Narrowings that shaped no part of the request this catalogue received, whether its route declares no field for one or nothing written was left for one to decide."
      • addedOutput schema / properties / per_source / items / properties / narrowings_received_in_part / description
        Added value: +"Narrowings it received short of what was written, the rest of the list naming records another catalogue minted. It answered a wider question than the one asked."
      • addedOutput schema / properties / results / items / properties / aliases
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / also_held_at
        Added value: +{
        +  "description": "The same record on another catalogue, read from a link this one publishes to it. A shared name is no join.",
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "id": {
        +        "type": "string"
        +      },
        +      "source": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "source",
        +      "id"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / linked_unfollowed
        Added value: +{
        +  "description": "A link to another catalogue naming the record by something this client cannot address. The link is written, and following it is what failed.",
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "source": {
        +        "type": "string"
        +      },
        +      "url": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "source",
        +      "url"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / name
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ]
        +}
      • addedOutput schema / properties / results / items / properties / parent
        Added value: +{
        +  "anyOf": [
        +    {
        +      "additionalProperties": false,
        +      "properties": {
        +        "id": {
        +          "type": "string"
        +        },
        +        "name": {
        +          "anyOf": [
        +            {
        +              "type": "string"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ]
        +        },
        +        "status": {
        +          "enum": [
        +            "established",
        +            "merged",
        +            "deleted"
        +          ],
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "id",
        +        "name",
        +        "status"
        +      ],
        +      "type": "object"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "The studio this one sits under, where its catalogue records one."
        +}
      • addedOutput schema / properties / results / items / properties / pending_edits
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "number"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Edits open against it, null where its catalogue publishes no such count."
        +}
      • addedOutput schema / properties / results / items / properties / pending_edits_unreadable
        Added value: +{
        +  "description": "The count of open edits came back in a shape this client could not read.",
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / results / items / properties / retrieved_at
        Added value: +{
        +  "description": "The moment this client read it there.",
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / rows_skipped
        Added value: +{
        +  "description": "Entries of this record's own lists that could not be read and are left out.",
        +  "type": "number"
        +}
      • addedOutput schema / properties / results / items / properties / rows_skipped_in
        Added value: +{
        +  "description": "Which of its lists lost them.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / scene_count
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "number"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Scenes this one catalogue indexes on it, null where it publishes no such count. Never added to another catalogue's."
        +}
      • addedOutput schema / properties / results / items / properties / status / description
        Added value: +"What the identifier addresses on that catalogue now. A folded record answers with a marker, which describes the record and never what it once named."
      • changedOutput schema / properties / results / items / required
        Previous value: -[
        -  "id",
        -  "source",
        -  "source_url",
        -  "status"
        -]New value: +[
        +  "id",
        +  "source",
        +  "source_url",
        +  "retrieved_at",
        +  "status",
        +  "also_held_at",
        +  "linked_unfollowed",
        +  "name",
        +  "aliases",
        +  "parent",
        +  "scene_count"
        +]
      • changedOutput schema / properties / window / description
        Previous value: -"The page a catalogue paged through, absent where none was given one."New value: +"The page and the row limit this answer was read at, absent where no catalogue answered."
    • Changedsearch_tags19 fields changed
      • changedInput schema / properties / limit / description
        Previous value: -"How many rows one page of one catalogue carries. An answer holding several catalogues carries up to this many from each of them, since their pages are their own and nothing here interleaves them into one."New value: +"How many rows one page of one catalogue carries. An answer holding several carries up to this many from each: their pages are their own and nothing here interleaves them into one."
      • changedInput schema / properties / page / description
        Previous value: -"The page of each catalogue's own order. A route that reads words alone takes no page, and the answer reports it as one that catalogue did not receive."New value: +"Which page of its own order every catalogue asked is read at, counted from 1. A search written with words alone reads the first rows each text index answers with, since those routes take no page."
      • changedOutput schema / properties / per_source / items / properties / index_total / description
        Previous value: -"What its own index holds for this question, the rows on this page included."New value: +"What its own index holds for the question it received, the rows on this page included. A narrowing it could not receive, or received in part, leaves that question wider than the one written."
      • changedOutput schema / properties / per_source / items / properties / narrowings_not_received / description
        Previous value: -"Narrowings this catalogue cannot receive. This is the one field that says a catalogue cannot do something."New value: +"Narrowings that shaped no part of the request this catalogue received, whether its route declares no field for one or nothing written was left for one to decide."
      • addedOutput schema / properties / per_source / items / properties / narrowings_received_in_part / description
        Added value: +"Narrowings it received short of what was written, the rest of the list naming records another catalogue minted. It answered a wider question than the one asked."
      • addedOutput schema / properties / results / items / properties / aliases
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / also_held_at
        Added value: +{
        +  "description": "The same record on another catalogue, read from a link this one publishes to it. A shared name is no join.",
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "id": {
        +        "type": "string"
        +      },
        +      "source": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "source",
        +      "id"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / category
        Added value: +{
        +  "anyOf": [
        +    {
        +      "additionalProperties": false,
        +      "properties": {
        +        "group": {
        +          "anyOf": [
        +            {
        +              "type": "string"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ]
        +        },
        +        "id": {
        +          "type": "string"
        +        },
        +        "name": {
        +          "anyOf": [
        +            {
        +              "type": "string"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ]
        +        }
        +      },
        +      "required": [
        +        "id",
        +        "name",
        +        "group"
        +      ],
        +      "type": "object"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "The table its catalogue sorts the tag under, and the group that table covers."
        +}
      • addedOutput schema / properties / results / items / properties / description
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ]
        +}
      • addedOutput schema / properties / results / items / properties / linked_unfollowed
        Added value: +{
        +  "description": "A link to another catalogue naming the record by something this client cannot address. The link is written, and following it is what failed.",
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "source": {
        +        "type": "string"
        +      },
        +      "url": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "source",
        +      "url"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / name
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ]
        +}
      • addedOutput schema / properties / results / items / properties / pending_edits
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "number"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Edits open against it, null where its catalogue publishes no such count."
        +}
      • addedOutput schema / properties / results / items / properties / pending_edits_unreadable
        Added value: +{
        +  "description": "The count of open edits came back in a shape this client could not read.",
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / results / items / properties / retrieved_at
        Added value: +{
        +  "description": "The moment this client read it there.",
        +  "type": "string"
        +}
      • addedOutput schema / properties / results / items / properties / rows_skipped
        Added value: +{
        +  "description": "Entries of this record's own lists that could not be read and are left out.",
        +  "type": "number"
        +}
      • addedOutput schema / properties / results / items / properties / rows_skipped_in
        Added value: +{
        +  "description": "Which of its lists lost them.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / results / items / properties / status / description
        Added value: +"What the identifier addresses on that catalogue now. A folded record answers with a marker, which describes the record and never what it once named."
      • changedOutput schema / properties / results / items / required
        Previous value: -[
        -  "id",
        -  "source",
        -  "source_url",
        -  "status"
        -]New value: +[
        +  "id",
        +  "source",
        +  "source_url",
        +  "retrieved_at",
        +  "status",
        +  "also_held_at",
        +  "linked_unfollowed",
        +  "name",
        +  "description",
        +  "aliases",
        +  "category"
        +]
      • changedOutput schema / properties / window / description
        Previous value: -"The page a catalogue paged through, absent where none was given one."New value: +"The page and the row limit this answer was read at, absent where no catalogue answered."
  3. 10 tool updatesv0.9.0
    • Changedfind_by_fingerprint57 fields changed
      • removedInput schema / properties / fingerprints / description
        Removed value: -"Every fingerprint held for one file. A file carries one hash per algorithm, so a longer list is an inventory rather than a question."
      • addedInput schema / properties / fingerprints / items / additionalProperties
        Added value: +false
      • removedInput schema / properties / fingerprints / items / properties / hash / description
        Removed value: -"The fingerprint as the hashing tool produced it."
      • addedInput schema / properties / fingerprints / items / properties / hash / minLength
        Added value: +1
      • changedInput schema / properties / fingerprints / maxItems
        Previous value: -10New value: +25
      • addedInput schema / properties / prefer
        Added value: +{
        +  "description": "The order the catalogues are preferred in where they disagree on a field. Left out, the order the registry declares stands. Every card states the order that was applied.",
        +  "items": {
        +    "enum": [
        +      "stashdb",
        +      "tpdb",
        +      "fansdb",
        +      "pmv",
        +      "javstash"
        +    ],
        +    "type": "string"
        +  },
        +  "maxItems": 5,
        +  "minItems": 1,
        +  "type": "array"
        +}
      • addedInput schema / properties / sections
        Added value: +{
        +  "description": "The blocks read beside the record's own fields, which come back whatever is written here. Each name adds a block, and 'basic' asks for those fields alone.",
        +  "items": {
        +    "enum": [
        +      "basic",
        +      "fingerprints",
        +      "images"
        +    ],
        +    "type": "string"
        +  },
        +  "maxItems": 3,
        +  "minItems": 1,
        +  "type": "array"
        +}
      • removedInput schema / properties / sources / description
        Removed value: -"Narrow to named catalogues. Every configured catalogue is asked by default."
      • addedInput schema / properties / sources / items / enum
        Added value: +[
        +  "stashdb",
        +  "tpdb",
        +  "fansdb",
        +  "pmv",
        +  "javstash"
        +]
      • addedInput schema / properties / sources / maxItems
        Added value: +5
      • addedInput schema / properties / sources / minItems
        Added value: +1
      • addedOutput schema / properties / cached
        Added value: +{
        +  "type": "boolean"
        +}
      • changedOutput schema / properties / match_count / description
        Previous value: -"Matches returned: one per scene per fingerprint it carries."New value: +"One per record reached, whatever number of hashes reached it."
      • removedOutput schema / properties / matches / items / properties / algorithm
        Removed value: -{
        -  "enum": [
        -    "MD5",
        -    "OSHASH",
        -    "PHASH"
        -  ],
        -  "type": "string"
        -}
      • removedOutput schema / properties / matches / items / properties / fingerprint
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "additionalProperties": false,
        -      "properties": {
        -        "algorithm": {
        -          "enum": [
        -            "MD5",
        -            "OSHASH",
        -            "PHASH"
        -          ],
        -          "type": "string"
        -        },
        -        "contested": {
        -          "anyOf": [
        -            {
        -              "type": "boolean"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "description": "Whether the reports reach the submissions. Null where the catalogue publishes no report count: a fingerprint nobody has disputed and one on a catalogue that counts no disputes are different things."
        -        },
        -        "duration_seconds": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ]
        -        },
        -        "hash": {
        -          "type": "string"
        -        },
        -        "reports": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "description": "How many people reported against it. Null on a catalogue that records no reports, which is an unknown contest and never an absence of one."
        -        },
        -        "submissions": {
        -          "anyOf": [
        -            {
        -              "type": "number"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ],
        -          "description": "How many people entered this fingerprint. Null where the catalogue counts none."
        -        }
        -      },
        -      "required": [
        -        "algorithm",
        -        "hash",
        -        "duration_seconds",
        -        "submissions",
        -        "reports",
        -        "contested"
        -      ],
        -      "type": "object"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • changedOutput schema / properties / matches / items / properties / match_kind / description
        Previous value: -"'exact_file' means the same file, byte for byte. 'perceptual_similarity' means images that resemble each other, which covers a re-encode, a crop and a different scene from one shoot, and is no evidence that two files are the same."New value: +"'exact_file' names the same bytes. 'perceptual_similarity' covers a re-encode, a crop and another scene from one shoot, and is no evidence that two files are the same."
      • addedOutput schema / properties / matches / items / properties / matched_by
        Added value: +{
        +  "description": "Every hash that reached this record, each naming the catalogues it reached it on. A hash a catalogue does not search reached nothing there.",
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "algorithm": {
        +        "enum": [
        +          "MD5",
        +          "OSHASH",
        +          "PHASH"
        +        ],
        +        "type": "string"
        +      },
        +      "hash": {
        +        "type": "string"
        +      },
        +      "sources": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "required": [
        +      "hash",
        +      "algorithm",
        +      "sources"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / matches / items / properties / scene / properties / counts
        Added value: +{
        +  "additionalProperties": {
        +    "items": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "source": {
        +          "type": "string"
        +        },
        +        "state": {
        +          "enum": [
        +            "answered",
        +            "failed",
        +            "absent"
        +          ],
        +          "type": "string"
        +        },
        +        "value": {
        +          "anyOf": [
        +            {
        +              "type": "number"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ]
        +        }
        +      },
        +      "required": [
        +        "source",
        +        "value",
        +        "state"
        +      ],
        +      "type": "object"
        +    },
        +    "type": "array"
        +  },
        +  "description": "Counts, one entry per catalogue asked and never added together. A null is read with the state beside it: a catalogue that publishes no such count, one that could not answer, and one nobody asked are three different facts.",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / matches / items / properties / scene / properties / fields
        Added value: +{
        +  "additionalProperties": {
        +    "anyOf": [
        +      {
        +        "additionalProperties": false,
        +        "properties": {
        +          "agreed_by": {
        +            "description": "The catalogues that published this reading. Two agreeing is evidence of its own.",
        +            "items": {
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          "disagreed": {
        +            "description": "The readings nobody preferred, published rather than dropped: choosing between them is a policy, and a policy applied in silence is a claim nobody can check.",
        +            "items": {
        +              "additionalProperties": false,
        +              "properties": {
        +                "source": {
        +                  "type": "string"
        +                },
        +                "value": {}
        +              },
        +              "required": [
        +                "source",
        +                "value"
        +              ],
        +              "type": "object"
        +            },
        +            "type": "array"
        +          },
        +          "value": {
        +            "description": "The reading the preference named, null where none published one."
        +          }
        +        },
        +        "required": [
        +          "value",
        +          "agreed_by"
        +        ],
        +        "type": "object"
        +      },
        +      {
        +        "items": {
        +          "additionalProperties": false,
        +          "properties": {
        +            "also_at": {
        +              "description": "What this same record is called on another catalogue, from a link joining the two.",
        +              "items": {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "id": {
        +                    "type": "string"
        +                  },
        +                  "source": {
        +                    "type": "string"
        +                  }
        +                },
        +                "required": [
        +                  "source",
        +                  "id"
        +                ],
        +                "type": "object"
        +              },
        +              "type": "array"
        +            },
        +            "published_by": {
        +              "description": "Every catalogue that published this very record. A shared name is no join, so an entry one catalogue minted names that one.",
        +              "items": {
        +                "type": "string"
        +              },
        +              "type": "array"
        +            },
        +            "same_name_as": {
        +              "description": "A record another catalogue published under a matching name. A resemblance, never a join.",
        +              "items": {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "id": {
        +                    "type": "string"
        +                  },
        +                  "source": {
        +                    "type": "string"
        +                  }
        +                },
        +                "required": [
        +                  "source",
        +                  "id"
        +                ],
        +                "type": "object"
        +              },
        +              "type": "array"
        +            },
        +            "value": {}
        +          },
        +          "required": [
        +            "value",
        +            "published_by"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      }
        +    ]
        +  },
        +  "description": "Each field of the record. A scalar carries the catalogues that said it; a list is the union, each entry naming who published it.",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / matches / items / properties / scene / properties / held_by
        Added value: +{
        +  "description": "Every catalogue asked, with the identifier the record carries there.",
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "error": {
        +        "type": "string"
        +      },
        +      "id": {
        +        "type": "string"
        +      },
        +      "reason": {
        +        "type": "string"
        +      },
        +      "retrieved_at": {
        +        "description": "The moment this client read it there.",
        +        "type": "string"
        +      },
        +      "source": {
        +        "type": "string"
        +      },
        +      "source_url": {
        +        "description": "The address it was read at, which credits it.",
        +        "type": "string"
        +      },
        +      "state": {
        +        "enum": [
        +          "answered",
        +          "failed",
        +          "absent"
        +        ],
        +        "type": "string"
        +      },
        +      "status": {
        +        "description": "What the identifier addresses there now. A folded record is held elsewhere.",
        +        "enum": [
        +          "established",
        +          "merged",
        +          "deleted"
        +        ],
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "source",
        +      "state"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • removedOutput schema / properties / matches / items / properties / scene / properties / id
        Removed value: -{
        -  "type": "string"
        -}
      • addedOutput schema / properties / matches / items / properties / scene / properties / kind
        Added value: +{
        +  "type": "string"
        +}
      • addedOutput schema / properties / matches / items / properties / scene / properties / notes
        Added value: +{
        +  "description": "What this answer does not establish, which is what makes it safe to act on.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • removedOutput schema / properties / matches / items / properties / scene / properties / performers
        Removed value: -{
        -  "items": {
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • addedOutput schema / properties / matches / items / properties / scene / properties / preferred
        Added value: +{
        +  "description": "The order the readings were preferred in. This is the policy that was applied, whether or not every catalogue in it answered.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / matches / items / properties / scene / properties / read_from
        Added value: +{
        +  "description": "The catalogues that answered, in the order they were preferred. A policy and an outcome are two facts, and a reader deciding whether to change the policy needs both.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • removedOutput schema / properties / matches / items / properties / scene / properties / release_date
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "additionalProperties": false,
        -      "properties": {
        -        "precision": {
        -          "description": "How much of the date a cataloguer entered. A value recorded to the year carries no month and no day, and reading it as one would claim a precision nobody entered.",
        -          "enum": [
        -            "day",
        -            "month",
        -            "year"
        -          ],
        -          "type": "string"
        -        },
        -        "value": {
        -          "description": "The date exactly as the catalogue publishes it.",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "value",
        -        "precision"
        -      ],
        -      "type": "object"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • removedOutput schema / properties / matches / items / properties / scene / properties / source
        Removed value: -{
        -  "type": "string"
        -}
      • removedOutput schema / properties / matches / items / properties / scene / properties / source_url
        Removed value: -{
        -  "type": "string"
        -}
      • removedOutput schema / properties / matches / items / properties / scene / properties / studio
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • removedOutput schema / properties / matches / items / properties / scene / properties / title
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • changedOutput schema / properties / matches / items / properties / scene / required
        Previous value: -[
        -  "id",
        -  "source",
        -  "title",
        -  "release_date",
        -  "studio",
        -  "performers",
        -  "source_url"
        -]New value: +[
        +  "kind",
        +  "fields",
        +  "counts",
        +  "held_by",
        +  "preferred",
        +  "read_from",
        +  "notes"
        +]
      • changedOutput schema / properties / matches / items / required
        Previous value: -[
        -  "algorithm",
        -  "match_kind",
        -  "scene",
        -  "fingerprint"
        -]New value: +[
        +  "scene",
        +  "matched_by",
        +  "match_kind"
        +]
      • addedOutput schema / properties / not_searched
        Added value: +{
        +  "description": "Hashes and the catalogues that answered without searching their algorithm, so they were never put to those. Nobody looked there, which is no evidence about the files behind them.",
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "algorithm": {
        +        "type": "string"
        +      },
        +      "hash": {
        +        "type": "string"
        +      },
        +      "sources": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      }
        +    },
        +    "required": [
        +      "hash",
        +      "algorithm",
        +      "sources"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / per_source / items / properties / algorithms_not_searched
        Added value: +{
        +  "description": "Fingerprint algorithms its lookup does not search, so they were never put to it.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • changedOutput schema / properties / per_source / items / properties / count / description
        Previous value: -"Rows this catalogue contributed to this page."New value: +"Rows it contributed. Never added to another catalogue's: they index corpora that overlap by an amount none of them publishes."
      • addedOutput schema / properties / per_source / items / properties / error / enum
        Added value: +[
        +  "not_found",
        +  "invalid_input",
        +  "rate_limited",
        +  "parse_failure",
        +  "network_error",
        +  "timeout"
        +]
      • removedOutput schema / properties / per_source / items / properties / fields_searched
        Removed value: -{
        -  "description": "The fields the text index read. Absent where no text index was consulted.",
        -  "items": {
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • changedOutput schema / properties / per_source / items / properties / index_total / description
        Previous value: -"What this catalogue's index holds for the question, beyond the page returned."New value: +"What its own index holds for this question, the rows on this page included."
      • addedOutput schema / properties / per_source / items / properties / index_total_over_any_word
        Added value: +{
        +  "description": "The total counts rows carrying any word of the query, its text index reading them apart.",
        +  "type": "boolean"
        +}
      • changedOutput schema / properties / per_source / items / properties / moment / description
        Previous value: -"Which step failed, for a catalogue that failed."New value: +"Which moment failed."
      • addedOutput schema / properties / per_source / items / properties / name / description
        Added value: +"The name that catalogue calls itself."
      • addedOutput schema / properties / per_source / items / properties / narrowings_naming_no_record
        Added value: +{
        +  "description": "Narrowings written only with identifiers another catalogue minted.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • changedOutput schema / properties / per_source / items / properties / narrowings_not_received / description
        Previous value: -"Narrowings this catalogue could not receive. A row of its satisfying one of them does so by chance."New value: +"Narrowings this catalogue cannot receive. This is the one field that says a catalogue cannot do something."
      • addedOutput schema / properties / per_source / items / properties / narrowings_received_in_part
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / per_source / items / properties / reason / description
        Added value: +"Why it was not asked, or what went wrong."
      • addedOutput schema / properties / per_source / items / properties / records
        Added value: +{
        +  "description": "Distinct records behind its rows.",
        +  "type": "number"
        +}
      • addedOutput schema / properties / per_source / items / properties / skipped / description
        Added value: +"Rows it answered with that this client could not read and left out."
      • addedOutput schema / properties / per_source / items / properties / source / description
        Added value: +"The catalogue this row is about."
      • changedOutput schema / properties / per_source / items / properties / state / description
        Previous value: -"'answered' is a catalogue that looked, and a count of zero there means it found nothing. 'failed' could not answer. 'absent' was never asked. An answer holding rows from some catalogues is no evidence about the others."New value: +"'answered' looked, and a count of zero means it found nothing. 'failed' could not answer, and states nothing about what it holds. 'absent' was never asked. Only the first is evidence about the world."
      • addedOutput schema / properties / per_source / items / properties / unattributed / description
        Added value: +"Records it answered with while carrying none of what was asked about."
      • addedOutput schema / properties / records_named
        Added value: +{
        +  "description": "Distinct records an exact hash named. Two hashes reaching one record count once, and a perceptual match names no record.",
        +  "type": "number"
        +}
      • addedOutput schema / properties / resemblances
        Added value: +{
        +  "description": "Matches a perceptual hash reached, each a likeness and no claim about any file's bytes.",
        +  "type": "number"
        +}
      • removedOutput schema / properties / scenes_matched
        Removed value: -{
        -  "description": "Distinct scenes behind those matches.",
        -  "type": "number"
        -}
      • changedOutput schema / properties / unattributed / description
        Previous value: -"Scenes a catalogue answered with while returning none of the fingerprints asked for. Which hash reached them is unknown, which is kept apart from a catalogue that found nothing."New value: +"Records the catalogues answered with that carry none of the hashes asked. Which hash reached them is unknown, so they stand as no match and are counted apart."
      • addedOutput schema / properties / unmatched
        Added value: +{
        +  "description": "The hashes put to a catalogue that answered, which reached no record there. A catalogue named as unasked says nothing about them either way.",
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "algorithm": {
        +        "type": "string"
        +      },
        +      "hash": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "hash",
        +      "algorithm"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "asked",
        -  "matches",
        -  "match_count",
        -  "scenes_matched",
        -  "unattributed",
        -  "per_source",
        -  "notes"
        -]New value: +[
        +  "matches",
        +  "match_count",
        +  "records_named",
        +  "resemblances",
        +  "unattributed",
        +  "unmatched",
        +  "not_searched",
        +  "asked",
        +  "per_source",
        +  "notes"
        +]
    • Changedget_performer43 fields changed
      • removedInput schema / properties / id / description
        Removed value: -"Identifier as returned by another tool, such as stashdb:<uuid>."
      • addedInput schema / properties / id / pattern
        Added value: +"^(?:(?:stashdb|tpdb|fansdb|pmv|javstash):)?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
      • addedInput schema / properties / prefer
        Added value: +{
        +  "description": "The order the catalogues are preferred in where they disagree on a field. Left out, the order the registry declares stands. Every card states the order that was applied.",
        +  "items": {
        +    "enum": [
        +      "stashdb",
        +      "tpdb",
        +      "fansdb",
        +      "pmv",
        +      "javstash"
        +    ],
        +    "type": "string"
        +  },
        +  "maxItems": 5,
        +  "minItems": 1,
        +  "type": "array"
        +}
      • changedInput schema / properties / sections / description
        Previous value: -"Which blocks to load. Defaults to basic."New value: +"The blocks read beside the record's own fields, which come back whatever is written here. Each name adds a block, and 'basic' asks for those fields alone. 'studios' is the whole table of studios they are credited on, which runs to hundreds of rows."
      • changedInput schema / properties / sections / items / enum
        Previous value: -[
        -  "basic",
        -  "appearance",
        -  "images",
        -  "scenes",
        -  "studios"
        -]New value: +[
        +  "basic",
        +  "appearance",
        +  "images",
        +  "studios"
        +]
      • addedInput schema / properties / sections / maxItems
        Added value: +4
      • addedInput schema / properties / sections / minItems
        Added value: +1
      • addedInput schema / properties / sources
        Added value: +{
        +  "items": {
        +    "enum": [
        +      "stashdb",
        +      "tpdb",
        +      "fansdb",
        +      "pmv",
        +      "javstash"
        +    ],
        +    "type": "string"
        +  },
        +  "maxItems": 5,
        +  "minItems": 1,
        +  "type": "array"
        +}
      • removedOutput schema / description
        Removed value: -"A performer when 'status' is 'established'. When it is 'deleted' or 'merged' this is a marker: it carries the identifier, the catalogue, the successor, the identifiers folded in and the former name, and no field describing a person."
      • removedOutput schema / properties / aliases
        Removed value: -{
        -  "description": "Stage names and variant spellings alike.",
        -  "items": {
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • removedOutput schema / properties / appearance
        Removed value: -{
        -  "additionalProperties": false,
        -  "properties": {
        -    "band_size": {
        -      "anyOf": [
        -        {
        -          "type": "number"
        -        },
        -        {
        -          "type": "null"
        -        }
        -      ]
        -    },
        -    "breast_type": {
        -      "anyOf": [
        -        {
        -          "type": "string"
        -        },
        -        {
        -          "type": "null"
        -        }
        -      ]
        -    },
        -    "cup_size": {
        -      "anyOf": [
        -        {
        -          "type": "string"
        -        },
        -        {
        -          "type": "null"
        -        }
        -      ]
        -    },
        -    "ethnicity": {
        -      "anyOf": [
        -        {
        -          "type": "string"
        -        },
        -        {
        -          "type": "null"
        -        }
        -      ]
        -    },
        -    "eye_color": {
        -      "anyOf": [
        -        {
        -          "type": "string"
        -        },
        -        {
        -          "type": "null"
        -        }
        -      ]
        -    },
        -    "hair_color": {
        -      "anyOf": [
        -        {
        -          "type": "string"
        -        },
        -        {
        -          "type": "null"
        -        }
        -      ]
        -    },
        -    "height_cm": {
        -      "anyOf": [
        -        {
        -          "type": "number"
        -        },
        -        {
        -          "type": "null"
        -        }
        -      ]
        -    },
        -    "hip_size": {
        -      "anyOf": [
        -        {
        -          "type": "number"
        -        },
        -        {
        -          "type": "null"
        -        }
        -      ]
        -    },
        -    "piercings": {
        -      "anyOf": [
        -        {
        -          "items": {
        -            "type": "string"
        -          },
        -          "type": "array"
        -        },
        -        {
        -          "type": "null"
        -        }
        -      ]
        -    },
        -    "tattoos": {
        -      "anyOf": [
        -        {
        -          "items": {
        -            "type": "string"
        -          },
        -          "type": "array"
        -        },
        -        {
        -          "type": "null"
        -        }
        -      ]
        -    },
        -    "waist_size": {
        -      "anyOf": [
        -        {
        -          "type": "number"
        -        },
        -        {
        -          "type": "null"
        -        }
        -      ]
        -    }
        -  },
        -  "required": [
        -    "ethnicity",
        -    "eye_color",
        -    "hair_color",
        -    "height_cm",
        -    "breast_type",
        -    "cup_size",
        -    "band_size",
        -    "waist_size",
        -    "hip_size",
        -    "tattoos",
        -    "piercings"
        -  ],
        -  "type": "object"
        -}
      • removedOutput schema / properties / birth_date
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "additionalProperties": false,
        -      "properties": {
        -        "precision": {
        -          "description": "How much of the date a cataloguer entered. A value recorded to the year carries no month and no day, and reading it as one would claim a precision nobody entered.",
        -          "enum": [
        -            "day",
        -            "month",
        -            "year"
        -          ],
        -          "type": "string"
        -        },
        -        "value": {
        -          "description": "The date exactly as the catalogue publishes it.",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "value",
        -        "precision"
        -      ],
        -      "type": "object"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • addedOutput schema / properties / cached
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / card
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "counts": {
        +      "additionalProperties": {
        +        "items": {
        +          "additionalProperties": false,
        +          "properties": {
        +            "source": {
        +              "type": "string"
        +            },
        +            "state": {
        +              "enum": [
        +                "answered",
        +                "failed",
        +                "absent"
        +              ],
        +              "type": "string"
        +            },
        +            "value": {
        +              "anyOf": [
        +                {
        +                  "type": "number"
        +                },
        +                {
        +                  "type": "null"
        +                }
        +              ]
        +            }
        +          },
        +          "required": [
        +            "source",
        +            "value",
        +            "state"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "description": "Counts, one entry per catalogue asked and never added together. A null is read with the state beside it: a catalogue that publishes no such count, one that could not answer, and one nobody asked are three different facts.",
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "fields": {
        +      "additionalProperties": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": false,
        +            "properties": {
        +              "agreed_by": {
        +                "description": "The catalogues that published this reading. Two agreeing is evidence of its own.",
        +                "items": {
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              },
        +              "disagreed": {
        +                "description": "The readings nobody preferred, published rather than dropped: choosing between them is a policy, and a policy applied in silence is a claim nobody can check.",
        +                "items": {
        +                  "additionalProperties": false,
        +                  "properties": {
        +                    "source": {
        +                      "type": "string"
        +                    },
        +                    "value": {}
        +                  },
        +                  "required": [
        +                    "source",
        +                    "value"
        +                  ],
        +                  "type": "object"
        +                },
        +                "type": "array"
        +              },
        +              "value": {
        +                "description": "The reading the preference named, null where none published one."
        +              }
        +            },
        +            "required": [
        +              "value",
        +              "agreed_by"
        +            ],
        +            "type": "object"
        +          },
        +          {
        +            "items": {
        +              "additionalProperties": false,
        +              "properties": {
        +                "also_at": {
        +                  "description": "What this same record is called on another catalogue, from a link joining the two.",
        +                  "items": {
        +                    "additionalProperties": false,
        +                    "properties": {
        +                      "id": {
        +                        "type": "string"
        +                      },
        +                      "source": {
        +                        "type": "string"
        +                      }
        +                    },
        +                    "required": [
        +                      "source",
        +                      "id"
        +                    ],
        +                    "type": "object"
        +                  },
        +                  "type": "array"
        +                },
        +                "published_by": {
        +                  "description": "Every catalogue that published this very record. A shared name is no join, so an entry one catalogue minted names that one.",
        +                  "items": {
        +                    "type": "string"
        +                  },
        +                  "type": "array"
        +                },
        +                "same_name_as": {
        +                  "description": "A record another catalogue published under a matching name. A resemblance, never a join.",
        +                  "items": {
        +                    "additionalProperties": false,
        +                    "properties": {
        +                      "id": {
        +                        "type": "string"
        +                      },
        +                      "source": {
        +                        "type": "string"
        +                      }
        +                    },
        +                    "required": [
        +                      "source",
        +                      "id"
        +                    ],
        +                    "type": "object"
        +                  },
        +                  "type": "array"
        +                },
        +                "value": {}
        +              },
        +              "required": [
        +                "value",
        +                "published_by"
        +              ],
        +              "type": "object"
        +            },
        +            "type": "array"
        +          }
        +        ]
        +      },
        +      "description": "Each field of the record. A scalar carries the catalogues that said it; a list is the union, each entry naming who published it.",
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "held_by": {
        +      "description": "Every catalogue asked, with the identifier the record carries there.",
        +      "items": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "error": {
        +            "type": "string"
        +          },
        +          "id": {
        +            "type": "string"
        +          },
        +          "reason": {
        +            "type": "string"
        +          },
        +          "retrieved_at": {
        +            "description": "The moment this client read it there.",
        +            "type": "string"
        +          },
        +          "source": {
        +            "type": "string"
        +          },
        +          "source_url": {
        +            "description": "The address it was read at, which credits it.",
        +            "type": "string"
        +          },
        +          "state": {
        +            "enum": [
        +              "answered",
        +              "failed",
        +              "absent"
        +            ],
        +            "type": "string"
        +          },
        +          "status": {
        +            "description": "What the identifier addresses there now. A folded record is held elsewhere.",
        +            "enum": [
        +              "established",
        +              "merged",
        +              "deleted"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "source",
        +          "state"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "kind": {
        +      "type": "string"
        +    },
        +    "notes": {
        +      "description": "What this answer does not establish, which is what makes it safe to act on.",
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "preferred": {
        +      "description": "The order the readings were preferred in. This is the policy that was applied, whether or not every catalogue in it answered.",
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "read_from": {
        +      "description": "The catalogues that answered, in the order they were preferred. A policy and an outcome are two facts, and a reader deciding whether to change the policy needs both.",
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "kind",
        +    "fields",
        +    "counts",
        +    "held_by",
        +    "preferred",
        +    "read_from",
        +    "notes"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / properties / career_end_year
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "number"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • removedOutput schema / properties / career_start_year
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "number"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • removedOutput schema / properties / country
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • removedOutput schema / properties / created
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • removedOutput schema / properties / death_date
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "additionalProperties": false,
        -      "properties": {
        -        "precision": {
        -          "description": "How much of the date a cataloguer entered. A value recorded to the year carries no month and no day, and reading it as one would claim a precision nobody entered.",
        -          "enum": [
        -            "day",
        -            "month",
        -            "year"
        -          ],
        -          "type": "string"
        -        },
        -        "value": {
        -          "description": "The date exactly as the catalogue publishes it.",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "value",
        -        "precision"
        -      ],
        -      "type": "object"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • removedOutput schema / properties / disambiguation
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "description": "Free text telling two people apart. It reads and never parses."
        -}
      • removedOutput schema / properties / former_name
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "description": "Present on a marker: the name the record carried."
        -}
      • removedOutput schema / properties / gender
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • removedOutput schema / properties / id
        Removed value: -{
        -  "type": "string"
        -}
      • removedOutput schema / properties / images
        Removed value: -{
        -  "items": {
        -    "additionalProperties": false,
        -    "properties": {
        -      "height": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "url": {
        -        "description": "The address of the image. The image itself is never returned.",
        -        "type": "string"
        -      },
        -      "width": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      }
        -    },
        -    "required": [
        -      "url",
        -      "width",
        -      "height"
        -    ],
        -    "type": "object"
        -  },
        -  "type": "array"
        -}
      • removedOutput schema / properties / merged_ids
        Removed value: -{
        -  "items": {
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • removedOutput schema / properties / merged_into
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "description": "Present on a marker: the identifier that continues this record."
        -}
      • removedOutput schema / properties / name
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • removedOutput schema / properties / notes
        Removed value: -{
        -  "items": {
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • addedOutput schema / properties / per_source
        Added value: +{
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "algorithms_not_searched": {
        +        "description": "Fingerprint algorithms its lookup does not search, so they were never put to it.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "count": {
        +        "description": "Rows it contributed. Never added to another catalogue's: they index corpora that overlap by an amount none of them publishes.",
        +        "type": "number"
        +      },
        +      "error": {
        +        "enum": [
        +          "not_found",
        +          "invalid_input",
        +          "rate_limited",
        +          "parse_failure",
        +          "network_error",
        +          "timeout"
        +        ],
        +        "type": "string"
        +      },
        +      "index_total": {
        +        "description": "What its own index holds for this question, the rows on this page included.",
        +        "type": "number"
        +      },
        +      "index_total_over_any_word": {
        +        "description": "The total counts rows carrying any word of the query, its text index reading them apart.",
        +        "type": "boolean"
        +      },
        +      "moment": {
        +        "description": "Which moment failed.",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "The name that catalogue calls itself.",
        +        "type": "string"
        +      },
        +      "narrowings_naming_no_record": {
        +        "description": "Narrowings written only with identifiers another catalogue minted.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "narrowings_not_received": {
        +        "description": "Narrowings this catalogue cannot receive. This is the one field that says a catalogue cannot do something.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "narrowings_received_in_part": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "reason": {
        +        "description": "Why it was not asked, or what went wrong.",
        +        "type": "string"
        +      },
        +      "records": {
        +        "description": "Distinct records behind its rows.",
        +        "type": "number"
        +      },
        +      "skipped": {
        +        "description": "Rows it answered with that this client could not read and left out.",
        +        "type": "number"
        +      },
        +      "source": {
        +        "description": "The catalogue this row is about.",
        +        "type": "string"
        +      },
        +      "state": {
        +        "description": "'answered' looked, and a count of zero means it found nothing. 'failed' could not answer, and states nothing about what it holds. 'absent' was never asked. Only the first is evidence about the world.",
        +        "enum": [
        +          "answered",
        +          "failed",
        +          "absent"
        +        ],
        +        "type": "string"
        +      },
        +      "unattributed": {
        +        "description": "Records it answered with while carrying none of what was asked about.",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "source",
        +      "state"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • removedOutput schema / properties / retrieved_at
        Removed value: -{
        -  "description": "When this record came off the catalogue, ISO 8601.",
        -  "type": "string"
        -}
      • removedOutput schema / properties / scene_count
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "number"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "description": "Scenes this catalogue has indexed crediting this performer. A settled record naming a career spanning decades can report zero, which measures coverage and states nothing about a person's work. Null on a marker, since the count belongs to the record that continues it."
        -}
      • removedOutput schema / properties / scene_count_means
        Removed value: -{
        -  "type": "string"
        -}
      • removedOutput schema / properties / scenes
        Removed value: -{
        -  "items": {
        -    "additionalProperties": false,
        -    "properties": {
        -      "id": {
        -        "type": "string"
        -      },
        -      "release_date": {
        -        "anyOf": [
        -          {
        -            "additionalProperties": false,
        -            "properties": {
        -              "precision": {
        -                "description": "How much of the date a cataloguer entered. A value recorded to the year carries no month and no day, and reading it as one would claim a precision nobody entered.",
        -                "enum": [
        -                  "day",
        -                  "month",
        -                  "year"
        -                ],
        -                "type": "string"
        -              },
        -              "value": {
        -                "description": "The date exactly as the catalogue publishes it.",
        -                "type": "string"
        -              }
        -            },
        -            "required": [
        -              "value",
        -              "precision"
        -            ],
        -            "type": "object"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "source_url": {
        -        "type": "string"
        -      },
        -      "studio": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "title": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      }
        -    },
        -    "required": [
        -      "id",
        -      "title",
        -      "release_date",
        -      "studio",
        -      "source_url"
        -    ],
        -    "type": "object"
        -  },
        -  "type": "array"
        -}
      • removedOutput schema / properties / scenes_total
        Removed value: -{
        -  "description": "What the catalogue holds behind the one page this section shows.",
        -  "type": "number"
        -}
      • removedOutput schema / properties / scenes_unavailable
        Removed value: -{
        -  "description": "Why the section is missing, when it was asked for and could not be read. Its absence then says nothing about what the catalogue holds.",
        -  "type": "string"
        -}
      • removedOutput schema / properties / source
        Removed value: -{
        -  "type": "string"
        -}
      • removedOutput schema / properties / source_url
        Removed value: -{
        -  "type": "string"
        -}
      • removedOutput schema / properties / status
        Removed value: -{
        -  "description": "'established' is a record the catalogue holds. 'merged' and 'deleted' are markers: the identifier resolves, and what comes back describes the record rather than the thing it once named.",
        -  "enum": [
        -    "established",
        -    "deleted",
        -    "merged"
        -  ],
        -  "type": "string"
        -}
      • removedOutput schema / properties / studios
        Removed value: -{
        -  "items": {
        -    "additionalProperties": false,
        -    "properties": {
        -      "id": {
        -        "type": "string"
        -      },
        -      "name": {
        -        "type": "string"
        -      },
        -      "sceneCount": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      }
        -    },
        -    "required": [
        -      "id",
        -      "name",
        -      "sceneCount"
        -    ],
        -    "type": "object"
        -  },
        -  "type": "array"
        -}
      • removedOutput schema / properties / studios_total
        Removed value: -{
        -  "description": "How many the record credits, where the section shows a page of them.",
        -  "type": "number"
        -}
      • removedOutput schema / properties / updated
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • removedOutput schema / properties / urls
        Removed value: -{
        -  "items": {
        -    "additionalProperties": false,
        -    "properties": {
        -      "site_category": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "The catalogue's own category for that site. Null on a catalogue that publishes no table of sites, since borrowing a neighbour's would sort a link by a taxonomy this catalogue never applied."
        -      },
        -      "site_name": {
        -        "type": "string"
        -      },
        -      "url": {
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "url",
        -      "site_name",
        -      "site_category"
        -    ],
        -    "type": "object"
        -  },
        -  "type": "array"
        -}
      • changedOutput schema / required
        Previous value: -[
        -  "id",
        -  "source",
        -  "source_url",
        -  "retrieved_at",
        -  "status",
        -  "notes"
        -]New value: +[
        +  "card"
        +]
    • Changedget_scene37 fields changed
      • removedInput schema / properties / id / description
        Removed value: -"Identifier as returned by another tool, such as stashdb:<uuid>."
      • addedInput schema / properties / id / pattern
        Added value: +"^(?:(?:stashdb|tpdb|fansdb|pmv|javstash):)?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
      • addedInput schema / properties / prefer
        Added value: +{
        +  "description": "The order the catalogues are preferred in where they disagree on a field. Left out, the order the registry declares stands. Every card states the order that was applied.",
        +  "items": {
        +    "enum": [
        +      "stashdb",
        +      "tpdb",
        +      "fansdb",
        +      "pmv",
        +      "javstash"
        +    ],
        +    "type": "string"
        +  },
        +  "maxItems": 5,
        +  "minItems": 1,
        +  "type": "array"
        +}
      • changedInput schema / properties / sections / description
        Previous value: -"Which blocks to load. Defaults to basic."New value: +"The blocks read beside the record's own fields, which come back whatever is written here. Each name adds a block, and 'basic' asks for those fields alone."
      • addedInput schema / properties / sections / maxItems
        Added value: +3
      • addedInput schema / properties / sections / minItems
        Added value: +1
      • addedInput schema / properties / sources
        Added value: +{
        +  "items": {
        +    "enum": [
        +      "stashdb",
        +      "tpdb",
        +      "fansdb",
        +      "pmv",
        +      "javstash"
        +    ],
        +    "type": "string"
        +  },
        +  "maxItems": 5,
        +  "minItems": 1,
        +  "type": "array"
        +}
      • removedOutput schema / description
        Removed value: -"A scene when 'status' is 'established'. When it is 'deleted' or 'merged' this is a marker: it carries the identifier, the catalogue, the successor and the former title, and no field describing a scene."
      • addedOutput schema / properties / cached
        Added value: +{
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / card
        Added value: +{
        +  "additionalProperties": false,
        +  "properties": {
        +    "counts": {
        +      "additionalProperties": {
        +        "items": {
        +          "additionalProperties": false,
        +          "properties": {
        +            "source": {
        +              "type": "string"
        +            },
        +            "state": {
        +              "enum": [
        +                "answered",
        +                "failed",
        +                "absent"
        +              ],
        +              "type": "string"
        +            },
        +            "value": {
        +              "anyOf": [
        +                {
        +                  "type": "number"
        +                },
        +                {
        +                  "type": "null"
        +                }
        +              ]
        +            }
        +          },
        +          "required": [
        +            "source",
        +            "value",
        +            "state"
        +          ],
        +          "type": "object"
        +        },
        +        "type": "array"
        +      },
        +      "description": "Counts, one entry per catalogue asked and never added together. A null is read with the state beside it: a catalogue that publishes no such count, one that could not answer, and one nobody asked are three different facts.",
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "fields": {
        +      "additionalProperties": {
        +        "anyOf": [
        +          {
        +            "additionalProperties": false,
        +            "properties": {
        +              "agreed_by": {
        +                "description": "The catalogues that published this reading. Two agreeing is evidence of its own.",
        +                "items": {
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              },
        +              "disagreed": {
        +                "description": "The readings nobody preferred, published rather than dropped: choosing between them is a policy, and a policy applied in silence is a claim nobody can check.",
        +                "items": {
        +                  "additionalProperties": false,
        +                  "properties": {
        +                    "source": {
        +                      "type": "string"
        +                    },
        +                    "value": {}
        +                  },
        +                  "required": [
        +                    "source",
        +                    "value"
        +                  ],
        +                  "type": "object"
        +                },
        +                "type": "array"
        +              },
        +              "value": {
        +                "description": "The reading the preference named, null where none published one."
        +              }
        +            },
        +            "required": [
        +              "value",
        +              "agreed_by"
        +            ],
        +            "type": "object"
        +          },
        +          {
        +            "items": {
        +              "additionalProperties": false,
        +              "properties": {
        +                "also_at": {
        +                  "description": "What this same record is called on another catalogue, from a link joining the two.",
        +                  "items": {
        +                    "additionalProperties": false,
        +                    "properties": {
        +                      "id": {
        +                        "type": "string"
        +                      },
        +                      "source": {
        +                        "type": "string"
        +                      }
        +                    },
        +                    "required": [
        +                      "source",
        +                      "id"
        +                    ],
        +                    "type": "object"
        +                  },
        +                  "type": "array"
        +                },
        +                "published_by": {
        +                  "description": "Every catalogue that published this very record. A shared name is no join, so an entry one catalogue minted names that one.",
        +                  "items": {
        +                    "type": "string"
        +                  },
        +                  "type": "array"
        +                },
        +                "same_name_as": {
        +                  "description": "A record another catalogue published under a matching name. A resemblance, never a join.",
        +                  "items": {
        +                    "additionalProperties": false,
        +                    "properties": {
        +                      "id": {
        +                        "type": "string"
        +                      },
        +                      "source": {
        +                        "type": "string"
        +                      }
        +                    },
        +                    "required": [
        +                      "source",
        +                      "id"
        +                    ],
        +                    "type": "object"
        +                  },
        +                  "type": "array"
        +                },
        +                "value": {}
        +              },
        +              "required": [
        +                "value",
        +                "published_by"
        +              ],
        +              "type": "object"
        +            },
        +            "type": "array"
        +          }
        +        ]
        +      },
        +      "description": "Each field of the record. A scalar carries the catalogues that said it; a list is the union, each entry naming who published it.",
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "held_by": {
        +      "description": "Every catalogue asked, with the identifier the record carries there.",
        +      "items": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "error": {
        +            "type": "string"
        +          },
        +          "id": {
        +            "type": "string"
        +          },
        +          "reason": {
        +            "type": "string"
        +          },
        +          "retrieved_at": {
        +            "description": "The moment this client read it there.",
        +            "type": "string"
        +          },
        +          "source": {
        +            "type": "string"
        +          },
        +          "source_url": {
        +            "description": "The address it was read at, which credits it.",
        +            "type": "string"
        +          },
        +          "state": {
        +            "enum": [
        +              "answered",
        +              "failed",
        +              "absent"
        +            ],
        +            "type": "string"
        +          },
        +          "status": {
        +            "description": "What the identifier addresses there now. A folded record is held elsewhere.",
        +            "enum": [
        +              "established",
        +              "merged",
        +              "deleted"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "source",
        +          "state"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "kind": {
        +      "type": "string"
        +    },
        +    "notes": {
        +      "description": "What this answer does not establish, which is what makes it safe to act on.",
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "preferred": {
        +      "description": "The order the readings were preferred in. This is the policy that was applied, whether or not every catalogue in it answered.",
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    },
        +    "read_from": {
        +      "description": "The catalogues that answered, in the order they were preferred. A policy and an outcome are two facts, and a reader deciding whether to change the policy needs both.",
        +      "items": {
        +        "type": "string"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "kind",
        +    "fields",
        +    "counts",
        +    "held_by",
        +    "preferred",
        +    "read_from",
        +    "notes"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / properties / code
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "description": "The studio's own reference, in whatever form it publishes."
        -}
      • removedOutput schema / properties / created
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • removedOutput schema / properties / details
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • removedOutput schema / properties / director
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "description": "Free text, which can name several people."
        -}
      • removedOutput schema / properties / duration_seconds
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "number"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • removedOutput schema / properties / fingerprint_count
        Removed value: -{
        -  "additionalProperties": {
        -    "type": "number"
        -  },
        -  "propertyNames": {
        -    "type": "string"
        -  },
        -  "type": "object"
        -}
      • removedOutput schema / properties / fingerprints
        Removed value: -{
        -  "items": {
        -    "additionalProperties": false,
        -    "properties": {
        -      "algorithm": {
        -        "enum": [
        -          "MD5",
        -          "OSHASH",
        -          "PHASH"
        -        ],
        -        "type": "string"
        -      },
        -      "contested": {
        -        "anyOf": [
        -          {
        -            "type": "boolean"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Whether the reports reach the submissions. Null where the catalogue publishes no report count: a fingerprint nobody has disputed and one on a catalogue that counts no disputes are different things."
        -      },
        -      "duration_seconds": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "hash": {
        -        "type": "string"
        -      },
        -      "reports": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "How many people reported against it. Null on a catalogue that records no reports, which is an unknown contest and never an absence of one."
        -      },
        -      "submissions": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "How many people entered this fingerprint. Null where the catalogue counts none."
        -      }
        -    },
        -    "required": [
        -      "algorithm",
        -      "hash",
        -      "duration_seconds",
        -      "submissions",
        -      "reports",
        -      "contested"
        -    ],
        -    "type": "object"
        -  },
        -  "type": "array"
        -}
      • removedOutput schema / properties / fingerprints_held
        Removed value: -{
        -  "description": "How many the record holds, where the section shows a page of them.",
        -  "type": "number"
        -}
      • removedOutput schema / properties / former_title
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "description": "Present on a marker: the title the record carried."
        -}
      • removedOutput schema / properties / id
        Removed value: -{
        -  "type": "string"
        -}
      • removedOutput schema / properties / images
        Removed value: -{
        -  "items": {
        -    "additionalProperties": false,
        -    "properties": {
        -      "height": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "url": {
        -        "description": "The address of the image. The image itself is never returned.",
        -        "type": "string"
        -      },
        -      "width": {
        -        "anyOf": [
        -          {
        -            "type": "number"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      }
        -    },
        -    "required": [
        -      "url",
        -      "width",
        -      "height"
        -    ],
        -    "type": "object"
        -  },
        -  "type": "array"
        -}
      • removedOutput schema / properties / merged_into
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "description": "Present on a marker: the identifier that continues this record."
        -}
      • removedOutput schema / properties / notes
        Removed value: -{
        -  "items": {
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • addedOutput schema / properties / per_source
        Added value: +{
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "algorithms_not_searched": {
        +        "description": "Fingerprint algorithms its lookup does not search, so they were never put to it.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "count": {
        +        "description": "Rows it contributed. Never added to another catalogue's: they index corpora that overlap by an amount none of them publishes.",
        +        "type": "number"
        +      },
        +      "error": {
        +        "enum": [
        +          "not_found",
        +          "invalid_input",
        +          "rate_limited",
        +          "parse_failure",
        +          "network_error",
        +          "timeout"
        +        ],
        +        "type": "string"
        +      },
        +      "index_total": {
        +        "description": "What its own index holds for this question, the rows on this page included.",
        +        "type": "number"
        +      },
        +      "index_total_over_any_word": {
        +        "description": "The total counts rows carrying any word of the query, its text index reading them apart.",
        +        "type": "boolean"
        +      },
        +      "moment": {
        +        "description": "Which moment failed.",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "The name that catalogue calls itself.",
        +        "type": "string"
        +      },
        +      "narrowings_naming_no_record": {
        +        "description": "Narrowings written only with identifiers another catalogue minted.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "narrowings_not_received": {
        +        "description": "Narrowings this catalogue cannot receive. This is the one field that says a catalogue cannot do something.",
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "narrowings_received_in_part": {
        +        "items": {
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "reason": {
        +        "description": "Why it was not asked, or what went wrong.",
        +        "type": "string"
        +      },
        +      "records": {
        +        "description": "Distinct records behind its rows.",
        +        "type": "number"
        +      },
        +      "skipped": {
        +        "description": "Rows it answered with that this client could not read and left out.",
        +        "type": "number"
        +      },
        +      "source": {
        +        "description": "The catalogue this row is about.",
        +        "type": "string"
        +      },
        +      "state": {
        +        "description": "'answered' looked, and a count of zero means it found nothing. 'failed' could not answer, and states nothing about what it holds. 'absent' was never asked. Only the first is evidence about the world.",
        +        "enum": [
        +          "answered",
        +          "failed",
        +          "absent"
        +        ],
        +        "type": "string"
        +      },
        +      "unattributed": {
        +        "description": "Records it answered with while carrying none of what was asked about.",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "source",
        +      "state"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • removedOutput schema / properties / performers
        Removed value: -{
        -  "items": {
        -    "additionalProperties": false,
        -    "properties": {
        -      "credited_as": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "The name printed on this release, where it differs from the performer's own. It travels beside that name and never in place of it."
        -      },
        -      "disambiguation": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "id": {
        -        "type": "string"
        -      },
        -      "name": {
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "id",
        -      "name",
        -      "credited_as",
        -      "disambiguation"
        -    ],
        -    "type": "object"
        -  },
        -  "type": "array"
        -}
      • removedOutput schema / properties / production_date
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "additionalProperties": false,
        -      "properties": {
        -        "precision": {
        -          "description": "How much of the date a cataloguer entered. A value recorded to the year carries no month and no day, and reading it as one would claim a precision nobody entered.",
        -          "enum": [
        -            "day",
        -            "month",
        -            "year"
        -          ],
        -          "type": "string"
        -        },
        -        "value": {
        -          "description": "The date exactly as the catalogue publishes it.",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "value",
        -        "precision"
        -      ],
        -      "type": "object"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "description": "When the scene was made, which is a different question from when it was published. Rarely recorded, and never filled in from the release date."
        -}
      • removedOutput schema / properties / release_date
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "additionalProperties": false,
        -      "properties": {
        -        "precision": {
        -          "description": "How much of the date a cataloguer entered. A value recorded to the year carries no month and no day, and reading it as one would claim a precision nobody entered.",
        -          "enum": [
        -            "day",
        -            "month",
        -            "year"
        -          ],
        -          "type": "string"
        -        },
        -        "value": {
        -          "description": "The date exactly as the catalogue publishes it.",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "value",
        -        "precision"
        -      ],
        -      "type": "object"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "description": "When the scene was published."
        -}
      • removedOutput schema / properties / retrieved_at
        Removed value: -{
        -  "description": "When this record came off the catalogue, ISO 8601.",
        -  "type": "string"
        -}
      • removedOutput schema / properties / source
        Removed value: -{
        -  "type": "string"
        -}
      • removedOutput schema / properties / source_url
        Removed value: -{
        -  "type": "string"
        -}
      • removedOutput schema / properties / status
        Removed value: -{
        -  "description": "'established' is a record the catalogue holds. 'merged' and 'deleted' are markers: the identifier resolves, and what comes back describes the record rather than the thing it once named.",
        -  "enum": [
        -    "established",
        -    "deleted",
        -    "merged"
        -  ],
        -  "type": "string"
        -}
      • removedOutput schema / properties / studio
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "additionalProperties": false,
        -      "properties": {
        -        "id": {
        -          "type": "string"
        -        },
        -        "name": {
        -          "type": "string"
        -        },
        -        "parent": {
        -          "anyOf": [
        -            {
        -              "type": "string"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ]
        -        }
        -      },
        -      "required": [
        -        "id",
        -        "name",
        -        "parent"
        -      ],
        -      "type": "object"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • removedOutput schema / properties / tags
        Removed value: -{
        -  "items": {
        -    "additionalProperties": false,
        -    "properties": {
        -      "category": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "id": {
        -        "type": "string"
        -      },
        -      "name": {
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "id",
        -      "name",
        -      "category"
        -    ],
        -    "type": "object"
        -  },
        -  "type": "array"
        -}
      • removedOutput schema / properties / title
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • removedOutput schema / properties / updated
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • removedOutput schema / properties / urls
        Removed value: -{
        -  "items": {
        -    "additionalProperties": false,
        -    "properties": {
        -      "site_category": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "The catalogue's own category for that site. Null on a catalogue that publishes no table of sites, since borrowing a neighbour's would sort a link by a taxonomy this catalogue never applied."
        -      },
        -      "site_name": {
        -        "type": "string"
        -      },
        -      "url": {
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "url",
        -      "site_name",
        -      "site_category"
        -    ],
        -    "type": "object"
        -  },
        -  "type": "array"
        -}
      • changedOutput schema / required
        Previous value: -[
        -  "id",
        -  "source",
        -  "source_url",
        -  "retrieved_at",
        -  "status",
        -  "notes"
        -]New value: +[
        +  "card"
        +]
    • Addedget_sources
    • Addedget_studio
    • Addedget_tag
    • Changedsearch_performers61 fields changed
      • addedInput schema / properties / alias
        Added value: +{
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / birth_year
        Added value: +{
        +  "maximum": 2200,
        +  "minimum": 1800,
        +  "type": "integer"
        +}
      • addedInput schema / properties / career_end_year
        Added value: +{
        +  "maximum": 2200,
        +  "minimum": 1800,
        +  "type": "integer"
        +}
      • addedInput schema / properties / career_start_year
        Added value: +{
        +  "maximum": 2200,
        +  "minimum": 1800,
        +  "type": "integer"
        +}
      • removedInput schema / properties / country / description
        Removed value: -"Two-letter country code."
      • addedInput schema / properties / country / pattern
        Added value: +"^[A-Za-z]{2}$"
      • removedInput schema / properties / disambiguation / description
        Removed value: -"Free text a catalogue uses to tell two people of one name apart."
      • addedInput schema / properties / disambiguation / minLength
        Added value: +1
      • addedInput schema / properties / ethnicity
        Added value: +{
        +  "enum": [
        +    "UNKNOWN",
        +    "CAUCASIAN",
        +    "BLACK",
        +    "ASIAN",
        +    "INDIAN",
        +    "LATIN",
        +    "MIDDLE_EASTERN",
        +    "MIXED",
        +    "OTHER"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / gender
        Added value: +{
        +  "enum": [
        +    "UNKNOWN",
        +    "MALE",
        +    "FEMALE",
        +    "TRANSGENDER_MALE",
        +    "TRANSGENDER_FEMALE",
        +    "INTERSEX",
        +    "NON_BINARY"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / limit / description
        Added value: +"How many rows one page of one catalogue carries. An answer holding several catalogues carries up to this many from each of them, since their pages are their own and nothing here interleaves them into one."
      • addedInput schema / properties / name / minLength
        Added value: +1
      • addedInput schema / properties / page / description
        Added value: +"The page of each catalogue's own order. A route that reads words alone takes no page, and the answer reports it as one that catalogue did not receive."
      • changedInput schema / properties / page / maximum
        Previous value: -10000New value: +1000
      • removedInput schema / properties / performed_with / description
        Removed value: -"Namespaced identifier of another performer."
      • addedInput schema / properties / performed_with / pattern
        Added value: +"^(?:(?:stashdb|tpdb|fansdb|pmv|javstash):)?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
      • changedInput schema / properties / query / description
        Previous value: -"Free text matched against names and aliases."New value: +"Words for the catalogue's own text index, which reads them as a union. It is exclusive with the typed arguments, which narrow as an intersection."
      • addedInput schema / properties / query / minLength
        Added value: +1
      • changedInput schema / properties / sort / enum
        Previous value: -[
        -  "name",
        -  "birthdate",
        -  "scene_count",
        -  "created",
        -  "updated"
        -]New value: +[
        +  "name",
        +  "birthdate",
        +  "deathdate",
        +  "scene_count",
        +  "career_start_year",
        +  "debut",
        +  "last_scene",
        +  "popularity",
        +  "created_at",
        +  "updated_at"
        +]
      • addedInput schema / properties / sources / items / enum
        Added value: +[
        +  "stashdb",
        +  "tpdb",
        +  "fansdb",
        +  "pmv",
        +  "javstash"
        +]
      • addedInput schema / properties / sources / maxItems
        Added value: +5
      • addedInput schema / properties / sources / minItems
        Added value: +1
      • removedInput schema / properties / studio_id / description
        Removed value: -"Namespaced studio identifier."
      • addedInput schema / properties / studio_id / pattern
        Added value: +"^(?:(?:stashdb|tpdb|fansdb|pmv|javstash):)?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
      • changedOutput schema / properties / cached / description
        Previous value: -"Present when the answer came from the in-memory store."New value: +"Replayed from this client's store."
      • changedOutput schema / properties / ordering / description
        Previous value: -"How the order was built. The catalogues publish no score in common, so rows interleave and nothing is ranked across them."New value: +"How the rows were laid out, which a reader needs before reading the first."
      • addedOutput schema / properties / per_source / items / properties / algorithms_not_searched
        Added value: +{
        +  "description": "Fingerprint algorithms its lookup does not search, so they were never put to it.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • changedOutput schema / properties / per_source / items / properties / count / description
        Previous value: -"Rows this catalogue contributed to this page."New value: +"Rows it contributed. Never added to another catalogue's: they index corpora that overlap by an amount none of them publishes."
      • addedOutput schema / properties / per_source / items / properties / error / enum
        Added value: +[
        +  "not_found",
        +  "invalid_input",
        +  "rate_limited",
        +  "parse_failure",
        +  "network_error",
        +  "timeout"
        +]
      • removedOutput schema / properties / per_source / items / properties / fields_searched
        Removed value: -{
        -  "description": "The fields the text index read. Absent where no text index was consulted.",
        -  "items": {
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • changedOutput schema / properties / per_source / items / properties / index_total / description
        Previous value: -"What this catalogue's index holds for the question, beyond the page returned."New value: +"What its own index holds for this question, the rows on this page included."
      • addedOutput schema / properties / per_source / items / properties / index_total_over_any_word
        Added value: +{
        +  "description": "The total counts rows carrying any word of the query, its text index reading them apart.",
        +  "type": "boolean"
        +}
      • changedOutput schema / properties / per_source / items / properties / moment / description
        Previous value: -"Which step failed, for a catalogue that failed."New value: +"Which moment failed."
      • addedOutput schema / properties / per_source / items / properties / name / description
        Added value: +"The name that catalogue calls itself."
      • addedOutput schema / properties / per_source / items / properties / narrowings_naming_no_record
        Added value: +{
        +  "description": "Narrowings written only with identifiers another catalogue minted.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • changedOutput schema / properties / per_source / items / properties / narrowings_not_received / description
        Previous value: -"Narrowings this catalogue could not receive. A row of its satisfying one of them does so by chance."New value: +"Narrowings this catalogue cannot receive. This is the one field that says a catalogue cannot do something."
      • addedOutput schema / properties / per_source / items / properties / narrowings_received_in_part
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / per_source / items / properties / reason / description
        Added value: +"Why it was not asked, or what went wrong."
      • addedOutput schema / properties / per_source / items / properties / records
        Added value: +{
        +  "description": "Distinct records behind its rows.",
        +  "type": "number"
        +}
      • addedOutput schema / properties / per_source / items / properties / skipped / description
        Added value: +"Rows it answered with that this client could not read and left out."
      • addedOutput schema / properties / per_source / items / properties / source / description
        Added value: +"The catalogue this row is about."
      • changedOutput schema / properties / per_source / items / properties / state / description
        Previous value: -"'answered' is a catalogue that looked, and a count of zero there means it found nothing. 'failed' could not answer. 'absent' was never asked. An answer holding rows from some catalogues is no evidence about the others."New value: +"'answered' looked, and a count of zero means it found nothing. 'failed' could not answer, and states nothing about what it holds. 'absent' was never asked. Only the first is evidence about the world."
      • addedOutput schema / properties / per_source / items / properties / unattributed / description
        Added value: +"Records it answered with while carrying none of what was asked about."
      • removedOutput schema / properties / query
        Removed value: -{
        -  "type": "string"
        -}
      • addedOutput schema / properties / result_count / description
        Added value: +"How many rows this page carries."
      • changedOutput schema / properties / results / items / additionalProperties
        Previous value: -falseNew value: +{}
      • removedOutput schema / properties / results / items / properties / aliases
        Removed value: -{
        -  "items": {
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • removedOutput schema / properties / results / items / properties / birth_date
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "additionalProperties": false,
        -      "properties": {
        -        "precision": {
        -          "description": "How much of the date a cataloguer entered. A value recorded to the year carries no month and no day, and reading it as one would claim a precision nobody entered.",
        -          "enum": [
        -            "day",
        -            "month",
        -            "year"
        -          ],
        -          "type": "string"
        -        },
        -        "value": {
        -          "description": "The date exactly as the catalogue publishes it.",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "value",
        -        "precision"
        -      ],
        -      "type": "object"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • removedOutput schema / properties / results / items / properties / career_end_year
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "number"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • removedOutput schema / properties / results / items / properties / career_start_year
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "number"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • removedOutput schema / properties / results / items / properties / country
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • removedOutput schema / properties / results / items / properties / disambiguation
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • addedOutput schema / properties / results / items / properties / id / description
        Added value: +"Written instance:uuid. The catalogue travels with the uuid."
      • removedOutput schema / properties / results / items / properties / name
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • removedOutput schema / properties / results / items / properties / scene_count
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "number"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "description": "Scenes that catalogue has indexed crediting this performer."
        -}
      • addedOutput schema / properties / results / items / properties / source_url / description
        Added value: +"The address it was read from. Credit the catalogue and link it."
      • removedOutput schema / properties / results / items / properties / status / description
        Removed value: -"'established' is a record the catalogue holds. 'merged' and 'deleted' are markers: the identifier resolves, and what comes back describes the record rather than the thing it once named."
      • changedOutput schema / properties / results / items / properties / status / enum
        Previous value: -[
        -  "established",
        -  "deleted",
        -  "merged"
        -]New value: +[
        +  "established",
        +  "merged",
        +  "deleted"
        +]
      • changedOutput schema / properties / results / items / required
        Previous value: -[
        -  "id",
        -  "source",
        -  "name",
        -  "disambiguation",
        -  "aliases",
        -  "country",
        -  "birth_date",
        -  "career_start_year",
        -  "career_end_year",
        -  "scene_count",
        -  "status",
        -  "source_url"
        -]New value: +[
        +  "id",
        +  "source",
        +  "source_url",
        +  "status"
        +]
      • changedOutput schema / properties / window / description
        Previous value: -"The window this answer covers, per catalogue. An emptiness here is an emptiness inside that window."New value: +"The page a catalogue paged through, absent where none was given one."
      • changedOutput schema / required
        Previous value: -[
        -  "results",
        -  "result_count",
        -  "ordering",
        -  "per_source",
        -  "notes"
        -]New value: +[
        +  "results",
        +  "result_count",
        +  "per_source",
        +  "ordering",
        +  "notes"
        +]
    • Changedsearch_scenes64 fields changed
      • addedInput schema / properties / alias
        Added value: +{
        +  "minLength": 1,
        +  "type": "string"
        +}
      • removedInput schema / properties / code / description
        Removed value: -"The studio's own reference for the scene."
      • addedInput schema / properties / code / minLength
        Added value: +1
      • addedInput schema / properties / date
        Added value: +{
        +  "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        +  "type": "string"
        +}
      • addedInput schema / properties / date_compare
        Added value: +{
        +  "description": "These catalogues compare a date against one bound and answer no range, so the comparison is written rather than assumed.",
        +  "enum": [
        +    "on",
        +    "before",
        +    "after"
        +  ],
        +  "type": "string"
        +}
      • removedInput schema / properties / date_from
        Removed value: -{
        -  "description": "Released strictly after this date, as YYYY-MM-DD. A catalogue takes one date comparison at a time, so giving both bounds sends this one and reports the other as not received.",
        -  "type": "string"
        -}
      • removedInput schema / properties / date_to
        Removed value: -{
        -  "description": "Released strictly before this date, as YYYY-MM-DD.",
        -  "type": "string"
        -}
      • addedInput schema / properties / limit / description
        Added value: +"How many rows one page of one catalogue carries. An answer holding several catalogues carries up to this many from each of them, since their pages are their own and nothing here interleaves them into one."
      • removedInput schema / properties / match / description
        Removed value: -"How a list of identifiers reads. 'all' returns scenes carrying every one of them and is the default; 'any' returns scenes carrying at least one."
      • addedInput schema / properties / page / description
        Added value: +"The page of each catalogue's own order. A route that reads words alone takes no page, and the answer reports it as one that catalogue did not receive."
      • changedInput schema / properties / page / maximum
        Previous value: -10000New value: +1000
      • addedInput schema / properties / parent_studio_id
        Added value: +{
        +  "pattern": "^(?:(?:stashdb|tpdb|fansdb|pmv|javstash):)?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
        +  "type": "string"
        +}
      • removedInput schema / properties / performer_ids / description
        Removed value: -"Namespaced performer identifiers."
      • addedInput schema / properties / performer_ids / items / pattern
        Added value: +"^(?:(?:stashdb|tpdb|fansdb|pmv|javstash):)?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
      • addedInput schema / properties / performer_ids / maxItems
        Added value: +25
      • addedInput schema / properties / performer_ids / minItems
        Added value: +1
      • changedInput schema / properties / query / description
        Previous value: -"Free text matched against a scene's own fields."New value: +"Words for the catalogue's own text index, which reads them as a union. It is exclusive with the typed arguments, which narrow as an intersection."
      • addedInput schema / properties / query / minLength
        Added value: +1
      • changedInput schema / properties / sort / enum
        Previous value: -[
        -  "title",
        -  "date",
        -  "duration",
        -  "created",
        -  "updated"
        -]New value: +[
        +  "title",
        +  "date",
        +  "duration",
        +  "trending",
        +  "popularity",
        +  "created_at",
        +  "updated_at"
        +]
      • addedInput schema / properties / sources / items / enum
        Added value: +[
        +  "stashdb",
        +  "tpdb",
        +  "fansdb",
        +  "pmv",
        +  "javstash"
        +]
      • addedInput schema / properties / sources / maxItems
        Added value: +5
      • addedInput schema / properties / sources / minItems
        Added value: +1
      • addedInput schema / properties / studio_ids / items / pattern
        Added value: +"^(?:(?:stashdb|tpdb|fansdb|pmv|javstash):)?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
      • addedInput schema / properties / studio_ids / maxItems
        Added value: +25
      • addedInput schema / properties / studio_ids / minItems
        Added value: +1
      • addedInput schema / properties / tag_ids / items / pattern
        Added value: +"^(?:(?:stashdb|tpdb|fansdb|pmv|javstash):)?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
      • addedInput schema / properties / tag_ids / maxItems
        Added value: +25
      • addedInput schema / properties / tag_ids / minItems
        Added value: +1
      • addedInput schema / properties / title / minLength
        Added value: +1
      • changedOutput schema / properties / cached / description
        Previous value: -"Present when the answer came from the in-memory store."New value: +"Replayed from this client's store."
      • changedOutput schema / properties / ordering / description
        Previous value: -"How the order was built. The catalogues publish no score in common, so rows interleave and nothing is ranked across them."New value: +"How the rows were laid out, which a reader needs before reading the first."
      • addedOutput schema / properties / per_source / items / properties / algorithms_not_searched
        Added value: +{
        +  "description": "Fingerprint algorithms its lookup does not search, so they were never put to it.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • changedOutput schema / properties / per_source / items / properties / count / description
        Previous value: -"Rows this catalogue contributed to this page."New value: +"Rows it contributed. Never added to another catalogue's: they index corpora that overlap by an amount none of them publishes."
      • addedOutput schema / properties / per_source / items / properties / error / enum
        Added value: +[
        +  "not_found",
        +  "invalid_input",
        +  "rate_limited",
        +  "parse_failure",
        +  "network_error",
        +  "timeout"
        +]
      • removedOutput schema / properties / per_source / items / properties / fields_searched
        Removed value: -{
        -  "description": "The fields the text index read. Absent where no text index was consulted.",
        -  "items": {
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • changedOutput schema / properties / per_source / items / properties / index_total / description
        Previous value: -"What this catalogue's index holds for the question, beyond the page returned."New value: +"What its own index holds for this question, the rows on this page included."
      • addedOutput schema / properties / per_source / items / properties / index_total_over_any_word
        Added value: +{
        +  "description": "The total counts rows carrying any word of the query, its text index reading them apart.",
        +  "type": "boolean"
        +}
      • changedOutput schema / properties / per_source / items / properties / moment / description
        Previous value: -"Which step failed, for a catalogue that failed."New value: +"Which moment failed."
      • addedOutput schema / properties / per_source / items / properties / name / description
        Added value: +"The name that catalogue calls itself."
      • addedOutput schema / properties / per_source / items / properties / narrowings_naming_no_record
        Added value: +{
        +  "description": "Narrowings written only with identifiers another catalogue minted.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • changedOutput schema / properties / per_source / items / properties / narrowings_not_received / description
        Previous value: -"Narrowings this catalogue could not receive. A row of its satisfying one of them does so by chance."New value: +"Narrowings this catalogue cannot receive. This is the one field that says a catalogue cannot do something."
      • addedOutput schema / properties / per_source / items / properties / narrowings_received_in_part
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / per_source / items / properties / reason / description
        Added value: +"Why it was not asked, or what went wrong."
      • addedOutput schema / properties / per_source / items / properties / records
        Added value: +{
        +  "description": "Distinct records behind its rows.",
        +  "type": "number"
        +}
      • addedOutput schema / properties / per_source / items / properties / skipped / description
        Added value: +"Rows it answered with that this client could not read and left out."
      • addedOutput schema / properties / per_source / items / properties / source / description
        Added value: +"The catalogue this row is about."
      • changedOutput schema / properties / per_source / items / properties / state / description
        Previous value: -"'answered' is a catalogue that looked, and a count of zero there means it found nothing. 'failed' could not answer. 'absent' was never asked. An answer holding rows from some catalogues is no evidence about the others."New value: +"'answered' looked, and a count of zero means it found nothing. 'failed' could not answer, and states nothing about what it holds. 'absent' was never asked. Only the first is evidence about the world."
      • addedOutput schema / properties / per_source / items / properties / unattributed / description
        Added value: +"Records it answered with while carrying none of what was asked about."
      • removedOutput schema / properties / query
        Removed value: -{
        -  "type": "string"
        -}
      • changedOutput schema / properties / result_count / description
        Previous value: -"Rows returned here. Counts are never added across catalogues."New value: +"How many rows this page carries."
      • changedOutput schema / properties / results / items / additionalProperties
        Previous value: -falseNew value: +{}
      • removedOutput schema / properties / results / items / properties / duration_seconds
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "number"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • addedOutput schema / properties / results / items / properties / id / description
        Added value: +"Written instance:uuid. The catalogue travels with the uuid."
      • removedOutput schema / properties / results / items / properties / performers
        Removed value: -{
        -  "items": {
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
      • removedOutput schema / properties / results / items / properties / release_date
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "additionalProperties": false,
        -      "properties": {
        -        "precision": {
        -          "description": "How much of the date a cataloguer entered. A value recorded to the year carries no month and no day, and reading it as one would claim a precision nobody entered.",
        -          "enum": [
        -            "day",
        -            "month",
        -            "year"
        -          ],
        -          "type": "string"
        -        },
        -        "value": {
        -          "description": "The date exactly as the catalogue publishes it.",
        -          "type": "string"
        -        }
        -      },
        -      "required": [
        -        "value",
        -        "precision"
        -      ],
        -      "type": "object"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • removedOutput schema / properties / results / items / properties / retrieved_at
        Removed value: -{
        -  "description": "When this record came off the catalogue, ISO 8601.",
        -  "type": "string"
        -}
      • addedOutput schema / properties / results / items / properties / source_url / description
        Added value: +"The address it was read from. Credit the catalogue and link it."
      • removedOutput schema / properties / results / items / properties / status / description
        Removed value: -"'established' is a record the catalogue holds. 'merged' and 'deleted' are markers: the identifier resolves, and what comes back describes the record rather than the thing it once named."
      • changedOutput schema / properties / results / items / properties / status / enum
        Previous value: -[
        -  "established",
        -  "deleted",
        -  "merged"
        -]New value: +[
        +  "established",
        +  "merged",
        +  "deleted"
        +]
      • removedOutput schema / properties / results / items / properties / studio
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • removedOutput schema / properties / results / items / properties / title
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ]
        -}
      • changedOutput schema / properties / results / items / required
        Previous value: -[
        -  "id",
        -  "source",
        -  "title",
        -  "release_date",
        -  "duration_seconds",
        -  "studio",
        -  "performers",
        -  "status",
        -  "retrieved_at",
        -  "source_url"
        -]New value: +[
        +  "id",
        +  "source",
        +  "source_url",
        +  "status"
        +]
      • changedOutput schema / properties / window / description
        Previous value: -"The window this answer covers, per catalogue. An emptiness here is an emptiness inside that window."New value: +"The page a catalogue paged through, absent where none was given one."
      • changedOutput schema / required
        Previous value: -[
        -  "results",
        -  "result_count",
        -  "ordering",
        -  "per_source",
        -  "notes"
        -]New value: +[
        +  "results",
        +  "result_count",
        +  "per_source",
        +  "ordering",
        +  "notes"
        +]
    • Addedsearch_studios
    • Addedsearch_tags
  4. 4 tool updatesv0.2.1
    • Changedfind_by_fingerprint5 fields changed
      • addedOutput schema / properties / match_count / description
        Added value: +"Matches returned: one per scene per fingerprint it carries."
      • addedOutput schema / properties / per_source / items / properties / skipped
        Added value: +{
        +  "type": "number"
        +}
      • addedOutput schema / properties / per_source / items / properties / unattributed
        Added value: +{
        +  "type": "number"
        +}
      • addedOutput schema / properties / scenes_matched
        Added value: +{
        +  "description": "Distinct scenes behind those matches.",
        +  "type": "number"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "asked",
        -  "matches",
        -  "match_count",
        -  "unattributed",
        -  "per_source",
        -  "notes"
        -]New value: +[
        +  "asked",
        +  "matches",
        +  "match_count",
        +  "scenes_matched",
        +  "unattributed",
        +  "per_source",
        +  "notes"
        +]
    • Changedget_performer1 field changed
      • addedOutput schema / properties / studios_total
        Added value: +{
        +  "description": "How many the record credits, where the section shows a page of them.",
        +  "type": "number"
        +}
    • Changedsearch_performers9 fields changed
      • removedInput schema / properties / career_end_year
        Removed value: -{
        -  "maximum": 9007199254740991,
        -  "minimum": -9007199254740991,
        -  "type": "integer"
        -}
      • removedInput schema / properties / career_start_year
        Removed value: -{
        -  "maximum": 9007199254740991,
        -  "minimum": -9007199254740991,
        -  "type": "integer"
        -}
      • changedInput schema / properties / page / maximum
        Previous value: -9007199254740991New value: +10000
      • addedOutput schema / properties / cached
        Added value: +{
        +  "description": "Present when the answer came from the in-memory store.",
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / per_source / items / properties / skipped
        Added value: +{
        +  "type": "number"
        +}
      • addedOutput schema / properties / per_source / items / properties / unattributed
        Added value: +{
        +  "type": "number"
        +}
      • removedOutput schema / properties / query / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / query / type
        Added value: +"string"
      • changedOutput schema / required
        Previous value: -[
        -  "query",
        -  "results",
        -  "result_count",
        -  "ordering",
        -  "per_source",
        -  "notes"
        -]New value: +[
        +  "results",
        +  "result_count",
        +  "ordering",
        +  "per_source",
        +  "notes"
        +]
    • Changedsearch_scenes10 fields changed
      • changedInput schema / properties / date_from / description
        Previous value: -"Earliest release date, as YYYY-MM-DD."New value: +"Released strictly after this date, as YYYY-MM-DD. A catalogue takes one date comparison at a time, so giving both bounds sends this one and reports the other as not received."
      • changedInput schema / properties / date_to / description
        Previous value: -"Latest release date, as YYYY-MM-DD."New value: +"Released strictly before this date, as YYYY-MM-DD."
      • addedInput schema / properties / match
        Added value: +{
        +  "description": "How a list of identifiers reads. 'all' returns scenes carrying every one of them and is the default; 'any' returns scenes carrying at least one.",
        +  "enum": [
        +    "all",
        +    "any"
        +  ],
        +  "type": "string"
        +}
      • changedInput schema / properties / page / maximum
        Previous value: -9007199254740991New value: +10000
      • addedOutput schema / properties / cached
        Added value: +{
        +  "description": "Present when the answer came from the in-memory store.",
        +  "type": "boolean"
        +}
      • addedOutput schema / properties / per_source / items / properties / skipped
        Added value: +{
        +  "type": "number"
        +}
      • addedOutput schema / properties / per_source / items / properties / unattributed
        Added value: +{
        +  "type": "number"
        +}
      • removedOutput schema / properties / query / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / query / type
        Added value: +"string"
      • changedOutput schema / required
        Previous value: -[
        -  "query",
        -  "results",
        -  "result_count",
        -  "ordering",
        -  "per_source",
        -  "notes"
        -]New value: +[
        +  "results",
        +  "result_count",
        +  "ordering",
        +  "per_source",
        +  "notes"
        +]
  5. 5 tool updatesv0.1.1
    • First observedfind_by_fingerprint
    • First observedget_performer
    • First observedget_scene
    • First observedsearch_performers
    • First observedsearch_scenes

TDQS

A3.7/5.0

Scored across 10 tools

Disambiguation4/5

The set is neatly partitioned by verb (search_* vs get_*) and by entity type (scenes, performers, studios, tags), so selection is almost always obvious. The only soft edge is find_by_fingerprint, which reaches records that are then rendered like scene cards, making it slightly confusable with get_scene at the point of consumption; get_sources is clearly separate as install metadata.

Naming Consistency4/5

Names are uniformly snake_case and verb-led, with a clean search_<entity> / get_<entity> symmetry across the four entity types. find_by_fingerprint and get_sources break the verb_noun shape slightly (prepositional compound, and a non-entity noun), which is a minor deviation rather than an inconsistency.

Tool Count5/5

Ten tools is well within the ideal range and every tool earns its place: four entity searches, four entity reads, one hash lookup, and one configuration/health inspection. Nothing looks redundant or bolted on for a read-only cross-catalogue facade.

Completeness4/5

The read lifecycle is covered end to end for all four entity types: discover via search, resolve via get with cross-catalogue merge, plus fingerprint-based file identification and catalogue introspection. The main gap is the absence of an unfiltered browse/list operation — if a caller has no query terms or typed filters, there is no way to page through a catalogue's contents, and there are no tools for traversing relations (e.g. scenes by performer) beyond whatever filters the search schemas accept.

Maintenance

ActivityActive
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers