{"openapi":"3.1.0","info":{"title":"Noryo Transaction Intelligence API","version":"ti_v1+canon_ti_v1","summary":"D'une transaction financiere brute a une intelligence structuree.","description":"★ `signals.used` liste les signaux RECUS qui ont ete transmis au moteur — au resolveur d'identite, ou a la base pour les series, les relations et la couverture d'observation. `signals.ignored` liste ceux que personne n'a lus. Ce champ n'est pas une commodite : sans lui, un client peut envoyer un MCC pendant des mois, recevoir 200, et croire qu'il pese sur la reponse. \n\n★★★ LES NOMBRES DE CETTE API NE SONT PAS DES PROBABILITES. Une vingtaine de champs numeriques ressemblent a une confiance, sous trois noms (`confidence`, `strength`, `value`). Chacun porte une extension `x-noryo-score` qui dit sa CLASSE (`declared_constant`, `evidence_ratio`, `calendar_fill`, `anchor_stability`, `authority_tiebreak`, `text_coverage`), a quoi il est comparable, et a quoi il ne l'est PAS. Le meme `0.5` vaut 1/2 signal pour une paire de virement et 2/4 pour une contre-passation : il ne se compare qu'a l'interieur de sa classe et de son type. Aucun n'est calibre — `calibration = non_calibree` partout, par contrainte — parce qu'aucun corpus reel de reference ne permet aujourd'hui de rapporter l'un de ces nombres a une frequence observee. Les classes sont decrites dans `components.x-noryo-score-classes`. \n\n★ Le nom `confidence` (sous `resolution`) est conserve pour la compatibilite de `ti_v1`. Lisez-le comme « force declaree du motif », jamais comme une confiance."},"servers":[{"url":"https://api.noryo.app"}],"security":[{"txnApiKey":[]}],"x-noryo-rate-limit":{"policy_version":"debit_ti_v1","kind":"operational_burst_protection","not":["sandbox_lifetime_quota","production_usage_quota","billing_entitlement","commercial_promise"],"algorithm":"token_bucket","scopes":{"key":{"requests_per_minute":120,"burst_capacity":120,"refill_per_second":2},"workspace":{"requests_per_minute":600,"burst_capacity":600,"refill_per_second":10}},"translation":"« 120 requetes / minute » est traduit en seau a jetons : capacite 120 (la rafale toleree) rechargee a 2 jetons / seconde (le regime durable). Une clef au repos peut envoyer 120 requetes d'un coup, puis 2 par seconde ; sur la premiere minute apres un repos, jusqu'a 240 passent. Le workspace, lui, borne la somme de toutes ses clefs a 600 / minute (capacite 600, 10 / s) : cent clefs ne font pas cent fois la limite.","counts":["POST /transactions/v1/enrichments","GET /transactions/v1/enrichments/{enrichment_id}","POST /transactions/v1/coverage-windows"],"does_not_count":["GET /openapi.json","400 hote non declare, 415, 413 : refuses AVANT toute lecture de credential","401 credential absente, mal formee, d'une autre famille, inconnue, revoquee ou presentee sous un PREFIXE DIVERGENT ; 403 tenant inactif : aucun seau n'est touche, aucun usage n'est marque — la porte compare le prefixe declare AVANT de debiter"],"counts_even_when_refused":["422 schema, 400 JSON illisible ou Idempotency-Key invalide, 404, 409 : la credential etait valide, un jeton est consomme","200 rejeu idempotent : la requete a ete authentifiee et traitee, un jeton est consomme"],"order":"hote -> content-type -> taille du corps -> credential -> authentification + prefixe + usage + debit (une transaction) -> JSON -> Idempotency-Key -> schema -> metier : une credential inconnue n'a pas de seau et n'en apprend pas l'existence ; une clef valide consomme un jeton meme si la requete finit en 422.","environments":{"sandbox":"les valeurs ci-dessus","production":"NON OUVERTE. Des reglages provisoires existent en base et seront recalibres avant toute ouverture ; ils ne sont pas un engagement."},"environment_scoped":true,"authority":"database (single writer, atomic per request) — never a per-process counter","on_limiter_failure":"500 internal_error, fail closed — never a fabricated 429, never an unlimited API"},"paths":{"/openapi.json":{"get":{"operationId":"getOpenApiDocument","summary":"Ce document, tel qu'il est genere","security":[],"description":"★★★ UNE SEULE SOURCE. Le document servi est exactement celui que le runtime genere — pas une copie versionnee, pas un fichier reconstruit a la main, pas une « version site developpeur ». Public : aucune credential, aucun contexte de workspace, aucun debit consomme, aucun evenement facturable. ★ Ce n'est pas le portail developpeur : ici une machine lit un contrat ; les guides pour une personne vivent ailleurs. ★ Cacheable : `ETag` et `If-None-Match` -> 304 ; `Cache-Control: public, max-age=300, must-revalidate`. Servi sur les hotes declares de l'API (`servers`).","parameters":[{"name":"If-None-Match","in":"header","required":false,"schema":{"type":"string"},"description":"L'`ETag` d'une lecture precedente : 304 si le document n'a pas change."}],"responses":{"200":{"description":"Le document OpenAPI 3.1 courant.","headers":{"ETag":{"schema":{"type":"string"},"description":"Condense du corps ; change avec le document. L'hebergeur peut le rendre FAIBLE (`W/\"…\"`) derriere la compression : `If-None-Match` accepte les deux formes."},"Access-Control-Allow-Origin":{"schema":{"type":"string","enum":["*"]},"description":"Document public, sans credential : lisible depuis un navigateur (un explorateur OpenAPI) sur toute origine."},"Cache-Control":{"schema":{"type":"string","enum":["public, max-age=300, must-revalidate"]}}},"content":{"application/json":{"schema":{"type":"object","x-noryo-opaque":"le document OpenAPI lui-meme"}}}},"304":{"description":"Inchange depuis l'`ETag` presente. Corps vide."},"400":{"description":"Hote non declare : le document n'est servi que sur les hotes declares de l'API.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Erreur interne (configuration ou serialisation).","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/transactions/v1/coverage-windows":{"post":{"operationId":"declareCoverageWindow","summary":"Declarer ce qui a ete fourni pour un compte, sur une periode","description":"★★★ UNE COUVERTURE EST UN FAIT DE COMPTE ET DE PERIODE, PAS DE TRANSACTION. Elle repond a « toutes les operations de ce compte entre ces deux dates vous ont-elles ete fournies ? » — et elle existe precisement quand il n'y a AUCUNE transaction a envoyer : un mois sans prelevement est le cas ou la declaration compte le plus. C'est pour cela qu'elle a sa propre ressource plutot qu'un champ sur l'enrichissement. ★★★ SANS ELLE, NOUS NE DIRONS JAMAIS QU'UNE SERIE EST EN RETARD : l'absence d'une echeance ne prouve rien tant que nous ignorons si le compte etait observe, et `lifecycle.state` reste `unknown`. ★★★ ET NOUS NE VERIFIONS RIEN : ce que vous declarez est enregistre comme une affirmation d'appelant (`caller_asserted`). La provenance n'est pas un champ que vous choisissez. ★ L'appel est idempotent par construction : les intervalles qui se touchent fusionnent, donc une synchronisation horaire ne fabrique pas d'intervalles.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverageWindow"}}}},"responses":{"200":{"description":"Couverture enregistree, ou fusionnee avec une voisine.","headers":{"noryo-request-id":{"schema":{"type":"string"},"description":"L'identifiant de cette requete, le meme que `request_id` dans un probleme."},"noryo-ratelimit-limit":{"schema":{"type":"integer"},"description":"La capacite de rafale de VOTRE CLEF (120 en `debit_ti_v1`)."},"noryo-ratelimit-remaining":{"schema":{"type":"integer"},"description":"Ce que votre clef peut encore envoyer MAINTENANT : le plus petit des deux soldes, celui de la clef et celui du workspace (toutes clefs confondues)."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverageWindowResult"},"examples":{"enregistree":{"value":{"covered_from":"2026-07-01","covered_to":"2026-07-31","completeness":"complete","provenance":"caller_asserted","merged_intervals":0,"policy_version":"cov_v1","note":"","request_id":"req_01J9…"}},"fusionnee":{"summary":"Deux declarations qui se touchent n'en font qu'une.","value":{"covered_from":"2026-07-01","covered_to":"2026-08-15","completeness":"complete","provenance":"caller_asserted","merged_intervals":1,"policy_version":"cov_v1","note":"","request_id":"req_01J9…"}}}}}},"400":{"description":"Corps illisible, ou hote non declare.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Clef absente, inconnue ou revoquee.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Organisation ou workspace inactif.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"413":{"description":"Corps trop volumineux.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"415":{"description":"Le corps doit etre du application/json.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"Schema ferme : champ inconnu, compte absent ou malforme, jour inexistant, intervalle inverse ou dans le futur, completude inconnue. `errors[].code` nomme la regle, et la liste est celle du runtime, par construction : `must_be_object`, `unknown_field`, `required`, `malformed_iban`, `must_be_non_empty_string`, `too_long`, `contains_control_character`, `account_identity_required`, `must_be_iso_date`, `after_covered_to`, `unknown_completeness`, `interval_in_future`. ★ `must_be_iso_date` couvre la FORME et le CALENDRIER (`2026-02-30` est refuse). `interval_in_future` : `covered_to` au-dela de demain, date du serveur en UTC. `provenance` n'est pas un champ d'entree : le schema ferme le refuse `unknown_field`, la base ne le voit jamais.","headers":{"noryo-ratelimit-limit":{"schema":{"type":"integer"},"description":"La capacite de rafale de VOTRE CLEF (120 en `debit_ti_v1`)."},"noryo-ratelimit-remaining":{"schema":{"type":"integer"},"description":"Ce que votre clef peut encore envoyer MAINTENANT : le plus petit des deux soldes, celui de la clef et celui du workspace (toutes clefs confondues)."}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"`rate_limited` : la limite operationnelle de debit est atteinte, pour cette clef ou pour le workspace (le `detail` le dit). Rien n'a ete calcule, rien n'a ete range, aucun evenement n'a ete emis. Rejouez apres `Retry-After`. Voir `x-noryo-rate-limit`.","headers":{"Retry-After":{"schema":{"type":"integer","minimum":1},"description":"Secondes entieres avant que le seau qui a refuse couvre une requete."},"noryo-ratelimit-limit":{"schema":{"type":"integer"},"description":"La capacite de rafale de VOTRE CLEF (120 en `debit_ti_v1`)."},"noryo-ratelimit-remaining":{"schema":{"type":"integer"},"description":"Ce que votre clef peut encore envoyer MAINTENANT : le plus petit des deux soldes, celui de la clef et celui du workspace (toutes clefs confondues)."}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Erreur interne.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/transactions/v1/enrichments":{"post":{"operationId":"createEnrichment","summary":"Enrichir une transaction.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","pattern":"^[\\x21-\\x7E]{1,255}$"},"description":"★★★ FACULTATIF. Avec la meme clef et la meme requete : REJEU (200), la reponse d'origine est rendue telle quelle, version de moteur comprise. Avec la meme clef et une requete differente : 409. ★★★ « REQUETE DIFFERENTE » SE JUGE SUR L'EMPREINTE ECONOMIQUE (`fingerprint`), et sur elle seule : deux corps qui ne different que par `external_transaction_id`, `account_hint` ou `counterparty_hint` ont la meme empreinte et sont la MEME requete pour l'idempotence — le premier envoi est rejoue tel quel. Ne reutilisez pas une clef pour deux transactions que vous distinguez par ces seuls champs. ★★★ AUCUNE VERSION DE MOTEUR N'ENTRE DANS CETTE IDENTITE : un deploiement entre deux tentatives ne transforme pas un rejeu en operation neuve. La valeur brute n'est jamais rangee ni journalisee. ★ La clef est retenue AU MOINS 24 heures : elle expire 24 heures apres le premier envoi et n'est effacee que par la purge quotidienne qui suit cette expiration. Entre 24 et 48 heures apres le premier envoi, la meme clef ouvre donc une operation neuve (201) — jamais avant 24 heures. De 1 a 255 OCTETS d'ASCII visible (0x21 a 0x7E) ; une valeur vide ou hors alphabet est refusee 400."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransactionInput"},"examples":{"achat_carte":{"summary":"Un achat carte, avec le compte pour relier une couverture","value":{"descriptor":"CARTE 09/09 MONOPRIX PARIS 15","direction":"outgoing","occurred_at":"2026-09-09T07:31:00+02:00","amount":{"value":"49.90","currency":"EUR"},"payment":{"rail":"card","mcc":"5411","card_present":true},"location_hint":{"country":"FR"},"account_hint":{"iban":"FR7630006000011234567890189"},"external_transaction_id":"tx-2026-09-09-0042"}},"prelevement":{"summary":"Un prelevement SEPA recurrent","value":{"descriptor":"PRLV SEPA NETFLIX INTERNATIONAL","direction":"outgoing","occurred_at":"2026-09-05T03:10:00+02:00","amount":{"value":"13.49","currency":"EUR"},"payment":{"rail":"sepa_direct_debit"},"account_hint":{"iban":"FR7630006000011234567890189"}}},"compte_sans_iban":{"summary":"Une carte prepayee : le compte se nomme par votre identifiant","value":{"descriptor":"APPLE.COM/BILL","direction":"outgoing","amount":{"value":"2.99","currency":"EUR"},"account_hint":{"external_account_id":"carte-4970"}}}}}}},"responses":{"200":{"description":"Deja enrichie : requete rejouee, rien n'a ete cree. ★ `Location` est pose ici aussi : le client apprend ou vit la ressource qu'il n'a pas creee.","headers":{"noryo-request-id":{"schema":{"type":"string"},"description":"L'identifiant de cette requete, le meme que `request_id` dans un probleme."},"noryo-ratelimit-limit":{"schema":{"type":"integer"},"description":"La capacite de rafale de VOTRE CLEF (120 en `debit_ti_v1`)."},"noryo-ratelimit-remaining":{"schema":{"type":"integer"},"description":"Ce que votre clef peut encore envoyer MAINTENANT : le plus petit des deux soldes, celui de la clef et celui du workspace (toutes clefs confondues)."},"Location":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Enrichment"}}}},"201":{"description":"Enrichissement cree.","headers":{"noryo-request-id":{"schema":{"type":"string"},"description":"L'identifiant de cette requete, le meme que `request_id` dans un probleme."},"noryo-ratelimit-limit":{"schema":{"type":"integer"},"description":"La capacite de rafale de VOTRE CLEF (120 en `debit_ti_v1`)."},"noryo-ratelimit-remaining":{"schema":{"type":"integer"},"description":"Ce que votre clef peut encore envoyer MAINTENANT : le plus petit des deux soldes, celui de la clef et celui du workspace (toutes clefs confondues)."},"Location":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Enrichment"},"examples":{"resolue":{"summary":"Un achat carte resolu, sans relation ni serie","value":{"enrichment_id":"enr_3f2504e0-4f89-41d3-9a0c-0305e82c3301","created_at":"2026-09-09T05:31:02Z","contract_version":"ti_v1","canonical_version":"canon_ti_v1","fingerprint":"canon_ti_v1:c2a1…","signals":{"used":["descriptor","direction","payment.rail","location_hint.country","occurred_at","amount","account_hint.iban","external_transaction_id"],"ignored":["payment.mcc","payment.card_present"],"conflicting":[]},"resolution":{"policy":{"outcome":"resolved","archetype":"achat_carte","missing":[],"policy_version":"ti_resolution_v1"},"normalized":{"descriptor":"CARTE 09 09 MONOPRIX PARIS","signal":"CARTE 09 09 MONOPRIX PARIS","useful":"09 09 MONOPRIX PARIS","residual":"CARTE 09 09 MONOPRIX PARIS","normalizer_version":"norm_ti_v3"},"counterparty":{"entity_id":"b83d1756-258c-4541-adc7-54eec83dbd3c","name":"Monoprix","kind":"brand","evidence":{"match":"jetons","pattern":"MONOPRIX","coverage":0.4},"semantics":{"roles":["merchant"],"activity":{"code":"retail.grocery","label":"alimentation generale","parent":"retail"},"provenance":{"nature":"curated","source":"catalogue_cure","strength":0.75,"calibration":"non_calibree","evidence":{"note":"La source est curee ; la derivation vers l'activite est deterministe.","derivation":"categorie_de_depense_vers_activite","categorie_source":"alimentation.supermarche"}},"legal_entity":{"entity_id":"5ecee4f8-fab0-444f-8711-29ff6e3f875a","name":"Groupe Casino"},"recurring_model":"usually_one_off"}},"counterparty_type":"merchant","counterparty_note":null,"category":{"slug":"alimentation.supermarche","label":"Supermarché","source":"entity_graph"},"identity_abstention":null,"intermediaries":[],"transaction_type":{"canonical":"card_purchase","evidence":"rail_rule","contradiction":null},"payment":{"rail":"card","mechanism":"card_purchase","note":"`rail` dit COMMENT l'argent a circule ; `transaction_type` dit CE QUE la transaction signifie. Un salaire recu par virement SEPA est les deux."},"signal_conflicts":[],"submerchant_lane":"none","truncated_lane":"none","confidence":{"entity":0.97,"counterparty":0.97,"transaction_type":0.95,"category":0.97,"location":0,"calibration":"non_calibree"},"timings_ms":{"normalization":4.1,"entity_resolution":10.8,"submerchant":2,"total":18.1},"versions":{"graph":"onto_v1","rules":"txtype_v1","engine":"ti_v4","resolution_policy":"ti_resolution_v1","calibration":"non_calibree"}},"relationships":[],"series":[],"relationships_policy":{"detector_version":"rel_v1","calibration":"non_calibree","unresolved":[{"type":"series","outcome":"single_occurrence","occurrences":1}]}}},"non_resolue":{"summary":"Un libelle que le graphe ne connait pas : la nature est connue (achat carte), l'entite manque — une abstention, pas une panne","value":{"enrichment_id":"enr_9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d","created_at":"2026-09-09T05:32:00Z","contract_version":"ti_v1","canonical_version":"canon_ti_v1","fingerprint":"canon_ti_v1:7f0e…","signals":{"used":["descriptor","direction"],"ignored":[],"conflicting":[]},"resolution":{"policy":{"outcome":"partial","archetype":"achat_carte","missing":["counterparty_entity"],"policy_version":"ti_resolution_v1"},"normalized":{"descriptor":"XK 4471 REF 88210","signal":"XK 4471 REF 88210","useful":"XK 4471 REF 88210","residual":"XK 4471 REF 88210","normalizer_version":"norm_ti_v3"},"counterparty":null,"counterparty_type":"unknown","counterparty_note":"aucun motif connu ne correspond","category":null,"identity_abstention":null,"intermediaries":[],"transaction_type":{"canonical":"card_purchase","evidence":"rail_rule","contradiction":null},"payment":{"rail":"card","mechanism":"card_purchase","note":"`rail` dit COMMENT l'argent a circule ; `transaction_type` dit CE QUE la transaction signifie. Un salaire recu par virement SEPA est les deux."},"signal_conflicts":[],"submerchant_lane":"none","truncated_lane":"none","confidence":{"entity":0,"counterparty":0,"transaction_type":0.95,"category":0,"location":0,"calibration":"non_calibree"},"timings_ms":{"normalization":0.1,"entity_resolution":3.8,"submerchant":1.1,"total":4.5},"versions":{"graph":"onto_v1","rules":"txtype_v1","engine":"ti_v4","resolution_policy":"ti_resolution_v1","calibration":"non_calibree"}},"relationships":[],"series":[],"relationships_policy":{"detector_version":"rel_v1","calibration":"non_calibree","unresolved":[{"type":"series","outcome":"no_series_key","occurrences":0}]}}},"remboursement":{"summary":"Un remboursement rattache a son achat, et une serie d'abonnement","value":{"enrichment_id":"enr_9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d","created_at":"2026-09-12T09:00:00Z","contract_version":"ti_v1","canonical_version":"canon_ti_v1","fingerprint":"canon_ti_v1:a9d3…","signals":{"used":["descriptor","direction","occurred_at","amount"],"ignored":[],"conflicting":[]},"resolution":{"policy":{"outcome":"resolved","archetype":"achat_carte","missing":[],"policy_version":"ti_resolution_v1"},"normalized":{"descriptor":"CARTE 09 09 MONOPRIX PARIS","signal":"CARTE 09 09 MONOPRIX PARIS","useful":"09 09 MONOPRIX PARIS","residual":"CARTE 09 09 MONOPRIX PARIS","normalizer_version":"norm_ti_v3"},"counterparty":{"entity_id":"b83d1756-258c-4541-adc7-54eec83dbd3c","name":"Monoprix","kind":"brand","evidence":{"match":"jetons","pattern":"MONOPRIX","coverage":0.4},"semantics":{"roles":["merchant"],"activity":{"code":"retail.grocery","label":"alimentation generale","parent":"retail"},"provenance":{"nature":"curated","source":"catalogue_cure","strength":0.75,"calibration":"non_calibree","evidence":{"note":"La source est curee ; la derivation vers l'activite est deterministe.","derivation":"categorie_de_depense_vers_activite","categorie_source":"alimentation.supermarche"}},"legal_entity":{"entity_id":"5ecee4f8-fab0-444f-8711-29ff6e3f875a","name":"Groupe Casino"},"recurring_model":"usually_one_off"}},"counterparty_type":"merchant","counterparty_note":null,"category":{"slug":"alimentation.supermarche","label":"Supermarché","source":"entity_graph"},"identity_abstention":null,"intermediaries":[],"transaction_type":{"canonical":"card_purchase","evidence":"rail_rule","contradiction":null},"payment":{"rail":"card","mechanism":"card_purchase","note":"`rail` dit COMMENT l'argent a circule ; `transaction_type` dit CE QUE la transaction signifie. Un salaire recu par virement SEPA est les deux."},"signal_conflicts":[],"submerchant_lane":"none","truncated_lane":"none","confidence":{"entity":0.97,"counterparty":0.97,"transaction_type":0.95,"category":0.97,"location":0,"calibration":"non_calibree"},"timings_ms":{"normalization":4.1,"entity_resolution":10.8,"submerchant":2,"total":18.1},"versions":{"graph":"onto_v1","rules":"txtype_v1","engine":"ti_v4","resolution_policy":"ti_resolution_v1","calibration":"non_calibree"}},"relationships":[{"type":"refund_of","role":"source","symmetric":false,"counterpart":"enr_3f2504e0-4f89-41d3-9a0c-0305e82c3301","match_strength":{"value":0.8,"calibration":"non_calibree","corroborations":{"present":4,"possible":5}},"evidence":[{"code":"same_counterparty_entity"},{"code":"refund_marker"},{"code":"within_window","value_seconds":259200},{"code":"resolved_type_refund"}],"window_seconds":2592000,"detector_version":"rel_v1","status":"active","created_at":"2026-09-12T09:00:00Z"}],"series":[{"series_id":"ser_6ba7b810-9dad-11d1-80b4-00c04fd430c8","type":"subscription","implies":["recurring_payment"],"status":"established","cadence":"monthly","cadence_detail":{"type":"monthly","strength":1,"calibration":"non_calibree"},"calendar_pattern":{"type":"fixed_day_of_month","nominal_day":5,"weekday":null,"day_range":[4,6],"weekend_shifts":0,"strength":0.67,"calibration":"non_calibree"},"occurrence_count":6,"amount_behavior":{"kind":"fixed","min_minor_units":"1349","max_minor_units":"1349","currency":"EUR"},"first_seen":"2026-04-05T03:10:00Z","last_seen":"2026-09-05T01:10:00Z","first_observed_on":"2026-04-05","last_observed_on":"2026-09-05","may_predate_observation":true,"expected_next_at":"2026-10-05T00:00:00Z","match_strength":{"value":1,"calibration":"non_calibree","corroborations":{"present":5,"possible":5}},"evidence":[{"code":"stable_counterparty","value":"entite:b83d1756-258c-4541-adc7-54eec83dbd3c"},{"code":"occurrences","value":6},{"code":"cadence","value":"monthly"},{"code":"amount_behavior","value":"fixed"},{"code":"subscription_category"}],"history_coverage":{"observed_from":"2026-04-05","observed_to":"2026-09-05","raw_days":30,"derived_days":400,"observed_days":153,"retention_limit_days":30,"occurrence_count":6,"cadence":"monthly","sufficiency":"sufficient","reason":"","first_occurrence_bounded":true,"first_occurrence_reason":"notre observation commence avec la premiere occurrence"},"lifecycle":{"state":"active","reason":"la prochaine echeance n'est pas encore echue","last_observed_on":"2026-09-05","expected_next_window":{"from":"2026-10-03","to":"2026-10-07","tolerance_days":5,"anchor":"fixed_day_of_month","widened_to_family_floor":true},"consecutive_misses":0,"observation_coverage":"complete","cadence_strength":1,"calendar_anchor":{"type":"fixed_day_of_month","nominal_day":5,"weekday":null,"day_range":[4,6],"weekend_shifts":0,"strength":0.67,"calibration":"non_calibree"},"policy_version":"cyc_v2","calibration":"non_calibree"},"identity":{"status":"current","superseded_by":null,"supersedes":[]},"membership":{"original_series_id":"ser_6ba7b810-9dad-11d1-80b4-00c04fd430c8","current_series_id":"ser_6ba7b810-9dad-11d1-80b4-00c04fd430c8","corrections":[]},"detector_version":"ser_v1"}],"relationships_policy":{"detector_version":"rel_v1","calibration":"non_calibree","unresolved":[]}}},"serie_scindee":{"summary":"Une occurrence dont la serie a ete SCINDEE : l'ancien nom redirige vers deux successeurs","value":{"enrichment_id":"enr_3f2504e0-4f89-41d3-9a0c-0305e82c3301","created_at":"2026-09-05T01:10:00Z","contract_version":"ti_v1","canonical_version":"canon_ti_v1","fingerprint":"canon_ti_v1:c2a1…","signals":{"used":["descriptor","direction","occurred_at","amount"],"ignored":[],"conflicting":[]},"resolution":{"policy":{"outcome":"resolved","archetype":"achat_carte","missing":[],"policy_version":"ti_resolution_v1"},"normalized":{"descriptor":"CARTE 09 09 MONOPRIX PARIS","signal":"CARTE 09 09 MONOPRIX PARIS","useful":"09 09 MONOPRIX PARIS","residual":"CARTE 09 09 MONOPRIX PARIS","normalizer_version":"norm_ti_v3"},"counterparty":{"entity_id":"b83d1756-258c-4541-adc7-54eec83dbd3c","name":"Monoprix","kind":"brand","evidence":{"match":"jetons","pattern":"MONOPRIX","coverage":0.4},"semantics":{"roles":["merchant"],"activity":{"code":"retail.grocery","label":"alimentation generale","parent":"retail"},"provenance":{"nature":"curated","source":"catalogue_cure","strength":0.75,"calibration":"non_calibree","evidence":{"note":"La source est curee ; la derivation vers l'activite est deterministe.","derivation":"categorie_de_depense_vers_activite","categorie_source":"alimentation.supermarche"}},"legal_entity":{"entity_id":"5ecee4f8-fab0-444f-8711-29ff6e3f875a","name":"Groupe Casino"},"recurring_model":"usually_one_off"}},"counterparty_type":"merchant","counterparty_note":null,"category":{"slug":"alimentation.supermarche","label":"Supermarché","source":"entity_graph"},"identity_abstention":null,"intermediaries":[],"transaction_type":{"canonical":"card_purchase","evidence":"rail_rule","contradiction":null},"payment":{"rail":"card","mechanism":"card_purchase","note":"`rail` dit COMMENT l'argent a circule ; `transaction_type` dit CE QUE la transaction signifie. Un salaire recu par virement SEPA est les deux."},"signal_conflicts":[],"submerchant_lane":"none","truncated_lane":"none","confidence":{"entity":0.97,"counterparty":0.97,"transaction_type":0.95,"category":0.97,"location":0,"calibration":"non_calibree"},"timings_ms":{"normalization":4.1,"entity_resolution":10.8,"submerchant":2,"total":18.1},"versions":{"graph":"onto_v1","rules":"txtype_v1","engine":"ti_v4","resolution_policy":"ti_resolution_v1","calibration":"non_calibree"}},"relationships":[],"series":[{"series_id":"ser_6ba7b811-9dad-11d1-80b4-00c04fd430c8","type":"subscription","implies":["recurring_payment"],"status":"uncertain","cadence":"irregular_recurring","cadence_detail":{"type":"irregular_recurring","strength":0,"calibration":"non_calibree"},"calendar_pattern":{"type":"fixed_day_of_month","nominal_day":5,"weekday":null,"day_range":[4,6],"weekend_shifts":0,"strength":0.67,"calibration":"non_calibree"},"occurrence_count":6,"amount_behavior":{"kind":"fixed","min_minor_units":"1349","max_minor_units":"1349","currency":"EUR"},"first_seen":"2026-04-05T03:10:00Z","last_seen":"2026-09-05T01:10:00Z","first_observed_on":"2026-04-05","last_observed_on":"2026-09-05","may_predate_observation":true,"expected_next_at":null,"match_strength":{"value":1,"calibration":"non_calibree","corroborations":{"present":5,"possible":5}},"evidence":[{"code":"stable_counterparty","value":"entite:b83d1756-258c-4541-adc7-54eec83dbd3c"},{"code":"occurrences","value":6},{"code":"cadence","value":"monthly"},{"code":"amount_behavior","value":"fixed"},{"code":"subscription_category"}],"history_coverage":{"observed_from":"2026-04-05","observed_to":"2026-09-05","raw_days":30,"derived_days":400,"observed_days":153,"retention_limit_days":30,"occurrence_count":6,"cadence":"monthly","sufficiency":"sufficient","reason":"","first_occurrence_bounded":true,"first_occurrence_reason":"notre observation commence avec la premiere occurrence"},"lifecycle":{"state":"unknown","reason":"identite corrigee : le cycle de vie appartient desormais aux successeurs","identity_status":"superseded","last_observed_on":"2026-09-05","policy_version":"cyc_v2","calibration":"non_calibree"},"identity":{"status":"superseded","superseded_by":{"reason":"split","at":"2026-09-10T22:14:00Z","evidence":["two_supported_partitions","time_overlap","basis_amount"],"successor_series_ids":["ser_6ba7b812-9dad-11d1-80b4-00c04fd430c8","ser_6ba7b810-9dad-11d1-80b4-00c04fd430c8"]},"supersedes":[]},"membership":{"original_series_id":"ser_6ba7b811-9dad-11d1-80b4-00c04fd430c8","current_series_id":"ser_6ba7b810-9dad-11d1-80b4-00c04fd430c8","corrections":[{"reason":"split","from_series_id":"ser_6ba7b811-9dad-11d1-80b4-00c04fd430c8","to_series_id":"ser_6ba7b810-9dad-11d1-80b4-00c04fd430c8","at":"2026-09-10T22:14:00Z"}]},"detector_version":"ser_v1"}],"relationships_policy":{"detector_version":"rel_v1","calibration":"non_calibree","unresolved":[]}}}}}}},"400":{"description":"Corps illisible, ou Idempotency-Key hors alphabet.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Credential absente, mal formee, d'une AUTRE FAMILLE, inconnue, revoquee, ou dont le prefixe declare ne correspond pas au prefixe enregistre. Un seul code pour tous ces cas : les distinguer serait un oracle.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Workspace ou organisation inactif.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Cette Idempotency-Key a deja servi pour une requete DIFFERENTE — c'est-a-dire d'empreinte economique (`fingerprint`) differente. Meme clef + meme empreinte = rejeu (200), jamais 409.","headers":{"noryo-ratelimit-limit":{"schema":{"type":"integer"},"description":"La capacite de rafale de VOTRE CLEF (120 en `debit_ti_v1`)."},"noryo-ratelimit-remaining":{"schema":{"type":"integer"},"description":"Ce que votre clef peut encore envoyer MAINTENANT : le plus petit des deux soldes, celui de la clef et celui du workspace (toutes clefs confondues)."}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"413":{"description":"Corps trop volumineux.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"415":{"description":"Le corps doit etre du application/json.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"422":{"description":"Schema ferme : champ inconnu, ou contrainte violee. `errors[].code` nomme la regle, et la liste est celle du runtime, par construction : `body_not_object`, `unknown_field`, `required_non_empty_string`, `too_long`, `contains_control_character`, `must_be_incoming_or_outgoing`, `must_be_rfc3339_with_offset`, `must_be_object`, `must_be_string`, `must_be_boolean`, `must_be_four_digits`, `must_be_iso_3166_1_alpha_2_uppercase`, `malformed_iban`, `malformed_bic`, `must_be_non_empty_string`, `amount_not_object`, `amount_value_not_string`, `amount_value_malformed`, `amount_currency_not_string`, `amount_currency_malformed`, `amount_currency_unknown`, `amount_precision_exceeds_currency`. ★ `must_be_rfc3339_with_offset` couvre la FORME et le CALENDRIER : `2026-02-30T00:00:00Z`, `+16:00` ou `23:59:60` sont refuses. `must_be_object` refuse aussi un TABLEAU, pour les quatre familles. `contains_control_character` : un caractere de controle (C0, DEL, C1) dans un texte, tabulation, saut de ligne et retour chariot exceptes. `amount_currency_unknown` est rendu sous le type `unknown_currency`, les autres sous `invalid_input`.","headers":{"noryo-ratelimit-limit":{"schema":{"type":"integer"},"description":"La capacite de rafale de VOTRE CLEF (120 en `debit_ti_v1`)."},"noryo-ratelimit-remaining":{"schema":{"type":"integer"},"description":"Ce que votre clef peut encore envoyer MAINTENANT : le plus petit des deux soldes, celui de la clef et celui du workspace (toutes clefs confondues)."}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"`rate_limited` : la limite operationnelle de debit est atteinte, pour cette clef ou pour le workspace (le `detail` le dit). Rien n'a ete calcule, rien n'a ete range, aucun evenement n'a ete emis. Rejouez apres `Retry-After`. Voir `x-noryo-rate-limit`.","headers":{"Retry-After":{"schema":{"type":"integer","minimum":1},"description":"Secondes entieres avant que le seau qui a refuse couvre une requete."},"noryo-ratelimit-limit":{"schema":{"type":"integer"},"description":"La capacite de rafale de VOTRE CLEF (120 en `debit_ti_v1`)."},"noryo-ratelimit-remaining":{"schema":{"type":"integer"},"description":"Ce que votre clef peut encore envoyer MAINTENANT : le plus petit des deux soldes, celui de la clef et celui du workspace (toutes clefs confondues)."}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Erreur interne.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/transactions/v1/enrichments/{enrichment_id}":{"get":{"operationId":"getEnrichment","summary":"Relire un enrichissement rendu.","parameters":[{"name":"enrichment_id","in":"path","required":true,"schema":{"type":"string","pattern":"^enr_[0-9a-f-]{36}$"}}],"responses":{"200":{"description":"Trouve.","headers":{"noryo-request-id":{"schema":{"type":"string"},"description":"L'identifiant de cette requete, le meme que `request_id` dans un probleme."},"noryo-ratelimit-limit":{"schema":{"type":"integer"},"description":"La capacite de rafale de VOTRE CLEF (120 en `debit_ti_v1`)."},"noryo-ratelimit-remaining":{"schema":{"type":"integer"},"description":"Ce que votre clef peut encore envoyer MAINTENANT : le plus petit des deux soldes, celui de la clef et celui du workspace (toutes clefs confondues)."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoredEnrichment"}}}},"400":{"description":"Hote non declare. Jamais rendu pour la forme de l'identifiant.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Credential inutilisable.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Workspace ou organisation inactif.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"MALFORME, inconnu, EXPIRE, ou appartenant a un autre workspace — les quatre cas rendent la meme reponse. Rendre 400 sur un identifiant malforme dirait qu'un `enr_<uuid>` bien forme « a la bonne tete » : c'est un oracle de forme, et il est ferme.","headers":{"noryo-ratelimit-limit":{"schema":{"type":"integer"},"description":"La capacite de rafale de VOTRE CLEF (120 en `debit_ti_v1`)."},"noryo-ratelimit-remaining":{"schema":{"type":"integer"},"description":"Ce que votre clef peut encore envoyer MAINTENANT : le plus petit des deux soldes, celui de la clef et celui du workspace (toutes clefs confondues)."}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"429":{"description":"`rate_limited` : la limite operationnelle de debit est atteinte, pour cette clef ou pour le workspace (le `detail` le dit). Rien n'a ete calcule, rien n'a ete range, aucun evenement n'a ete emis. Rejouez apres `Retry-After`. Voir `x-noryo-rate-limit`.","headers":{"Retry-After":{"schema":{"type":"integer","minimum":1},"description":"Secondes entieres avant que le seau qui a refuse couvre une requete."},"noryo-ratelimit-limit":{"schema":{"type":"integer"},"description":"La capacite de rafale de VOTRE CLEF (120 en `debit_ti_v1`)."},"noryo-ratelimit-remaining":{"schema":{"type":"integer"},"description":"Ce que votre clef peut encore envoyer MAINTENANT : le plus petit des deux soldes, celui de la clef et celui du workspace (toutes clefs confondues)."}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Erreur interne.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}}},"components":{"x-noryo-score-classes":{"declared_constant":{"label":"constante declaree","meaning":"Une valeur POSEE par la personne qui a ecrit le motif ou la regle, lue telle quelle. Elle ne resulte d'aucun calcul sur la transaction : toute transaction qui touche le meme motif recoit le meme nombre. Mesure sur 644 libelles : la precision n'est PAS monotone en ce nombre (0,85 -> 0,86 ; 0,88 -> 0,33 ; 0,92 -> 0,25 ; 0,97 -> 0,79).","monotonic":false,"use":"Ne l'utilisez ni comme seuil ni comme rang. Utilisez `policy.outcome`."},"evidence_ratio":{"label":"part des signaux corroborants","meaning":"`present / possible` : combien de signaux corroborants ce TYPE sait produire, et combien sont effectivement la. Le denominateur DEPEND du type — 5 pour `refund_of`, 4 pour `reversal_of`, 2 pour `transfer_pair`, 5 criteres heterogenes pour une serie — et `corroborations` le rend a cote, parce que sans lui le nombre ne se lit pas.","monotonic":"within_type","use":"Comparable entre deux objets du MEME type et de la meme `detector_version`. Jamais entre un `refund_of` et un `transfer_pair`, jamais entre une relation et une serie."},"calendar_fill":{"label":"taux de remplissage calendaire","meaning":"La part des periodes calendaires de l'etendue observee qui portent au moins une occurrence, pour l'hypothese de cadence retenue. ★ `0` signifie « aucune hypothese calendaire n'a ete retenue » (cadence `irregular_recurring`), pas « faible ».","monotonic":"within_cadence","use":"Comparable entre deux series de MEME cadence. Une hebdomadaire sur 8 semaines et une annuelle sur 2 ans ne se comparent pas."},"anchor_stability":{"label":"stabilite de l'ancrage","meaning":"Un jeu de constantes par TYPE d'ancrage (1,0 pour un jour fixe de semaine, 0,9 pour un jour ajuste au jour ouvre) et deux formules lineaires sur l'etendue des jours pour `fixed_day_of_month` et `flexible_calendar_window`. `0` pour `unknown`. ★ `flexible_calendar_window` a DEUX regles selon la cadence : une constante 0,3 sans `day_range` en cadence `weekly`/`biweekly`, et `1 - etendue/10` (plancher 0,1) avec `day_range` en cadence mensuelle ou plus longue.","monotonic":"within_anchor_type_and_cadence","use":"Comparable entre deux series de MEME type d'ancrage ET de MEME cadence. Un 0,33 `fixed_day_of_month` et un 0,3 `flexible_calendar_window` ne disent pas la meme chose ; un 0,3 `flexible_calendar_window` hebdomadaire et un 0,3 mensuel non plus."},"authority_tiebreak":{"label":"departage a autorite egale","meaning":"La confiance declaree de la source d'une activite. Elle n'entre en jeu qu'APRES la nature d'autorite (`curated` > `deterministic` > `provider` > `inferred` > `participant`), pour departager deux sources de meme nature.","monotonic":"within_nature","use":"Ne compare jamais deux natures : un 0,95 `inferred` ne l'emporte pas sur un 0,90 `curated`."},"text_coverage":{"label":"couverture textuelle","meaning":"Un rapport de longueurs : la part du libelle utile que le motif apparie couvre, ou la part d'un motif compact qu'un fragment tronque recouvre. C'est une propriete du TEXTE, pas une preuve d'identite : un seuil dessus couterait 61 justes pour ecarter 17 faux.","monotonic":true,"use":"Comparable entre libelles. N'en faites pas un seuil d'identite."}},"securitySchemes":{"txnApiKey":{"type":"http","scheme":"bearer","description":"★★★ Une credential de la famille `txn` : `nry_txn_sbx_<key_id>.<secret>` en Sandbox, `nry_txn_live_<key_id>.<secret>` en Production. Une clef `nry_mer_*` est REFUSEE ici, et reciproquement : les familles sont isolees par le domaine du verificateur, pas seulement par un filtre."}},"schemas":{"Problem":{"type":"object","required":["type","title","status"],"properties":{"type":{"type":"string","format":"uri","enum":["https://noryo.app/problems/transactions/account_inactive","https://noryo.app/problems/transactions/engine_unavailable","https://noryo.app/problems/transactions/idempotency_conflict","https://noryo.app/problems/transactions/internal_error","https://noryo.app/problems/transactions/invalid_api_key","https://noryo.app/problems/transactions/invalid_idempotency_key","https://noryo.app/problems/transactions/invalid_input","https://noryo.app/problems/transactions/invalid_request","https://noryo.app/problems/transactions/malformed_body","https://noryo.app/problems/transactions/not_found","https://noryo.app/problems/transactions/rate_limited","https://noryo.app/problems/transactions/request_entity_too_large","https://noryo.app/problems/transactions/unknown_currency","https://noryo.app/problems/transactions/unsupported_media_type"]},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"errors":{"type":"array","items":{"type":"object","required":["field","code"],"properties":{"field":{"type":"string"},"code":{"type":"string"}}}},"request_id":{"type":"string","description":"★ Present sur TOUTE erreur RENDUE PAR L'API : c'est ce que vous donnez au support. Il est aussi dans l'en-tete `noryo-request-id` des reponses de succes. ★ Deux reponses viennent de l'HEBERGEUR, avant l'API, et ne sont pas des Problem : un verbe non declare sur un chemin declare rend `405` avec un corps vide et sans en-tete `Allow` ; un chemin inconnu rend `404`. Ni l'un ni l'autre ne porte `request_id`. Mesure au bord public ; documente plutot que masque."}}},"Money":{"type":"object","required":["value","currency"],"additionalProperties":false,"properties":{"value":{"type":"string","pattern":"^-?(0|[1-9][0-9]{0,15})(\\.[0-9]{1,4})?$","description":"Decimal en CHAINE. Un flottant perdrait des centimes en silence. ★ Le nombre de decimales admis DEPEND de la devise : `5.905 EUR` est refuse, `100.50 ISK` aussi (ISK et JPY n'en ont aucune, KWD en a trois)."},"currency":{"type":"string","enum":["CAD","CHF","DKK","EUR","GBP","ISK","JPY","KWD","NOK","PLN","SEK","USD"],"description":"★ Une devise hors de cette liste est refusee 422 `unknown_currency`."}}},"TransactionInput":{"type":"object","required":["descriptor","direction"],"additionalProperties":false,"description":"★ Schema FERME : un champ inconnu est refuse (422), jamais ignore.","properties":{"descriptor":{"type":"string","minLength":1,"maxLength":512},"direction":{"type":"string","enum":["incoming","outgoing"]},"occurred_at":{"type":"string","format":"date-time","description":"RFC 3339 AVEC decalage. Jamais reduit a une date : minuit n'est pas le meme jour partout."},"amount":{"$ref":"#/components/schemas/Money"},"payment":{"type":"object","additionalProperties":false,"properties":{"rail":{"type":"string","maxLength":128},"mcc":{"type":"string","pattern":"^[0-9]{4}$"},"card_present":{"type":"boolean"},"network_merchant_id":{"type":"string","maxLength":128},"raw_type":{"type":"string","maxLength":128}}},"location_hint":{"type":"object","additionalProperties":false,"properties":{"country":{"type":"string","pattern":"^[A-Z]{2}$"},"city":{"type":"string","maxLength":128},"postal_code":{"type":"string","maxLength":128}}},"counterparty_hint":{"type":"object","additionalProperties":false,"description":"★★★ L'IBAN est REDUIT des l'entree a son pays et son code banque. Le numero de compte n'entre pas dans le systeme, donc ne peut pas en sortir.","properties":{"iban":{"type":"string","pattern":"^[A-Z]{2}[0-9]{2}[A-Z0-9]{10,30}$"},"bic":{"type":"string","pattern":"^[A-Z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$"}}},"account_hint":{"type":"object","additionalProperties":false,"description":"Le compte SUR LEQUEL la transaction est passee — a distinguer de `counterparty_hint`, qui designe l'autre bout. Sans lui, une paire de virement ne peut pas etre identifiee : le seul signal qui la designe est « mon compte est ta contrepartie, et ta contrepartie est mon compte ». ★★★ L'IBAN est REDUIT des l'entree, comme celui de la contrepartie : le numero de compte n'entre pas dans le systeme. ★★★ `external_account_id` : votre propre identifiant du compte, pour les cartes, portefeuilles et rails sans IBAN. Il sert a UNE chose : relier la transaction a une couverture declaree sur le meme compte. Il n'entre pas dans l'empreinte. Mesure : il etait accepte, puis JETE — la serie n'avait aucune source, et `lifecycle.state` restait `unknown`.","properties":{"iban":{"type":"string","pattern":"^[A-Z]{2}[0-9]{2}[A-Z0-9]{10,30}$"},"external_account_id":{"type":"string","minLength":1,"maxLength":128}}},"external_transaction_id":{"type":"string","minLength":1,"maxLength":128,"description":"Votre propre identifiant de transaction. Il N'ENTRE PAS dans l'empreinte : il dit comment vous nommez la transaction, pas ce qu'elle est. Il sert a empecher deux envois d'UNE MEME transaction de se rapprocher l'un de l'autre."}}},"Relationship":{"type":"object","required":["type","role","symmetric","counterpart","match_strength","evidence","detector_version","status"],"description":"Un lien economique entre DEUX transactions du meme workspace. ★★★ Il ne quitte jamais ce workspace et n'alimente jamais le graphe d'entites : une relation entre deux transactions privees n'est pas une verite globale.","properties":{"type":{"type":"string","enum":["refund_of","reversal_of","transfer_pair"],"description":"`refund_of` : l'achat a eu lieu, puis l'argent est revenu — les deux ecritures subsistent. `reversal_of` : l'ecriture d'origine est effacee, il ne s'est rien passe. `transfer_pair` : deux jambes d'un seul mouvement."},"role":{"type":"string","enum":["source","target","peer"],"description":"Le role de CETTE transaction. `peer` pour une relation symetrique, ou ni source ni cible ne veut rien dire."},"symmetric":{"type":"boolean"},"counterpart":{"type":"string","pattern":"^enr_[0-9a-f-]{36}$","description":"L'autre transaction, par son identifiant d'enrichissement."},"match_strength":{"type":"object","required":["value","calibration","corroborations"],"description":"★★★ CE N'EST PAS UNE PROBABILITE. C'est la part des signaux corroborants disponibles pour ce type qui sont effectivement presents. `calibration` vaut `non_calibree` tant qu'aucune verite terrain n'a certifie une lecture chiffree de ce nombre.","properties":{"value":{"type":"number","minimum":0.001,"maximum":1,"x-noryo-score":{"class":"evidence_ratio","calibration":"non_calibree","is_probability":false,"formula":"present / possible, arrondi a 3 decimales, plancher 0.001 ; present <= possible par construction","comparable_within":"relations du meme `type` et de la meme `detector_version`","not_comparable_with":["relations d'un autre type","series[].match_strength"]},"description":"★★★ LE DENOMINATEUR DEPEND DU TYPE : 5 pour `refund_of`, 4 pour `reversal_of`, 2 pour `transfer_pair`. Un `0.5` de paire de virement (1/2) et un `0.5` de contre-passation (2/4) ne sont pas la meme force. Lisez `corroborations` a cote. ★ `present` ne compte que les signaux de l'ensemble PROPRE au type : un marqueur de remboursement sur une paire de virement reste visible dans `evidence` mais ne corrobore pas."},"calibration":{"type":"string","enum":["non_calibree"],"description":"★★★ TOUJOURS `non_calibree` dans cette version, et c'est une CONTRAINTE, pas une convention : la valeur est un vocabulaire en base, les colonnes qui la portent y font reference, et une garde refuse tout litteral hors vocabulaire chez chaque producteur. Le jour ou une calibration reelle existe, elle entrera par une migration declaree, avec le corpus qui la defend."},"corroborations":{"type":"object","required":["present","possible"],"properties":{"present":{"type":"integer","minimum":0},"possible":{"type":"integer","minimum":1}}}}},"evidence":{"type":"array","description":"Les signaux qui fondent la relation, y compris les preconditions. Une relation qui ne peut pas dire POURQUOI elle existe n'est pas creee.","items":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"value":{"type":"string"},"value_seconds":{"type":"integer","description":"Pour `within_window` : l'ecart mesure, en secondes. Une duree, pas une confiance."}}}},"window_seconds":{"type":["integer","null"],"description":"La fenetre du type de relation, en secondes. Une constante de politique, pas une mesure."},"detector_version":{"type":"string"},"status":{"type":"string","enum":["active","supersedee","invalidee"]},"created_at":{"type":"string","format":"date-time"}}},"CounterpartySemantics":{"type":["object","null"],"description":"★★★ QUATRE CHOSES DIFFERENTES QUI SE RESSEMBLENT, ET QUE CE BLOC REFUSE DE CONFONDRE. Le TYPE D'ENTITE (`counterparty.kind` : marque, entite legale, intermediaire de paiement) dit CE QUE C'EST. L'ACTIVITE (`activity`) dit CE QUE CA FAIT, en noms d'industrie. La CATEGORIE (`category`, hors de cet objet) dit A QUOI l'argent est alle, en lignes de budget. Le TYPE DE TRANSACTION (`transaction_type`) dit ce qui s'est passe. Aucun ne se deduit d'un autre. ★★★ ET IL N'EXISTE AUCUN `category = subscription` : un abonnement n'est pas une sorte de depense, c'est un MODELE de relation commerciale. ★ `null` quand le graphe ne sait rien de cette entite — une abstention, pas une panne.","properties":{"activity":{"type":["object","null"],"description":"Le metier, sur deux niveaux (`parent` puis `code`). ★ On s'arrete au parent quand la source s'y arrete : un role `utility` dit « reseau » sans dire lequel, et on rend alors `utilities`, jamais `utilities.electricity`. Ce qui n'est pas su ne se complete pas.","properties":{"code":{"type":"string"},"label":{"type":"string"},"parent":{"type":["string","null"]}}},"recurring_model":{"type":["string","null"],"enum":["commonly_subscription_based","commonly_recurring_but_not_subscription","usually_one_off","both_recurring_and_one_off","unknown",null],"description":"★★★ CE QUI EST HABITUEL DANS CE METIER — PAS UN VERDICT SUR CETTE TRANSACTION. Un service de streaming se vend par abonnement ; un fournisseur d'electricite facture de facon repetee SANS qu'on s'abonne ; un supermarche vend a l'acte. C'est une PLAUSIBILITE qui renforce un rythme DEJA OBSERVE dans le workspace. Seul, il ne conclut jamais : `commonly_subscription_based` sur une transaction isolee ne fait pas un abonnement, et c'est la serie (`series[].type = subscription`) qui tranche."},"roles":{"type":"array","items":{"type":"string"},"description":"Les roles portes par l'entite dans le graphe (`merchant`, `utility`, `government`, `financial_institution`, `payment_intermediary`…). ★ Un role n'est pas un metier, mais il en dit assez pour en deriver un quand aucun catalogue ne couvre l'entite."},"legal_entity":{"type":["object","null"],"description":"★★★ UNE MARQUE N'EST PAS UNE ENTITE LEGALE. « Netflix » est ce qu'on lit sur le releve ; « Netflix Inc » est ce qui contracte. Les deux existent separement dans le graphe, relies par `brand_of`, parce que les fusionner ferait disparaitre le jour ou une marque change de proprietaire. ★ `null` quand aucune societe mere n'est connue — pas quand il n'y en a pas.","properties":{"entity_id":{"type":"string","format":"uuid","description":"Le meme espace d'identifiants que `counterparty.entity_id` : UUID nu, opaque, stable."},"name":{"type":"string"}}},"provenance":{"type":["object","null"],"description":"★★★ D'OU VIENT CE QU'ON AFFIRME. `nature` classe la connaissance par AUTORITE DECLAREE, dans cet ordre : `curated` (une personne l'a verifie), `deterministic` (derive mecaniquement d'un fait deja tenu), `provider` (un tiers l'annonce), `inferred` (nous l'avons deduit), `participant` (un seul client l'a dit). ★★★ CET ORDRE EST DECLARE, PAS DEDUIT D'UN NOMBRE : sans lui, un 0,95 deduit l'emporterait sur un 0,90 verifie. `strength` ne departage qu'a nature EGALE, et n'est pas calibree. ★★★ ET AUCUNE CONNAISSANCE GLOBALE NE VIENT D'UN SEUL CLIENT : ce qu'un workspace observe reste dans ce workspace. Une nature `participant` ne peut jamais devenir une verite du graphe partage.","properties":{"nature":{"type":"string","enum":["curated","deterministic","provider","inferred","participant"]},"source":{"type":"string"},"strength":{"type":"number","minimum":0,"maximum":1,"x-noryo-score":{"class":"authority_tiebreak","calibration":"non_calibree","is_probability":false,"comparable_within":"sources de la MEME `nature`","not_comparable_with":["une autre nature d'autorite","tout autre score de l'API"]}},"calibration":{"type":"string","enum":["non_calibree"],"description":"★★★ TOUJOURS `non_calibree` dans cette version, et c'est une CONTRAINTE, pas une convention : la valeur est un vocabulaire en base, les colonnes qui la portent y font reference, et une garde refuse tout litteral hors vocabulaire chez chaque producteur. Le jour ou une calibration reelle existe, elle entrera par une migration declaree, avec le corpus qui la defend."},"evidence":{"type":"object","x-noryo-opaque":"un objet explicatif dont les clefs dependent de la derivation ; jamais un score","description":"Comment la provenance a ete etablie. Les clefs varient : `derivation` (`categorie_de_depense_vers_activite`, `role_vers_activite`…), `categorie_source` ou `role`, et `note`, une phrase constante en francais. Aucune de ces valeurs n'est un nombre."}}}}},"CoverageWindowResult":{"type":"object","required":["covered_from","covered_to","completeness","provenance","merged_intervals","policy_version","request_id"],"description":"Ce que la declaration est devenue une fois enregistree. ★ `merged_intervals` compte les intervalles PREEXISTANTS que cette declaration a absorbes : `0` quand elle est seule, `1` sur un rejeu exact (elle a absorbe sa propre copie), `1` ou plus quand elle touche ou chevauche des declarations anterieures. `covered_from` / `covered_to` sont les bornes APRES fusion. Mesure au bord public : une premiere version de ce document disait « 1 si elle est seule » — le moteur avait raison, la doc non.","properties":{"covered_from":{"type":"string","format":"date"},"covered_to":{"type":"string","format":"date"},"completeness":{"type":"string","enum":["complete","partial","unknown"]},"provenance":{"type":"string","enum":["caller_asserted"],"description":"★ Toujours `caller_asserted` : nous enregistrons ce que vous affirmez, nous ne le verifions pas, et vous ne pouvez pas declarer autre chose."},"merged_intervals":{"type":"integer","minimum":0},"policy_version":{"type":"string"},"note":{"type":"string"},"request_id":{"type":"string"}}},"CoverageWindow":{"type":"object","required":["account_hint","covered_from","covered_to"],"additionalProperties":false,"description":"★ Schema FERME : un champ inconnu est refuse (422). En particulier `provenance` n'est PAS un champ d'entree.","properties":{"account_hint":{"type":"object","additionalProperties":false,"minProperties":1,"description":"Le compte concerne. `iban` quand il en a un, sinon `external_account_id` — votre propre identifiant, pour les cartes, portefeuilles et rails non-SEPA. Au moins l'un des deux. ★ Aucun des deux n'est conserve : nous n'en gardons qu'une empreinte opaque, portee a votre workspace — la MEME que celle de l'enrichissement, sans quoi la couverture ne croiserait jamais la serie qu'elle qualifie.","properties":{"iban":{"type":"string","pattern":"^[A-Z]{2}[0-9]{2}[A-Z0-9]{10,30}$"},"external_account_id":{"type":"string","minLength":1,"maxLength":128}}},"covered_from":{"type":"string","format":"date"},"covered_to":{"type":"string","format":"date","description":"★ On ne certifie pas ce qui n'a pas encore eu lieu : une date future est refusee."},"completeness":{"type":"string","enum":["complete","partial","unknown"],"default":"complete","description":"★★★ `complete` SIGNIFIE QUELQUE CHOSE DE PRECIS : vous affirmez que TOUTES les operations de ce compte sur cet intervalle nous ont ete fournies. C'est la seule valeur qui nous autorise a conclure d'une ABSENCE. `partial` et `unknown` n'y autorisent pas — dix appels en octobre peuvent etre dix operations sur cent."}}},"CalendarPattern":{"type":"object","description":"★★★ OU, DANS CHAQUE PERIODE, LA SERIE TEND A TOMBER — une question DIFFERENTE de `cadence`. Une serie peut etre franchement mensuelle en flottant entre le 1er et le 6 : sans ce champ, « monthly » se lirait comme « le meme jour chaque mois », ce qui est faux pour la majorite des series reelles. ★ C'est aussi ce qui donne sa largeur a `expected_next_window` : un prelevement toujours au 5 justifie trois jours, un loyer qui flotte en justifie huit. Appliquer la meme fenetre aux deux ferait declarer « en retard » une serie parfaitement normale.","properties":{"type":{"type":"string","enum":["fixed_day_of_month","month_end","last_business_day","business_day_adjusted","fixed_weekday","flexible_calendar_window","unknown"],"description":"`fixed_day_of_month` : toujours autour du meme jour. `month_end` : en fin de mois, quel que soit le nombre de jours — un prelevement du 31 janvier, 28 fevrier, 31 mars est un seul motif. `last_business_day` : le dernier jour ouvre, cas frequent des salaires. `business_day_adjusted` : un jour nominal deplace hors du week-end (samedi → vendredi, dimanche → lundi). ★ Nous NE modelisons PAS les jours feries : ni francais, ni TARGET, ni bancaires. Un report de ferie est absorbe par la tolerance de la fenetre, pas reconnu — pretendre connaitre un calendrier que nous n'avons pas serait pire que de l'ignorer. `fixed_weekday` : toujours le meme jour de la semaine. `flexible_calendar_window` : une occurrence par periode, sans jour stable. `unknown` : rien d'identifiable."},"nominal_day":{"type":["integer","null"]},"weekday":{"type":["integer","null"]},"day_range":{"type":["array","null"],"items":{"type":"integer"}},"weekend_shifts":{"type":["integer","null"]},"strength":{"type":"number","minimum":0,"maximum":1,"x-noryo-score":{"class":"anchor_stability","calibration":"non_calibree","is_probability":false,"comparable_within":"series du MEME `type` d'ancrage et de la MEME cadence","not_comparable_with":["un autre type d'ancrage","une autre cadence","cadence_detail.strength","match_strength"]},"description":"★ Une constante par type d'ancrage, ou une formule lineaire sur l'etendue des jours pour `fixed_day_of_month` et `flexible_calendar_window`. `0` pour `unknown`. Un 0,33 `fixed_day_of_month` et un 0,3 `flexible_calendar_window` ne se comparent pas — et `flexible_calendar_window` change de regle avec la cadence (constante 0,3 en hebdomadaire, `1 - etendue/10` en mensuel)."},"calibration":{"type":"string","enum":["non_calibree"],"description":"★★★ TOUJOURS `non_calibree` dans cette version, et c'est une CONTRAINTE, pas une convention : la valeur est un vocabulaire en base, les colonnes qui la portent y font reference, et une garde refuse tout litteral hors vocabulaire chez chaque producteur. Le jour ou une calibration reelle existe, elle entrera par une migration declaree, avec le corpus qui la defend."}}},"SeriesLifecycle":{"type":"object","required":["state","policy_version","calibration"],"description":"★★★ UN AXE DIFFERENT DE `status`. `status` dit A QUEL POINT nous croyons que c'est une serie ; `lifecycle` dit CE QUI LUI ARRIVE MAINTENANT. Une serie tres bien etablie peut avoir cesse de prelever, et une serie fraiche peut etre parfaitement vivante. ★★★ ET AUCUN ETAT NE SE CONCLUT D'UNE ABSENCE SANS COUVERTURE : si la source n'etait pas observee de facon complete sur la fenetre attendue, l'etat est `unknown`, pas `late`. « Je n'ai rien vu » ne devient jamais « il n'y a rien eu » — c'est la difference entre un client qui a cesse d'envoyer et un abonnement qui a cesse de prelever.","properties":{"state":{"type":"string","enum":["active","late","inactive","ended","unknown"],"description":"`active` : l'echeance attendue est arrivee, ou n'est pas encore echue. `late` : une echeance manque ET le compte etait observe. `inactive` : plusieurs echeances consecutives manquent sous observation complete — la serie ne preleve plus, sans que nous sachions POURQUOI. ★★★ `ended` : reserve a une preuve terminale explicite. Aucune accumulation d'absences ne produit cet etat : un prelevement qui s'arrete peut etre une resiliation, une suspension, une carte expiree ou un echec de prelevement, et nous ne devinons pas laquelle. `unknown` : nous ne pouvons pas conclure, et `reason` dit pourquoi."},"reason":{"type":"string"},"last_observed_on":{"type":["string","null"],"format":"date"},"expected_next_window":{"type":["object","null"],"description":"★★★ UNE FENETRE, PAS UNE DATE. Un salaire tombe vers les derniers jours ouvres, un prelevement SEPA vers le 5. Rendre un instant exact serait une precision que nous n'avons pas, et vous la croiriez.","properties":{"from":{"type":"string","format":"date"},"to":{"type":"string","format":"date"},"tolerance_days":{"type":"integer","description":"La demi-largeur de la fenetre, en jours. Plus grand = moins precis. Vient du type d'ancrage, releve au plancher de la famille de serie."},"anchor":{"type":"string","description":"Le type d'ancrage qui a donne la fenetre."},"widened_to_family_floor":{"type":"boolean","description":"`true` si la tolerance a ete relevee au plancher de la famille (5 jours pour un abonnement, 6 pour un salaire, 7 sinon)."}}},"consecutive_misses":{"type":["integer","null"],"description":"★ Le compteur n'avance QUE sous couverture complete. Absent quand rien n'est attendu — ce qui n'est pas la meme ignorance que « nous ne regardions pas »."},"observation_coverage":{"type":"string","enum":["not_required","complete","incomplete","unknown"],"description":"`not_required` : aucune echeance close, rien n'avait a etre observe. `complete` : chaque source de la serie etait couverte sur la fenetre attendue — un manque est un manque. `incomplete` : au moins une source ne l'etait pas — l'absence ne prouve rien, `state` est `unknown`. `unknown` : les sources sont inconnues ou trop nombreuses pour etre verifiees."},"cadence_strength":{"type":["number","null"],"x-noryo-score":{"class":"calendar_fill","calibration":"non_calibree","is_probability":false,"duplicate_of":"series[].cadence_detail.strength"},"description":"★ Le MEME nombre que `cadence_detail.strength`, rendu ici pour que le cycle de vie soit lisible seul. Ce n'est pas un second score."},"calendar_anchor":{"anyOf":[{"$ref":"#/components/schemas/CalendarPattern"},{"type":"null"}],"description":"★ Le MEME objet que `calendar_pattern` (classe `anchor_stability`), rendu ici pour la meme raison ; `{ type: unknown }` quand aucun ancrage n'a ete infere. Absent quand aucune echeance n'est attendue. duplicate_of : `series[].calendar_pattern` — ce n'est pas un second score."},"evidence":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"}}},"description":"Present pour `ended` : la preuve terminale qui l'a produit."},"identity_status":{"type":["string","null"],"enum":["superseded",null],"description":"★ Present UNIQUEMENT quand l'identite de la serie a ete corrigee, pour dire POURQUOI `state` vaut `unknown` : ce n'est pas une ignorance economique, c'est que le verdict appartient desormais aux successeurs. L'etat d'identite complet se lit dans `identity`, qui est un axe a part entiere ; ce champ n'est qu'un renvoi, et il ne prend jamais la valeur `current`."},"policy_version":{"type":"string"},"calibration":{"type":"string","enum":["non_calibree"],"description":"★★★ TOUJOURS `non_calibree` dans cette version, et c'est une CONTRAINTE, pas une convention : la valeur est un vocabulaire en base, les colonnes qui la portent y font reference, et une garde refuse tout litteral hors vocabulaire chez chaque producteur. Le jour ou une calibration reelle existe, elle entrera par une migration declaree, avec le corpus qui la defend."}}},"SeriesMembership":{"type":"object","required":["current_series_id","corrections"],"description":"★★★ D'OU VIENT CETTE OCCURRENCE, ET OU EST-ELLE MAINTENANT. Quand une identite est corrigee, l'occurrence change de serie : sans ce bloc, vous n'auriez aucun moyen de relier le `series_id` que vous aviez stocke a celui que vous recevez. ★ Vous n'avez jamais a reconstruire le graphe vous-meme.","properties":{"original_series_id":{"type":["string","null"],"pattern":"^ser_[0-9a-f-]{36}$","description":"La serie a laquelle cette occurrence a ete rattachee la PREMIERE fois. Egale a `current_series_id` tant qu'aucune correction n'a eu lieu."},"current_series_id":{"type":["string","null"],"pattern":"^ser_[0-9a-f-]{36}$"},"corrections":{"type":"array","description":"Les deplacements successifs, du plus ancien au plus recent. Vide pour une occurrence qui n'a jamais bouge.","items":{"type":"object","additionalProperties":false,"properties":{"reason":{"type":"string","enum":["split","merge"]},"from_series_id":{"type":["string","null"],"pattern":"^ser_[0-9a-f-]{36}$"},"to_series_id":{"type":["string","null"],"pattern":"^ser_[0-9a-f-]{36}$"},"at":{"type":"string","format":"date-time"}}}}}},"SeriesIdentity":{"type":"object","required":["status","supersedes"],"description":"★★★ UN TROISIEME AXE, ET IL NE SE MELANGE NI A `status` NI A `lifecycle`. `status` dit a quel point nous croyons que c'est une serie ; `lifecycle` dit ce qui lui arrive economiquement ; `identity` dit si son NOM est toujours le bon. Une serie peut prelever tous les mois et avoir change d'identite parce que nous avons compris qu'elle etait en realite deux flux, ou deux moities d'un seul. ★★★ ET UN `series_id` N'EST JAMAIS REECRIT NI REUTILISE EN SILENCE. Quand nous corrigeons, l'ancien nom subsiste, marque `superseded`, et il porte ses successeurs.","properties":{"status":{"type":"string","enum":["current","superseded"],"description":"`current` : ce nom est le nom courant de ce flux. `superseded` : ce nom a ete remplace par une correction d'identite. Il reste valide comme reference historique — il ne disparaitra pas — mais les occurrences futures porteront le nom de ses successeurs."},"superseded_by":{"type":["object","null"],"description":"★★★ APRES UNE SCISSION IL N'Y A PAS DE REDIRECTION UNIQUE, et c'est pourquoi ce champ rend une LISTE. Si nous decouvrons qu'une serie melangeait deux flux, aucun des deux successeurs n'est « la suite » de l'ancien : la moitie des occurrences de l'ancien n'est pas dans l'un d'eux. Elire un canonique serait confortable et faux.","properties":{"reason":{"type":"string","enum":["split","merge"],"description":"`split` : cette identite en recouvrait plusieurs, et chacune a desormais la sienne. `merge` : cette identite et une autre etaient le meme flux ; toutes deux sont remplacees par une identite neuve."},"at":{"type":"string","format":"date-time"},"evidence":{"type":"array","items":{"type":"string"},"description":"★ Les codes de preuve qui ont autorise la correction. Jamais un score interne, jamais un identifiant de ligne."},"successor_series_ids":{"type":"array","items":{"type":"string","pattern":"^ser_[0-9a-f-]{36}$"},"description":"Un seul apres une fusion, plusieurs apres une scission. Jamais vide quand `status` vaut `superseded`."}}},"supersedes":{"type":"array","items":{"type":"string","pattern":"^ser_[0-9a-f-]{36}$"},"description":"★★★ LE CHEMIN DE RETOUR, et il compte autant que l'autre. Les identites que celle-ci remplace. Sans lui, l'ancien `series_id` que vous aviez stocke ne correspondrait plus a rien de ce que vous recevez, et vous n'auriez aucun moyen de faire le lien. Vide pour une serie qui n'est nee d'aucune correction."}}},"Series":{"type":"object","required":["series_id","type","status","cadence","occurrence_count","amount_behavior","match_strength","history_coverage"],"description":"Plusieurs occurrences economiquement liees dans le temps, dans CE workspace. ★★★ Une serie privee ne devient jamais une verite du graphe d'entites.","properties":{"series_id":{"type":"string","pattern":"^ser_[0-9a-f-]{36}$","description":"★★★ STABLE. Il se derive de ce qui ne change pas — workspace, famille, contrepartie, sens, devise — jamais de la derniere occurrence ni du libelle courant. Une occurrence de plus ne cree pas une autre serie."},"type":{"type":"string","enum":["recurring_payment","subscription","recurring_income","salary_series"],"description":"★★★ `recurring_payment` dit « ce paiement revient », et RIEN de plus : un loyer et une echeance de pret le sont aussi. `subscription` est une affirmation plus forte et exige son propre signal ; sans lui, la reponse reste `recurring_payment`. De meme `recurring_income` couvre pension, prestation et loyer percu — `salary_series` en est une specialisation, pas un synonyme."},"implies":{"type":"array","items":{"type":"string"},"description":"Le type plus general que celui-ci specialise, s'il existe."},"status":{"type":"string","enum":["emerging","established","uncertain","broken"],"description":"Deux occurrences font emerger, trois peuvent etablir, une seule jamais. `broken` se CALCULE au moment de la lecture : une serie devient en retard par le seul passage du temps, sans qu'aucune ecriture n'ait lieu."},"cadence":{"type":"string","enum":["weekly","biweekly","monthly","quarterly","yearly","irregular_recurring","unknown"],"description":"Lue au CALENDRIER, pas en jours secs : le 31 janvier et le 28 fevrier sont a un mois d'intervalle, et un salaire au dernier jour ouvre glisse."},"occurrence_count":{"type":"integer"},"amount_behavior":{"type":"object","description":"L'egalite exacte n'est pas exigee : une facture d'electricite varie, un salaire aussi. Montants en unites mineures, en CHAINE — jamais un nombre JSON.","properties":{"kind":{"type":"string","enum":["fixed","narrow_variable","broadly_variable"]},"min_minor_units":{"type":"string"},"max_minor_units":{"type":"string"},"currency":{"type":"string"}}},"first_seen":{"type":"string","format":"date-time"},"last_seen":{"type":"string","format":"date-time"},"expected_next_at":{"type":["string","null"],"format":"date-time","description":"★★★ FACULTATIVE, ET C'EST LE POINT. Absente tant que la serie n'est pas etablie ou que la cadence est irreguliere : rendre une date sur deux observations faibles la ferait passer pour une prevision. Ce n'est pas une API de prevision."},"match_strength":{"type":"object","required":["value","calibration","corroborations"],"description":"★★★ CE N'EST PAS UNE PROBABILITE : c'est la part des signaux corroborants presents sur ceux que ce type sait produire. ★★★ ET CE N'EST PAS LE MEME NOMBRE QUE `relationships[].match_strength` : meme nom, autre denominateur, autres signaux. Cinq criteres heterogenes sur cinq — cadence calendaire, montant fixe ou etroit, au moins trois occurrences, entite connue, type specialise. Ils ne s'additionnent qu'ici.","properties":{"value":{"type":"number","minimum":0.001,"maximum":1,"x-noryo-score":{"class":"evidence_ratio","calibration":"non_calibree","is_probability":false,"formula":"criteres presents / 5","comparable_within":"series de la meme `detector_version`","not_comparable_with":["relationships[].match_strength","cadence_detail.strength"]}},"calibration":{"type":"string","enum":["non_calibree"],"description":"★★★ TOUJOURS `non_calibree` dans cette version, et c'est une CONTRAINTE, pas une convention : la valeur est un vocabulaire en base, les colonnes qui la portent y font reference, et une garde refuse tout litteral hors vocabulaire chez chaque producteur. Le jour ou une calibration reelle existe, elle entrera par une migration declaree, avec le corpus qui la defend."},"corroborations":{"type":"object","required":["present","possible"],"properties":{"present":{"type":"integer"},"possible":{"type":"integer","enum":[5]}}}}},"evidence":{"type":"array","description":"Les signaux qui fondent la serie. `value` est une chaine ou un entier selon le code (`occurrences` porte un entier).","items":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"value":{"type":["string","integer","null"],"x-noryo-not-a-score":"valeur de preuve (ex. le nombre d'occurrences)"}}}},"lifecycle":{"$ref":"#/components/schemas/SeriesLifecycle"},"identity":{"$ref":"#/components/schemas/SeriesIdentity"},"membership":{"$ref":"#/components/schemas/SeriesMembership"},"first_observed_on":{"type":"string","format":"date","description":"★★★ LE PREMIER JOUR OU **NOUS** AVONS OBSERVE CETTE SERIE — pas le jour ou elle a commence. Une serie peut tourner depuis cinq ans alors que nous ne l'observons que depuis trois mois. Il n'existe volontairement AUCUN champ `started_at` : nous ne le savons pas."},"last_observed_on":{"type":"string","format":"date"},"may_predate_observation":{"type":"boolean","description":"★ `true` : notre observation commence avec la premiere occurrence connue, donc la serie a pu commencer avant nous et rien ne le montrera. `false` : la premiere occurrence connue est anterieure au debut de notre observation, donc son commencement est observe et non suppose."},"cadence_detail":{"type":"object","description":"★★★ A QUELLE FREQUENCE L'EVENEMENT SE REPETE — et rien d'autre. La cadence se deduit de la progression des PERIODES CALENDAIRES, pas des ecarts en jours : trois mois consecutifs sont trois mois consecutifs, que les ecarts vaillent 28, 30 ou 31. ★★★ ET UNE RECURRENCE DE 28 JOURS N'EST PAS MENSUELLE : elle tombe une fois par mois pendant onze mois puis deux, et son jour recule a chaque cycle. Nous ne l'appelons pas `monthly` — cette version n'a pas de cadence pour elle, et `irregular_recurring` vaut mieux qu'un faux mensuel. ★ `strength` est la part des cycles attendus qui portent une occurrence. Ce n'est pas une probabilite.","properties":{"type":{"type":"string"},"strength":{"type":["number","null"],"minimum":0,"maximum":1,"x-noryo-score":{"class":"calendar_fill","calibration":"non_calibree","is_probability":false,"formula":"cycles portant une occurrence / cycles de l'etendue","comparable_within":"series de la MEME cadence","not_comparable_with":["une autre cadence","match_strength","calendar_pattern.strength"]},"description":"★ `0` = aucune hypothese calendaire retenue, PAS « faible »."},"calibration":{"type":"string","enum":["non_calibree"],"description":"★★★ TOUJOURS `non_calibree` dans cette version, et c'est une CONTRAINTE, pas une convention : la valeur est un vocabulaire en base, les colonnes qui la portent y font reference, et une garde refuse tout litteral hors vocabulaire chez chaque producteur. Le jour ou une calibration reelle existe, elle entrera par une migration declaree, avec le corpus qui la defend."}}},"calendar_pattern":{"$ref":"#/components/schemas/CalendarPattern"},"history_coverage":{"type":"object","required":["retention_limit_days","occurrence_count","sufficiency"],"description":"★★★ CE QUE NOUS POUVONS VOIR, ET CE QUE NOUS NE POUVONS PAS. `insufficient` signifie « notre memoire est trop courte pour en juger », JAMAIS « il n'y a pas d'occurrence plus ancienne ». ★★★ ET IL Y A DEUX MEMOIRES, QU'IL NE FAUT PAS CONFONDRE. `raw_days` (30) dit combien de temps la TRANSACTION reste lisible ; `derived_days` (400) dit combien de temps ce que nous avons APPRIS d'une serie lui survit. Une transaction purgee reste purgee — cette API ne la ressuscite jamais — mais la serie se souvient qu'elle a eu lieu. C'est ce qui rend une cadence mensuelle confirmable alors que la transaction de janvier n'existe plus. ★ `observed_days` est ce que nous avons EFFECTIVEMENT vu : un client qui lit « monthly / sufficient » peut verifier que la conclusion ne sort pas de trente jours.","properties":{"observed_from":{"type":"string","format":"date"},"observed_to":{"type":"string","format":"date"},"raw_days":{"type":"integer","description":"Duree de vie de la TRANSACTION brute. Passe ce delai elle est physiquement supprimee et rien ne la rend."},"derived_days":{"type":"integer","description":"Duree de vie de la MEMOIRE de serie, comptee depuis la derniere occurrence. Sans nouvelle occurrence, l'etat derive est physiquement supprime a l'echeance et une occurrence ulterieure ouvre une serie neuve."},"observed_days":{"type":"integer","description":"Etendue reellement observee, de la premiere a la derniere occurrence connue."},"retention_limit_days":{"type":"integer","description":"Conserve pour compatibilite : identique a `raw_days`."},"occurrence_count":{"type":"integer"},"cadence":{"type":"string"},"sufficiency":{"type":"string","enum":["sufficient","limited","insufficient"],"description":"★ Repond a UNE seule question : peut-on croire la cadence ? Pas a « sait-on quand ca a commence », qui est le champ suivant."},"reason":{"type":"string"},"first_occurrence_reason":{"type":"string","description":"Dit POURQUOI `first_occurrence_bounded` vaut ce qu'il vaut."},"first_occurrence_bounded":{"type":"boolean","description":"★★★ UNE QUESTION DIFFERENTE DE `sufficiency`, ET QUI ETAIT CONFONDUE AVEC ELLE. `true` : notre observation de cette serie commence avec la premiere occurrence que nous connaissons — elle a donc pu commencer avant nous, et rien ne le montrera jamais. `false` : la premiere occurrence connue est anterieure au debut de notre observation, donc le commencement est observe et non suppose. Un import d'historique rend `false` ; une serie decouverte au fil de l'eau rend `true`."}}},"detector_version":{"type":"string"}}},"RelationshipsPolicy":{"type":"object","required":["detector_version","calibration","unresolved"],"description":"★★★ L'ABSTENTION EST UN RESULTAT, PAS UN SILENCE. « aucune relation » et « deux candidats egalement plausibles » sont deux choses differentes ; un client qui ne peut pas les distinguer conclura la premiere.","properties":{"detector_version":{"type":"string"},"calibration":{"type":"string","enum":["non_calibree"]},"unresolved":{"type":"array","description":"Chaque detecteur qui n'a PAS conclu dit pourquoi. Pour une relation : `candidates_at_least` (jamais le compte exact — il ferait un oracle sur les transactions des autres). Pour la serie (`type = series`) : `occurrences`, et une issue de serie. ★ Une relation CONCLUE n'y figure jamais : elle est dans `relationships`. Une version anterieure y rangeait a tort les issues `resolved` et `already_known`.","items":{"type":"object","required":["type","outcome"],"properties":{"type":{"type":"string"},"outcome":{"type":"string","enum":["ambiguous","single_occurrence","no_recurrence_interval","no_series_key","excluded_by_relation","ambiguous_membership"]},"candidates_at_least":{"type":"integer","minimum":1},"occurrences":{"type":"integer","minimum":0}}}}}},"Enrichment":{"type":"object","required":["enrichment_id","created_at","contract_version","canonical_version","fingerprint","signals","resolution"],"properties":{"enrichment_id":{"type":"string","pattern":"^enr_[0-9a-f-]{36}$"},"created_at":{"type":"string","format":"date-time"},"contract_version":{"type":"string"},"canonical_version":{"type":"string"},"fingerprint":{"type":"string"},"signals":{"type":"object","required":["used","ignored"],"properties":{"used":{"type":"array","items":{"type":"string"},"description":"Transmis au resolveur OU a la base (series, relations, couverture)."},"ignored":{"type":"array","items":{"type":"string"},"description":"Recus, et lus par personne. Aujourd'hui : `payment.mcc`, `payment.card_present`, `payment.network_merchant_id`, `location_hint.city`, `location_hint.postal_code`, `counterparty_hint.bic`."},"conflicting":{"type":"array","items":{"$ref":"#/components/schemas/SignalConflict"},"description":"Les signaux qui se contredisent — copie de `resolution.signal_conflicts`, rendue ici pour que `signals` soit complet."}}},"resolution":{"$ref":"#/components/schemas/Resolution"},"relationships":{"type":"array","items":{"$ref":"#/components/schemas/Relationship"}},"series":{"type":"array","items":{"$ref":"#/components/schemas/Series"}},"relationships_policy":{"$ref":"#/components/schemas/RelationshipsPolicy"},"customization":{"$ref":"#/components/schemas/Customization"}}},"Customization":{"type":"object","required":["rules"],"description":"★★★ PRESENT SEULEMENT QUAND UNE REGLE DE VOTRE ORGANISATION A CHANGE CETTE REPONSE (Platform, Regles). Le resultat Noryo reste conserve intact ; une regle ne vaut que pour votre organisation et l'environnement de la clef. ★ Un POST est rendu avec les regles publiees a cet instant (un rejeu idempotent rend le meme corps) ; un GET applique les regles publiees AUJOURD'HUI. Un champ sur lequel deux regles se contredisent garde la valeur Noryo.","properties":{"rules":{"type":"array","items":{"type":"object","required":["id","version","fields"],"properties":{"id":{"type":"string","format":"uuid"},"version":{"type":"integer","minimum":1},"fields":{"type":"array","items":{"type":"string","enum":["contrepartie.nom","categorie","recurrence"]},"description":"Les champs que la regle a changes : `contrepartie.nom` (`resolution.counterparty.name`), `categorie` (`resolution.category`), `recurrence` (`resolution.counterparty.semantics.recurring_model`)."}}}}}},"StoredEnrichment":{"type":"object","required":["enrichment_id","created_at","expires_at","resolution"],"properties":{"enrichment_id":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"expires_at":{"type":"string","format":"date-time","description":"★ La reponse est OPERATIONNELLE et bornee : ce n'est pas un corpus."},"resolution":{"$ref":"#/components/schemas/Resolution"},"relationships":{"type":"array","items":{"$ref":"#/components/schemas/Relationship"}},"series":{"type":"array","items":{"$ref":"#/components/schemas/Series"}},"customization":{"$ref":"#/components/schemas/Customization"}}},"SignalConflict":{"type":"object","required":["dimension","signals","resolution","resolved_to"],"description":"Deux signaux independants qui se contredisent sur une dimension, et comment le conflit a ete arbitre. Aucune certitude n'est fabriquee : le type retenu est plafonne (`confidence.transaction_type` <= 0,25).","properties":{"dimension":{"type":"string"},"signals":{"type":"array","items":{"type":"string"}},"resolution":{"type":"string","description":"Une phrase, en francais : comment le conflit a ete arbitre."},"resolved_to":{"type":"string"}},"additionalProperties":{"type":"string","description":"`<signal>_suggests` : ce que chaque signal en conflit proposait."}},"Resolution":{"type":"object","description":"La forme rendue par le moteur `ti_v4`.","properties":{"policy":{"type":"object","required":["outcome","archetype","missing","policy_version"],"description":"★★★ CE QUE « RESOLU » VEUT DIRE DEPEND DE LA NATURE DE LA TRANSACTION. Un virement a une personne est `resolved` sans qu'aucune identite ne soit creee — c'est la bonne reponse, pas un echec. Un retrait d'especes est `resolved` sans marchand. Un achat carte, lui, exige sa contrepartie.","properties":{"outcome":{"type":"string","enum":["resolved","partial","unresolved"],"description":"`resolved` : toutes les dimensions exigees par l'archetype sont la. `partial` : la NATURE est connue, une dimension exigee manque — ou des signaux se contredisent, auquel cas on refuse de conclure. `unresolved` : on ignore jusqu'a la nature. ★ Les erreurs TECHNIQUES (401, 409, 503) ne sont jamais une issue semantique : elles ne portent pas ce champ."},"archetype":{"type":"string","enum":["achat_carte","frais_bancaires","impot","indetermine","prelevement","remboursement","retrait_especes","revenu","transfert","transfert_personne","inconnu","non_couvert"],"description":"★ Le vocabulaire est FRANCAIS et c'est celui de la base (le vocabulaire des archetypes de resolution), conserve tel quel pour `ti_v1`. `inconnu` : la nature meme de la transaction est inconnue. `non_couvert` : la nature est connue mais aucune politique ne la couvre (`missing = [resolution_policy]`)."},"missing":{"type":"array","items":{"type":"string","enum":["counterparty_entity","counterparty_type","transaction_type","resolution_policy"]},"description":"Les dimensions exigees par l'archetype et absentes."},"policy_version":{"type":"string","enum":["ti_resolution_v1"]}}},"normalized":{"type":"object","description":"Ce que le normaliseur a lu. Des chaines, pas des scores.","properties":{"descriptor":{"type":"string"},"signal":{"type":"string"},"useful":{"type":"string"},"residual":{"type":"string"},"normalizer_version":{"type":"string"}}},"counterparty":{"type":["object","null"],"description":"★ `null` est un resultat, pas une panne : un inconnu honnete.","properties":{"entity_id":{"type":"string","format":"uuid","description":"★ L'identifiant STABLE de l'entite dans le graphe, sous forme d'UUID nu, sans prefixe. Il est opaque : ne lui pretez aucune structure. Le meme identifiant designe la meme entite d'une reponse a l'autre et d'un workspace a l'autre (le graphe est partage ; l'identifiant n'est pas une donnee de votre workspace). ★ Il est cite tel quel dans `series[].evidence` sous la forme `entite:<uuid>`."},"name":{"type":"string"},"kind":{"type":"string","enum":["brand","organisation"]},"evidence":{"type":"object","description":"Comment le motif a apparie le libelle. Deux rapports de longueur, qui sont des proprietes du TEXTE et pas une preuve d'identite. `match` dit par quelle voie (`jetons` : un alias entier dans le libelle ; `tronque` : un fragment de libelle coupe par la banque). `pattern` est l'alias apparie, en clair.","properties":{"match":{"type":"string","enum":["jetons","tronque"]},"pattern":{"type":"string"},"coverage":{"type":"number","minimum":0,"x-noryo-score":{"class":"text_coverage","calibration":"non_calibree","is_probability":false,"formula":"longueur du motif apparie / longueur du libelle utile","comparable_within":"libelles","not_comparable_with":["tout score d'identite ou de serie"]}},"covered":{"type":"number","minimum":0.6,"maximum":1,"x-noryo-score":{"class":"text_coverage","calibration":"non_calibree","is_probability":false,"formula":"longueur du fragment / longueur du motif compact (voie tronquee)","comparable_within":"cas tronques","not_comparable_with":["tout autre score"]}}}},"semantics":{"$ref":"#/components/schemas/CounterpartySemantics"}}},"counterparty_type":{"type":"string"},"counterparty_note":{"type":["string","null"],"description":"Dit POURQUOI aucune identite n'a ete etablie."},"category":{"type":["object","null"],"description":"★★★ UNE CATEGORIE N'EST PAS UNE IDENTITE. Quand le libelle designe un METIER (« BOULANGERIE DUPONT », « PHARMACIE DE LA GARE ») et non une enseigne connue, la reponse rend ce metier ICI et laisse `counterparty` a `null`. Rendre « Boulangerie » comme contrepartie reviendrait a nommer un rayon a la place d'une entreprise. ★★★ ET C'EST UNE LIGNE DE BUDGET, PAS UN METIER. Cette categorie repond a « a quoi cet argent est-il alle », du point de vue de la personne. Ce que l'entite FAIT est un autre champ, `counterparty.semantics.activity`, et les deux ne se substituent pas : EDF vend de l'electricite (`activity = utilities.electricity`) et la depense se range sous `logement.electricite`. ★ `source` dit d'ou vient la ligne : `entity_graph` quand elle est portee par l'enseigne reconnue, `generic_trade_entry` quand elle est deduite d'un mot de metier lu dans le libelle. La premiere est bornee par `confidence.entity` — une enseigne mal reconnue ne donne pas une categorie sure. ★ Quand une regle de VOTRE organisation a pose la categorie (voir `customization`), `source` est ABSENT : `slug` et `label` viennent alors du catalogue Noryo, et aucune des deux origines Noryo ne serait vraie.","properties":{"slug":{"type":"string"},"label":{"type":["string","null"]},"source":{"type":"string","enum":["entity_graph","generic_trade_entry"]}}},"identity_abstention":{"type":["string","null"],"description":"★★★ POURQUOI LE MOTEUR A REFUSE DE NOMMER, alors qu'il aurait pu. `trade_not_identity` : un metier a ete reconnu, pas une enseigne. `atm_operator_not_counterparty` : sur un mouvement d'especes, la banque reconnue exploite le distributeur — elle n'est pas en face. `account_bank_not_counterparty` : sur un frais bancaire, c'est la banque du compte, et la nommer n'apprend rien. `person_named_not_brand` : le libelle nomme une personne, et l'enseigne reconnue appartient au motif du virement. ★ Une abstention n'est pas une panne : `policy.outcome` peut rester `resolved` si l'archetype n'exigeait pas d'entite."},"intermediaries":{"type":"array","description":"Les facilitateurs de paiement lus dans le libelle (`PAYPAL *NETFLIX` en donne un). Ils ne sont JAMAIS la contrepartie. ★ `evidence` est un CODE et une SOURCE — plus jamais le motif d'appariement lui-meme, qui est une regle interne.","items":{"type":"object","required":["name","role","evidence"],"properties":{"name":{"type":"string"},"role":{"type":"string"},"entity_id":{"type":["string","null"],"format":"uuid","description":"L'entite du facilitateur dans le graphe, quand elle y est."},"carries_sub_merchant":{"type":"boolean"},"evidence":{"type":"object","required":["code","source"],"properties":{"code":{"type":"string","description":"Le code du facilitateur au referentiel."},"source":{"type":"string","enum":["referentiel_facilitateurs"]}}}}}},"transaction_type":{"type":"object","required":["canonical","evidence","contradiction"],"description":"CE QUE la transaction signifie, par opposition a `payment` qui dit COMMENT l'argent a circule. ★ `evidence` est un CODE de regle, pas une explication : la NOTE interne de la regle sortait ici dans une version anterieure ; les reponses creees alors portent `legacy_note_redacted`.","properties":{"canonical":{"type":"string"},"evidence":{"type":"string","pattern":"^(rail_rule|descriptor_rule|descriptor_sense_rail_mechanism|rail_and_descriptor_agree|descriptor_refines_rail|rail_refines_descriptor|rail_descriptor_conflict|no_rule)(\\+counterparty_nature)?$|^legacy_note_redacted$","description":"`rail_rule` : le rail seul a decide. `descriptor_rule` : le libelle seul. `descriptor_sense_rail_mechanism` : le libelle donne le sens, le rail le mecanisme, sans conflit. `rail_and_descriptor_agree` : les deux disent la meme chose. `descriptor_refines_rail` / `rail_refines_descriptor` : l'un precise l'autre. `rail_descriptor_conflict` : contradiction, aucune certitude fabriquee (voir `signal_conflicts`). `no_rule` : rien ne s'applique. Le suffixe `+counterparty_nature` dit que la nature de la contrepartie a affine le type."},"contradiction":{"type":["string","null"]}}},"payment":{"type":["object","null"],"description":"Ce que le moteur a compris du rail et du mecanisme de paiement.","properties":{"rail":{"type":["string","null"]},"mechanism":{"type":["string","null"]},"note":{"type":["string","null"],"description":"Une phrase explicative CONSTANTE, en francais, qui rappelle la difference entre `rail` et `transaction_type`. Pas une donnee."}}},"signal_conflicts":{"type":"array","items":{"$ref":"#/components/schemas/SignalConflict"},"description":"Les signaux qui se contredisent. Quand il y en a, `policy.outcome` est `partial` : on refuse de conclure."},"submerchant_lane":{"type":"string","enum":["none","no_candidate","resolved","ambiguous"],"description":"L'issue de la voie « sous-marchand » (un facilitateur porte l'enseigne reelle). `none` : voie non ouverte. `no_candidate` : ouverte, aucune entite. `resolved` : une entite unique. `ambiguous` : plusieurs, abstention. ★ Absent sur les reponses les plus anciennes, creees avant que cette voie existe."},"truncated_lane":{"type":"string","enum":["none","no_candidate","resolved","ambiguous"],"description":"L'issue de la voie « libelle tronque » (la banque a coupe le nom). Memes valeurs que `submerchant_lane`. ★ Absent sur les reponses les plus anciennes, creees avant que cette voie existe."},"confidence":{"type":"object","required":["entity","counterparty","transaction_type","category","location","calibration"],"description":"★★★ LE NOM EST CONSERVE POUR `ti_v1` ; CE N'EST PAS UNE CONFIANCE. Chacun de ces nombres est une CONSTANTE DECLAREE — posee par la personne qui a ecrit le motif ou la regle, et lue telle quelle. Toute transaction qui touche le meme motif recoit le meme nombre. ★★★ MESURE SUR 644 LIBELLES : la precision en fonction du seuil n'est PAS monotone — 0,85 donne 0,86 de precision, 0,88 donne 0,33, 0,92 donne 0,25, 0,97 donne 0,79. Ce nombre n'ordonne pas le juste avant le faux. Ne l'utilisez ni comme probabilite ni comme seuil : utilisez `policy.outcome`. ★ `0` a un sens precis par champ : abstention (`entity`), role inconnu (`counterparty`), conflit sans ancetre commun (`transaction_type`). `location` vaut toujours `0` : rien n'est resolu sur cet axe dans cette version.","properties":{"entity":{"type":"number","minimum":0,"maximum":1,"x-noryo-score":{"class":"declared_constant","calibration":"non_calibree","is_probability":false,"source":"la confiance DECLAREE du motif d'entite apparie (referentiel interne), repli 0.700","not_comparable_with":["une autre entite","tout autre score"]}},"counterparty":{"type":"number","minimum":0,"maximum":1,"x-noryo-score":{"class":"declared_constant","calibration":"non_calibree","is_probability":false,"source":"= entity ; 0 si role inconnu ; 0.400 si forme de personne","not_comparable_with":["tout autre score"]}},"transaction_type":{"type":"number","minimum":0,"maximum":1,"x-noryo-score":{"class":"declared_constant","calibration":"non_calibree","is_probability":false,"source":"la confiance DECLAREE de la regle de type (referentiel interne) ; plafonds de politique 0.250 (conflit avec ancetre) et 0.300 (sens contredit)","not_comparable_with":["tout autre score"]}},"category":{"type":"number","minimum":0,"maximum":1,"x-noryo-score":{"class":"declared_constant","calibration":"non_calibree","is_probability":false,"source":"confiance du motif de metier (repli 0.700), ou copie de `entity` quand la categorie vient du graphe","not_comparable_with":["tout autre score"]}},"location":{"type":"number","enum":[0],"x-noryo-score":{"class":"declared_constant","calibration":"non_calibree","is_probability":false,"source":"constante 0"}},"calibration":{"type":"string","enum":["non_calibree"],"description":"★★★ TOUJOURS `non_calibree` dans cette version, et c'est une CONTRAINTE, pas une convention : la valeur est un vocabulaire en base, les colonnes qui la portent y font reference, et une garde refuse tout litteral hors vocabulaire chez chaque producteur. Le jour ou une calibration reelle existe, elle entrera par une migration declaree, avec le corpus qui la defend."}}},"timings_ms":{"type":"object","description":"Des durees, en millisecondes. Rien a voir avec une confiance.","properties":{"normalization":{"type":"number"},"entity_resolution":{"type":"number"},"submerchant":{"type":"number"},"total":{"type":"number"}}},"versions":{"type":"object","description":"★ Les versions qui ont produit cette reponse. Un client qui conserve un nombre doit conserver la version a cote : la meme valeur, sous une autre version, peut ne plus mesurer la meme chose.","required":["engine","resolution_policy","calibration"],"properties":{"graph":{"type":"string","description":"L'ontologie du graphe d'entites (`onto_v1`)."},"rules":{"type":"string","description":"Les regles de type de transaction (`txtype_v1`)."},"engine":{"type":"string","description":"Le moteur de resolution (`ti_v4`)."},"resolution_policy":{"type":"string","description":"La meme valeur que `policy.policy_version`."},"calibration":{"type":"string","enum":["non_calibree"],"description":"★★★ TOUJOURS `non_calibree` dans cette version, et c'est une CONTRAINTE, pas une convention : la valeur est un vocabulaire en base, les colonnes qui la portent y font reference, et une garde refuse tout litteral hors vocabulaire chez chaque producteur. Le jour ou une calibration reelle existe, elle entrera par une migration declaree, avec le corpus qui la defend."}}}}}}}}