Séries récurrentes
Ce qu'est une série (series[]), pourquoi son identifiant reste stable, et comment lire status, cadence, calendar_pattern et history_coverage.
Une série (series[] dans un enrichissement) regroupe plusieurs occurrences économiquement liées dans le temps, au sein de votre workspace : un abonnement, un loyer, un salaire, une pension. lifecycle et identity ont chacun leur page : Cycle de vie d'une série et Scission, fusion, supersession.
Une série n'est pas une contrepartie
Une contrepartie est l'autre bout d'une transaction ; une série est un flux qui revient. Une même contrepartie peut porter plusieurs séries : deux abonnements distincts chez Netflix sont deux séries, avec deux series_id. Et une série ne se réduit jamais à « toutes les transactions de cette contrepartie ».
Une série est privée : elle vit dans votre workspace et n'alimente jamais le graphe d'entités partagé.
Un identifiant qui ne dépend pas de la dernière occurrence
series_id se dérive de ce qui ne change pas : le workspace, la famille de série, la contrepartie, le sens et la devise. Il ne dépend ni de la dernière occurrence ni du libellé courant. Une occurrence de plus ne crée pas une autre série.
Vous pouvez donc stocker series_id. Seule une correction d'identité le remplace ; l'ancien reste lisible, marqué superseded dans identity, et membership relie ce que vous aviez stocké à ce que vous recevez.
Les quatre types
type | Ce que cela affirme |
|---|---|
recurring_payment | Ce paiement revient, rien de plus : un loyer et une échéance de prêt le sont aussi. |
subscription | Une affirmation plus forte, qui exige son propre signal ; sans lui, la réponse reste recurring_payment. |
recurring_income | Un revenu qui revient : pension, prestation, loyer perçu. |
salary_series | Une spécialisation de recurring_income, pas un synonyme. |
implies porte le type plus général : une subscription implique recurring_payment. counterparty.semantics.recurring_model dit ce qui est habituel dans le métier de la contrepartie, pas ce qu'il en est de cette transaction : seul, il ne conclut jamais ; c'est series[].type qui tranche. Il n'existe aucune catégorie subscription : un abonnement est un modèle de relation commerciale, pas une sorte de dépense.
status : à quel point c'est une série
status | Lecture |
|---|---|
emerging | Deux occurrences font émerger une série. Une seule, jamais. |
established | Trois occurrences peuvent l'établir. |
uncertain | Non décrit par le contrat au-delà de son nom ; son exemple le montre sur une cadence irregular_recurring (cadence_detail.strength à 0). |
broken | Se calcule au moment de la lecture : une série devient en retard par le seul passage du temps, sans qu'aucune écriture n'ait lieu. |
status ne dit ni ce qui arrive à la série maintenant (lifecycle.state) ni si son nom est toujours le bon (identity.status).
Une première occurrence n'ouvre aucune série : series[] est vide et relationships_policy.unresolved porte une entrée type = series avec outcome et occurrences (single_occurrence et 1 dans l'exemple du contrat, no_series_key et 0 dans son exemple non résolu). Les autres issues sont listées dans la Référence.
Cadence et ancrage : deux questions différentes
cadence dit à quelle fréquence l'événement se répète : weekly, biweekly, monthly, quarterly, yearly, irregular_recurring ou unknown. Elle se lit au calendrier, pas en jours secs : le 31 janvier et le 28 février sont à un mois d'intervalle. Une récurrence de 28 jours n'est pas mensuelle : son jour recule à chaque cycle, et elle est rangée sous irregular_recurring. cadence_detail.strength est la part des cycles attendus qui portent une occurrence ; 0 signifie « aucune hypothèse calendaire retenue », pas « faible ».
calendar_pattern répond à une autre question : où, dans chaque période, la série tend à tomber. Une série peut être franchement mensuelle en flottant entre le 1er et le 6 ; sans ce bloc, monthly se lirait comme « le même jour chaque mois ».
calendar_pattern.type | Ce que cela décrit |
|---|---|
fixed_day_of_month | Toujours autour du même jour. |
month_end | En fin de mois, quel que soit le nombre de jours. |
last_business_day | Le dernier jour ouvré, cas fréquent des salaires. |
business_day_adjusted | Un jour nominal déplacé hors du week-end. |
fixed_weekday | Toujours le même jour de la semaine. |
flexible_calendar_window | Une occurrence par période, sans jour stable. |
unknown | Rien d'identifiable. |
Les jours fériés ne sont pas modélisés : un report de férié est absorbé par la tolérance de la fenêtre, pas reconnu. C'est aussi l'ancrage qui donne sa largeur à lifecycle.expected_next_window.
Schéma CalendarPattern
Où, dans chaque période, la série tend à tomber — une question différente de `cadence`. Une série peut être franchement mensuelle en flottant entre le 1er et le 6 : sans ce champ, « monthly » se lirait comme « le même jour chaque mois », ce qui est faux pour la majorité des séries réelles. C'est aussi ce qui donne sa largeur à `expected_next_window` : un prélèvement toujours au 5 justifie trois jours, un loyer qui flotte en justifie huit. Appliquer la même fenêtre aux deux ferait déclarer « en retard » une série parfaitement normale.
- typestring
fixed_day_of_month: toujours autour du même jour.month_end: en fin de mois, quel que soit le nombre de jours — un prélèvement du 31 janvier, 28 février, 31 mars est un seul motif.last_business_day: le dernier jour ouvré, cas fréquent des salaires.business_day_adjusted: un jour nominal déplacé hors du week-end (samedi → vendredi, dimanche → lundi). Nous NE modélisons pas les jours fériés : ni français, ni target, ni bancaires. Un report de férié est absorbé par la tolérance de la fenêtre, pas reconnu — prétendre connaître un calendrier que nous n'avons pas serait pire que de l'ignorer.fixed_weekday: toujours le même jour de la semaine.flexible_calendar_window: une occurrence par période, sans jour stable.unknown: rien d'identifiable.fixed_day_of_monthmonth_endlast_business_daybusiness_day_adjustedfixed_weekdayflexible_calendar_windowunknown - nominal_dayinteger· nullable
- weekdayinteger· nullable
- day_rangearray<integer>· nullable
- weekend_shiftsinteger· nullable
- strengthnumber · 0–1
Une constante par type d'ancrage, ou une formule linéaire sur l'étendue des jours pour
fixed_day_of_monthetflexible_calendar_window.0pourunknown. Un 0,33fixed_day_of_monthet un 0,3flexible_calendar_windowne se comparent pas — etflexible_calendar_windowchange de règle avec la cadence (constante 0,3 en hebdomadaire,1 - etendue/10en mensuel). - calibrationstring
Toujours
non_calibreedans cette version, et c'est une contrainte, pas une convention : la valeur est un vocabulaire en base, les colonnes qui la portent y font référence, et une garde refuse tout littéral hors vocabulaire chez chaque producteur. Le jour où une calibration réelle existe, elle entrera par une migration déclarée, avec le corpus qui la défend.non_calibree
cadence_detail.strength (classe calendar_fill) et calendar_pattern.strength (classe anchor_stability) ne sont pas des probabilités : chacun ne se compare qu'entre séries de même cadence, et de même type d'ancrage pour le second. Voir Sémantique des scores.
Montants et prochaine échéance
amount_behavior n'exige pas l'égalité exacte : une facture d'électricité varie, un salaire aussi. kind vaut fixed, narrow_variable ou broadly_variable ; min_minor_units et max_minor_units sont des chaînes en unités mineures, jamais des nombres JSON.
expected_next_at est facultatif, et c'est voulu : absent tant que la série n'est pas établie ou que la cadence est irrégulière. Ce n'est pas une API de prévision.
Ce que la mémoire permet de conclure
history_coverage distingue deux mémoires.
| Champ | Sens |
|---|---|
raw_days | Durée de vie de la transaction brute ; passé ce délai, elle est supprimée et rien ne la rend. retention_limit_days est identique, conservé pour compatibilité. |
derived_days | Durée de vie de ce que nous avons appris d'une série, comptée depuis sa dernière occurrence. À l'échéance, une occurrence ultérieure ouvre une série neuve. |
observed_days | L'étendue réellement observée, de la première à la dernière occurrence connue. |
sufficiency | Une seule question : peut-on croire la cadence ? sufficient, limited ou insufficient. |
first_occurrence_bounded | Une autre question : sait-on quand cela a commencé ? first_occurrence_reason dit pourquoi. |
Une transaction purgée reste purgée, mais la série 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.
insufficient signifie « notre mémoire est trop courte pour en juger », jamais « il n'y a pas d'occurrence plus ancienne ». first_observed_on est le premier jour où nous avons observé la série, pas le jour où elle a commencé (il n'existe aucun champ started_at) ; may_predate_observation vaut true quand elle a pu commencer avant nous.
Une série annuelle ne peut pas s'établir dans la fenêtre observable : status reste emerging. Lisez sufficiency et observed_days plutôt que de conclure de occurrence_count seul.
match_strength et evidence
match_strength.value n'est pas une probabilité : c'est la part de cinq critères hétérogènes présents (corroborations.present sur corroborations.possible). Ce n'est pas le même nombre que relationships[].match_strength, et il ne se compare qu'entre séries de même detector_version. evidence[] liste les signaux qui fondent la série (occurrences y porte un entier).
Exemple
Une série d'abonnement établie, extrait de l'exemple du contrat :
{
"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_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": {
"raw_days": 30, "derived_days": 400, "observed_days": 153, "retention_limit_days": 30,
"occurrence_count": 6, "cadence": "monthly", "sufficiency": "sufficient",
"first_occurrence_bounded": true
}
}JSONSchéma Series
Plusieurs occurrences économiquement liées dans le temps, dans CE workspace. Une série privée ne devient jamais une vérité du graphe d'entités.
- series_idstringrequis
Stable. Il se dérive de ce qui ne change pas — workspace, famille, contrepartie, sens, devise — jamais de la dernière occurrence ni du libellé courant. Une occurrence de plus ne crée pas une autre série.
^ser_[0-9a-f-]{36}$ - typestringrequis
recurring_paymentdit « ce paiement revient », et rien de plus : un loyer et une échéance de prêt le sont aussi.subscriptionest une affirmation plus forte et exige son propre signal ; sans lui, la réponse resterecurring_payment. De mêmerecurring_incomecouvre pension, prestation et loyer perçu —salary_seriesen est une spécialisation, pas un synonyme.recurring_paymentsubscriptionrecurring_incomesalary_series - impliesarray<string>
Le type plus général que celui-ci spécialise, s'il existe.
- statusstringrequis
Deux occurrences font émerger, trois peuvent établir, une seule jamais.
brokense calcule au moment de la lecture : une série devient en retard par le seul passage du temps, sans qu'aucune écriture n'ait lieu.emergingestablisheduncertainbroken - cadencestringrequis
Lue au calendrier, pas en jours secs : le 31 janvier et le 28 février sont à un mois d'intervalle, et un salaire au dernier jour ouvré glisse.
weeklybiweeklymonthlyquarterlyyearlyirregular_recurringunknown - occurrence_countintegerrequis
- amount_behaviorobjectrequis
L'égalité exacte n'est pas exigée : une facture d'électricité varie, un salaire aussi. Montants en unités mineures, en chaîne — jamais un nombre JSON.
- kindstring
fixednarrow_variablebroadly_variable - min_minor_unitsstring
- max_minor_unitsstring
- currencystring
- first_seenstring · date-time
- last_seenstring · date-time
- expected_next_atstring · date-time· nullable
Facultative, et c'est le point. Absente tant que la série n'est pas établie ou que la cadence est irrégulière : rendre une date sur deux observations faibles la ferait passer pour une prévision. Ce n'est pas une API de prévision.
- match_strengthobjectrequis
Ce n'est pas une probabilité : c'est la part des signaux corroborants présents sur ceux que ce type sait produire. Et ce n'est pas le même nombre que
relationships[].match_strength: même nom, autre dénominateur, autres signaux. Cinq critères hétérogènes sur cinq — cadence calendaire, montant fixe ou étroit, au moins trois occurrences, entité connue, type spécialisé. Ils ne s'additionnent qu'ici. - valuenumber · 0.001–1requis
- calibrationstringrequis
Toujours
non_calibreedans cette version, et c'est une contrainte, pas une convention : la valeur est un vocabulaire en base, les colonnes qui la portent y font référence, et une garde refuse tout littéral hors vocabulaire chez chaque producteur. Le jour où une calibration réelle existe, elle entrera par une migration déclarée, avec le corpus qui la défend.non_calibree - corroborationsobjectrequis
- presentintegerrequis
- possibleintegerrequis
5 - evidencearray<object>
Les signaux qui fondent la série.
valueest une chaîne ou un entier selon le code (occurrencesporte un entier). - codestringrequis
- valuestring | integer· nullable
- lifecycleSeriesLifecycle
Un axe différent de
status.statusdit à quel point nous croyons que c'est une série ;lifecycledit ce qui lui arrive maintenant. Une série très bien établie peut avoir cessé de prélever, et une série fraîche peut être parfaitement vivante. Et aucun état ne se conclut d'une absence sans couverture : si la source n'était pas observée de façon complète sur la fenêtre attendue, l'état estunknown, paslate. « Je n'ai rien vu » ne devient jamais « il n'y a rien eu » — c'est la différence entre un client qui a cessé d'envoyer et un abonnement qui a cessé de prélever. - statestringrequis
active: l'échéance attendue est arrivée, ou n'est pas encore échue.late: une échéance manque ET le compte était observé.inactive: plusieurs échéances consécutives manquent sous observation complète — la série ne prélève plus, sans que nous sachions pourquoi.ended: réservé à une preuve terminale explicite. Aucune accumulation d'absences ne produit cet état : un prélèvement qui s'arrête peut être une résiliation, une suspension, une carte expirée ou un échec de prélèvement, et nous ne devinons pas laquelle.unknown: nous ne pouvons pas conclure, etreasondit pourquoi.activelateinactiveendedunknown - reasonstring
- last_observed_onstring · date· nullable
- expected_next_windowobject· nullable
Une fenêtre, pas une date. Un salaire tombe vers les derniers jours ouvrés, un prélèvement SEPA vers le 5. Rendre un instant exact serait une précision que nous n'avons pas, et vous la croiriez.
- fromstring · date
- tostring · date
- tolerance_daysinteger
La demi-largeur de la fenêtre, en jours. Plus grand = moins précis. Vient du type d'ancrage, relevé au plancher de la famille de série.
- anchorstring
Le type d'ancrage qui a donné la fenêtre.
- widened_to_family_floorboolean
truesi la tolérance a été relevée au plancher de la famille (5 jours pour un abonnement, 6 pour un salaire, 7 sinon). - consecutive_missesinteger· nullable
Le compteur n'avance que sous couverture complète. Absent quand rien n'est attendu — ce qui n'est pas la même ignorance que « nous ne regardions pas ».
- observation_coveragestring
not_required: aucune échéance close, rien n'avait à être observé.complete: chaque source de la série était couverte sur la fenêtre attendue — un manque est un manque.incomplete: au moins une source ne l'était pas — l'absence ne prouve rien,stateestunknown.unknown: les sources sont inconnues ou trop nombreuses pour être vérifiées.not_requiredcompleteincompleteunknown - cadence_strengthnumber· nullable
Le même nombre que
cadence_detail.strength, rendu ici pour que le cycle de vie soit lisible seul. Ce n'est pas un second score. - calendar_anchorany
Le même objet que
calendar_pattern(classeanchor_stability), rendu ici pour la même raison ;{ type: unknown }quand aucun ancrage n'a été inféré. Absent quand aucune échéance n'est attendue. duplicate_of :series[].calendar_pattern— ce n'est pas un second score. - evidencearray<object>
Présent pour
ended: la preuve terminale qui l'a produit. - codestring
- identity_statusstring· nullable
Présent uniquement quand l'identité de la série a été corrigée, pour dire pourquoi
statevautunknown: ce n'est pas une ignorance économique, c'est que le verdict appartient désormais aux successeurs. L'état d'identité complet se lit dansidentity, qui est un axe à part entière ; ce champ n'est qu'un renvoi, et il ne prend jamais la valeurcurrent.supersedednull - policy_versionstringrequis
- calibrationstringrequis
Toujours
non_calibreedans cette version, et c'est une contrainte, pas une convention : la valeur est un vocabulaire en base, les colonnes qui la portent y font référence, et une garde refuse tout littéral hors vocabulaire chez chaque producteur. Le jour où une calibration réelle existe, elle entrera par une migration déclarée, avec le corpus qui la défend.non_calibree - identitySeriesIdentity
Un troisième axe, et il ne se mélange ni à
statusNI Àlifecycle.statusdit à quel point nous croyons que c'est une série ;lifecycledit ce qui lui arrive économiquement ;identitydit si son nom est toujours le bon. Une série peut prélever tous les mois et avoir changé d'identité parce que nous avons compris qu'elle était en réalité deux flux, ou deux moitiés d'un seul. ET UNseries_idn'est jamais réécrit ni réutilisé en silence. Quand nous corrigeons, l'ancien nom subsiste, marquésuperseded, et il porte ses successeurs. - statusstringrequis
current: ce nom est le nom courant de ce flux.superseded: ce nom a été remplacé par une correction d'identité. Il reste valide comme référence historique — il ne disparaîtra pas — mais les occurrences futures porteront le nom de ses successeurs.currentsuperseded - superseded_byobject· nullable
Après une scission il n'y a pas de redirection unique, et c'est pourquoi ce champ rend une liste. Si nous découvrons qu'une série mélangeait deux flux, aucun des deux successeurs n'est « la suite » de l'ancien : la moitié des occurrences de l'ancien n'est pas dans l'un d'eux. Élire un canonique serait confortable et faux.
- reasonstring
split: cette identité en recouvrait plusieurs, et chacune a désormais la sienne.merge: cette identité et une autre étaient le même flux ; toutes deux sont remplacées par une identité neuve.splitmerge - atstring · date-time
- evidencearray<string>
Les codes de preuve qui ont autorisé la correction. Jamais un score interne, jamais un identifiant de ligne.
- successor_series_idsarray<string>
Un seul après une fusion, plusieurs après une scission. Jamais vide quand
statusvautsuperseded. - supersedesarray<string>requis
Le chemin de retour, et il compte autant que l'autre. Les identités que celle-ci remplace. Sans lui, l'ancien
series_idque vous aviez stocké ne correspondrait plus à rien de ce que vous recevez, et vous n'auriez aucun moyen de faire le lien. Vide pour une série qui n'est née d'aucune correction. - membershipSeriesMembership
D'où vient cette occurrence, et où est-elle maintenant. Quand une identité est corrigée, l'occurrence change de série : sans ce bloc, vous n'auriez aucun moyen de relier le
series_idque vous aviez stocké à celui que vous recevez. Vous n'avez jamais à reconstruire le graphe vous-même. - original_series_idstring· nullable
La série à laquelle cette occurrence a été rattachée la première fois. Égale à
current_series_idtant qu'aucune correction n'a eu lieu.^ser_[0-9a-f-]{36}$ - current_series_idstring· nullablerequis
^ser_[0-9a-f-]{36}$ - correctionsarray<object>requis
Les déplacements successifs, du plus ancien au plus récent. Vide pour une occurrence qui n'a jamais bougé.
- reasonstring
splitmerge - from_series_idstring· nullable
^ser_[0-9a-f-]{36}$ - to_series_idstring· nullable
^ser_[0-9a-f-]{36}$ - atstring · date-time
- first_observed_onstring · date
Le premier jour où nous Avons observé cette série — pas le jour où elle a commencé. Une série 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_onstring · date
- may_predate_observationboolean
true: notre observation commence avec la première occurrence connue, donc la série a pu commencer avant nous et rien ne le montrera.false: la première occurrence connue est antérieure au début de notre observation, donc son commencement est observé et non supposé. - cadence_detailobject
À quelle fréquence l'événement se répète — et rien d'autre. La cadence se déduit de la progression des périodes calendaires, pas des écarts en jours : trois mois consécutifs sont trois mois consécutifs, que les écarts vaillent 28, 30 ou 31. Et une récurrence de 28 jours n'est pas mensuelle : elle tombe une fois par mois pendant onze mois puis deux, et son jour recule à chaque cycle. Nous ne l'appelons pas
monthly— cette version n'a pas de cadence pour elle, etirregular_recurringvaut mieux qu'un faux mensuel.strengthest la part des cycles attendus qui portent une occurrence. Ce n'est pas une probabilité. - typestring
- strengthnumber · 0–1· nullable
0= aucune hypothèse calendaire retenue, pas « faible ». - calibrationstring
Toujours
non_calibreedans cette version, et c'est une contrainte, pas une convention : la valeur est un vocabulaire en base, les colonnes qui la portent y font référence, et une garde refuse tout littéral hors vocabulaire chez chaque producteur. Le jour où une calibration réelle existe, elle entrera par une migration déclarée, avec le corpus qui la défend.non_calibree - calendar_patternCalendarPattern
Où, dans chaque période, la série tend à tomber — une question différente de
cadence. Une série peut être franchement mensuelle en flottant entre le 1er et le 6 : sans ce champ, « monthly » se lirait comme « le même jour chaque mois », ce qui est faux pour la majorité des séries réelles. C'est aussi ce qui donne sa largeur àexpected_next_window: un prélèvement toujours au 5 justifie trois jours, un loyer qui flotte en justifie huit. Appliquer la même fenêtre aux deux ferait déclarer « en retard » une série parfaitement normale. - typestring
fixed_day_of_month: toujours autour du même jour.month_end: en fin de mois, quel que soit le nombre de jours — un prélèvement du 31 janvier, 28 février, 31 mars est un seul motif.last_business_day: le dernier jour ouvré, cas fréquent des salaires.business_day_adjusted: un jour nominal déplacé hors du week-end (samedi → vendredi, dimanche → lundi). Nous NE modélisons pas les jours fériés : ni français, ni target, ni bancaires. Un report de férié est absorbé par la tolérance de la fenêtre, pas reconnu — prétendre connaître un calendrier que nous n'avons pas serait pire que de l'ignorer.fixed_weekday: toujours le même jour de la semaine.flexible_calendar_window: une occurrence par période, sans jour stable.unknown: rien d'identifiable.fixed_day_of_monthmonth_endlast_business_daybusiness_day_adjustedfixed_weekdayflexible_calendar_windowunknown - nominal_dayinteger· nullable
- weekdayinteger· nullable
- day_rangearray<integer>· nullable
- weekend_shiftsinteger· nullable
- strengthnumber · 0–1
Une constante par type d'ancrage, ou une formule linéaire sur l'étendue des jours pour
fixed_day_of_monthetflexible_calendar_window.0pourunknown. Un 0,33fixed_day_of_monthet un 0,3flexible_calendar_windowne se comparent pas — etflexible_calendar_windowchange de règle avec la cadence (constante 0,3 en hebdomadaire,1 - etendue/10en mensuel). - calibrationstring
Toujours
non_calibreedans cette version, et c'est une contrainte, pas une convention : la valeur est un vocabulaire en base, les colonnes qui la portent y font référence, et une garde refuse tout littéral hors vocabulaire chez chaque producteur. Le jour où une calibration réelle existe, elle entrera par une migration déclarée, avec le corpus qui la défend.non_calibree - history_coverageobjectrequis
Ce que nous pouvons voir, et ce que nous ne pouvons pas.
insufficientsignifie « notre mémoire est trop courte pour en juger », jamais « il n'y a pas d'occurrence plus ancienne ». Et il y a deux mémoires, 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 série lui survit. Une transaction purgée reste purgée — cette API ne la ressuscite jamais — mais la série 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_daysest ce que nous avons effectivement vu : un client qui lit « monthly / sufficient » peut vérifier que la conclusion ne sort pas de trente jours. - observed_fromstring · date
- observed_tostring · date
- raw_daysinteger
Durée de vie de la transaction brute. Passé ce délai elle est physiquement supprimée et rien ne la rend.
- derived_daysinteger
Durée de vie de la mémoire de série, comptée depuis la dernière occurrence. Sans nouvelle occurrence, l'état dérivé est physiquement supprimé à l'échéance et une occurrence ultérieure ouvre une série neuve.
- observed_daysinteger
Étendue réellement observée, de la première à la dernière occurrence connue.
- retention_limit_daysintegerrequis
Conservé pour compatibilité : identique à
raw_days. - occurrence_countintegerrequis
- cadencestring
- sufficiencystringrequis
Répond à une seule question : peut-on croire la cadence ? Pas à « sait-on quand ça a commencé », qui est le champ suivant.
sufficientlimitedinsufficient - reasonstring
- first_occurrence_reasonstring
Dit pourquoi
first_occurrence_boundedvaut ce qu'il vaut. - first_occurrence_boundedboolean
Une question différente de
sufficiency, et qui était confondue avec elle.true: notre observation de cette série commence avec la première occurrence que nous connaissons — elle a donc pu commencer avant nous, et rien ne le montrera jamais.false: la première occurrence connue est antérieure au début de notre observation, donc le commencement est observé et non supposé. Un import d'historique rendfalse; une série découverte au fil de l'eau rendtrue. - detector_versionstring
Pour aller plus loin
Publié le 2026-09-17 11:19 UTC (version 1).