You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat: preserve event time separately from extraction time in ClaimEvent #717
ClaimEvent contains extracted_at but no dedicated event-occurrence or validity interval fields. This specific contract cannot preserve that distinction structurally; Cortex already has other temporal mechanisms, so this is not a claim that temporal retrieval is absent.
Proposed solution
Define event occurrence and, where needed, validity intervals with explicit unknowns, precision and timezone. Carry supported fields through extraction, persistence, synthesis and retrieval without converting an extraction timestamp into an event timestamp.
Acceptance evidence
A historical event extracted today retains its historical occurrence separately from extracted_at.
Unknown, point and interval dates round-trip with their precision and timezone.
Corrections and contradictory dates preserve provenance and uncertainty; do not invent a date.
Alternatives considered
Keep the current behavior and document its limits. This remains valid where the added guarantee has no user need; the issue should close with a documented product decision rather than assume that copying Hindsight is always appropriate. Reuse existing Cortex mechanisms before adding a second pipeline.
Scope assessment
MEDIUM. Raised from the October 10 Hindsight/Cortex comparison. Static observations refer to the pinned revisions below. They do not establish successful execution of Hindsight's whole pipeline or a repository-wide absence in Cortex. Priority is a proposal, not a release blocker.
CI autopilot : première tranche livrée dans #875 (Refs #717, pas Closes).
Tranche 1 : le contrat. ClaimEvent.event_time (EventTime : unknown / point / interval, chaque borne avec sa valeur, sa précision ISO 8601 et, si la source l'énonce, son décalage horaire). Valeur par défaut unknown, jamais dérivée de extracted_at. Les validateurs refusent une précision inventée, des bornes contraires au type, un intervalle inversé ou mêlant bornes avec et sans zone. 18 tests ajoutés, 825 tests voisins passent ; suite complète et pyright non lancés ici (pile torch non installable dans cet environnement), la CI fera foi.
Tranches restantes :
Persister event_time dans wiki.claim_events (PostgreSQL et SQLite), migration unique.
Extraire les dates énoncées dans core/claim_extractor via shared/temporal_normalize, avec leur précision, sans repli sur extracted_at.
Porter le champ à travers la synthèse et la recherche ; corrections et dates contradictoires conservent provenance et incertitude.
CI autopilot : tranche 2 dans #894 (Refs #717, pas Closes).
Tranche 2 : la persistance. wiki.claim_events.event_time contient le JSON d'EventTime (JSONB sous PostgreSQL, JSON sous SQLite). Une borne sans zone reste sans zone, une borne avec zone garde son décalage, ce qu'une paire TIMESTAMPTZ aurait ramené en UTC. Les bases existantes migrent une fois et leurs lignes se lisent unknown. wiki_extract écrit le champ. 4 tests SQLite passent (ils échouent sur main) ; les variantes PostgreSQL et la suite complète n'ont pas pu tourner ici (pas de pgvector, torch non téléchargeable), la CI fera foi.
Tranches restantes :
Extraire les dates énoncées dans core/claim_extractor via shared/temporal_normalize, avec leur précision, sans repli sur extracted_at.
Porter le champ à travers la synthèse et la recherche ; corrections et dates contradictoires gardent leur provenance et leur incertitude.
CI autopilot : la tranche 3 est dans #923 (Refs #717, pas Closes).
Tranche 3, l'extraction. extract_claims remplit maintenant event_time avec la date que la phrase de la claim énonce, à la précision où elle est écrite. « March 2026 » donne un mois. « 12 March 2026 » et « March 12, 2026 » donnent un jour. Les formats ISO 8601 étendus donnent un mois, un jour, une minute ou une seconde, avec leur décalage s'il est indiqué (sinon la valeur reste naïve). Ces cas restent unknown : pas de date, une année seule, une date relative, une date ou un décalage impossible, des fractions de seconde, ou deux dates différentes dans la même phrase. La valeur n'est jamais prise dans extracted_at.
Je n'ai pas réutilisé normalize_date_to_iso : il complète les composants absents. Mesuré le 2026-11-06 : « March 2026 » donne 2026-03-06, et « 2019 » donne 2019-11-06.
Ce que j'ai vérifié : les 35 nouveaux tests passent, ainsi que 1321 tests voisins (25 ignorés). La porte de mutation sur les lignes modifiées donne 0 échec, et la porte craftsmanship est OK.
Pas vérifié : la suite complète, pyright et les variantes PostgreSQL (torch ne se télécharge pas dans cet environnement). La CI fera foi.
Tranche restante : porter le champ à travers la synthèse et la recherche. Les corrections et les dates contradictoires doivent y garder leur provenance et leur incertitude. Les intervalles (« from X to Y ») en font partie.
CI autopilot : tranche 4 dans #926 (Refs #717, pas Closes ; commit 8d17252).
Tranche 4, les intervalles. stated_event_time lit maintenant « from D1 to|until|till|through D2 » et « between D1 and D2 » comme un intervalle fermé. « since D » donne un début avec une fin inconnue, « until|till D » une fin avec un début inconnu. Chaque borne garde sa précision et son fuseau écrits.
Restent unknown : les intervalles abrégés (« from 10 to 12 March 2026 », « 10-12 March 2026 »), parce que copier le mois et l'année de la seconde borne inventerait ce que la phrase ne dit pas. Restent aussi unknown une fin avant le début et une paire où une seule borne indique un fuseau.
Ce que j'ai vérifié : 75 tests du module passent, ainsi que 140 tests voisins (1 ignoré). La porte de mutation locale donne 203 mutants tués sur 204 ; le survivant est enregistré comme équivalent par construction dans memory/mutation-equivalents.json. ruff et la porte craftsmanship sont OK.
Pas vérifié : la suite complète, pyright et les variantes PostgreSQL (torch ne se télécharge pas dans cet environnement). La CI fera foi.
Tranches restantes :
Recherche : wiki_view ne peut ni sélectionner ni filtrer event_time sur claim_events. Avant de coder, il faut une décision : comment comparer des bornes de précisions différentes (un mois contre un jour) et des valeurs naïves contre des valeurs avec fuseau.
Synthèse : les brouillons référencent leurs claims par claim_ids, donc event_time reste joignable. _claims_for_memory ne le lit pas encore, et wiki_frontmatter n'accepte pas de dictionnaire imbriqué.
Corrections et dates contradictoires (critère 3) : chaque claim garde son propre event_time et supersedes, mais aucun test ne le prouve encore de bout en bout.
CI autopilot : tranche 5 dans #927 (Refs #717, pas Closes ; commit b308854).
Tranche 5, critère 3 (corrections et dates contradictoires). Un test bout-en-bout wiki_extract → wiki_resolve sur SQLite prouve que la résolution écrit supersedes et des memos sans toucher event_time : la claim remplacée garde sa date plus ancienne, deux dates contradictoires pour la même décision survivent avec leur précision sous un memo conflict_candidate, et une claim sans date reste unknown. Aucun code de production modifié : le comportement était correct mais non prouvé.
Vérifié : 5 tests nouveaux et 172 tests voisins passent (4 ignorés, PostgreSQL absent). Une mutation qui fait réinitialiser event_time par update_claim_supersedes fait échouer 2 des 5 tests. ruff et la porte craftsmanship sont OK.
Pas vérifié : la suite complète, pyright, PostgreSQL (torch ne se télécharge pas ici). La CI fera foi.
Observation hors périmètre : le résolveur ordonne la supersession par extracted_at, pas par event_time. Une correction extraite avant la claim qu'elle corrige ne la remplacerait pas.
Tranches restantes :
Recherche : wiki_view sur event_time (décision à prendre sur la comparaison de bornes de précisions et de fuseaux différents).
Synthèse : _claims_for_memory ne lit pas event_time, wiki_frontmatter n'accepte pas de dictionnaire imbriqué.
CI autopilot : en attente d'une décision (autopilot:hold).
Les tranches 1 à 5 sont fusionnées (dernières : #926, #927). Les trois critères d'acceptation ont chacun un test : date historique distincte de extracted_at, aller-retour point/intervalle/inconnu avec précision et fuseau, corrections et dates contradictoires sans date inventée. Les trois tranches restantes demandent chacune un choix que le code ne peut pas faire seul :
Synthèse (wiki_synthesize._claims_for_memory, draft_synthesizer) : un brouillon agrège plusieurs claims, chacune avec son propre event_time. Quelle date la page porte-t-elle ? Options : (a) aucune au niveau page, event_time par claim dans la provenance des sections ; (b) une date de page seulement si toutes les claims datées ont le même event_time, sinon unknown ; (c) l'enveloppe min/max des bornes, ce qui exige de comparer des précisions différentes (mois contre jour). (b) et (c) imposent aussi un frontmatter imbriqué, que shared/wiki_frontmatter._format_frontmatter refuse aujourd'hui (« keep metadata flat »).
Recherche (wiki_view sur event_time) : comment comparer « March 2026 » à « 2026-03-12 » ou une borne naïve à une borne avec décalage (recouvrement, inclusion, ou exclusion des bornes incomparables) ?
Intervalles abrégés (« 10-12 March 2026 ») : les lire en copiant mois et année de la seconde borne, ou les laisser unknown comme aujourd'hui ?
Une réponse sur l'un de ces points (ou la décision de fermer l'issue avec la limite documentée, comme le prévoit sa section Alternatives considered) suffit à relancer l'autopilot.
Décision : cette issue n'attend plus de réponse du propriétaire.
Le propriétaire a demandé le 12 novembre 2026 que les issues avancent sans lui ; il ne répondra pas aux questions posées ici. Ce commentaire de cdeust lève le hold et précise la demande. Il vaut pour toute la suite de cette issue.
Tranche toi-même chaque question restée ouverte : d'abord une décision écrite et acceptée du dépôt (ADR accepté, docs/), puis ce que le texte de l'issue propose ou exclut, puis les standards du dépôt ; à défaut, la plus petite tranche qui réalise ce que l'issue demande. Une valeur qui manque se mesure, elle ne s'invente pas.
Écris la décision dans un commentaire marqué <!-- ci-autopilot decision --> (ce qui est retenu, la raison et sa source, ce qui est écarté, comment revenir en arrière), puis livre la tranche dans une PR. Une décision écrite ne se rejoue pas aux passages suivants.
Ne repose pas autopilot:hold pour une question : seulement pour l'irréversible, un accès que tu n'as pas, une dépendance nommée encore ouverte ou le plafond de tentatives, en nommant exactement ce qui manque.
Jamais de tag, de release, de montée de version du projet ni de déclenchement manuel d'un workflow.
Hold autopilot:hold levé : un commentaire de cdeust (« Décision : cette issue n'attend plus de réponse du propriétaire », 12/11/2026) a été posté après la pose du hold.
Activity
feat(wiki): keep a claim's event time apart from its extraction time (#…
cdeust commentedon Nov 5, 2026
CI autopilot : première tranche livrée dans #875 (
Refs #717, pasCloses).Tranche 1 : le contrat.
ClaimEvent.event_time(EventTime:unknown/point/interval, chaque borne avec sa valeur, sa précision ISO 8601 et, si la source l'énonce, son décalage horaire). Valeur par défautunknown, jamais dérivée deextracted_at. Les validateurs refusent une précision inventée, des bornes contraires au type, un intervalle inversé ou mêlant bornes avec et sans zone. 18 tests ajoutés, 825 tests voisins passent ; suite complète et pyright non lancés ici (pile torch non installable dans cet environnement), la CI fera foi.Tranches restantes :
event_timedanswiki.claim_events(PostgreSQL et SQLite), migration unique.core/claim_extractorviashared/temporal_normalize, avec leur précision, sans repli surextracted_at.Generated by Claude Code
feat(wiki): keep a claim's event time apart from its extraction time (#…
cdeust commentedon Nov 5, 2026
CI autopilot : tranche 2 dans #894 (
Refs #717, pasCloses).Tranche 2 : la persistance.
wiki.claim_events.event_timecontient le JSON d'EventTime(JSONBsous PostgreSQL,JSONsous SQLite). Une borne sans zone reste sans zone, une borne avec zone garde son décalage, ce qu'une paireTIMESTAMPTZaurait ramené en UTC. Les bases existantes migrent une fois et leurs lignes se lisentunknown.wiki_extractécrit le champ. 4 tests SQLite passent (ils échouent surmain) ; les variantes PostgreSQL et la suite complète n'ont pas pu tourner ici (pas de pgvector, torch non téléchargeable), la CI fera foi.Tranches restantes :
core/claim_extractorviashared/temporal_normalize, avec leur précision, sans repli surextracted_at.Generated by Claude Code
fixup! feat(wiki): persist a claim's event time in wiki.claim_events (#…
fixup! feat(wiki): persist a claim's event time in wiki.claim_events (#…
fixup! feat(wiki): persist a claim's event time in wiki.claim_events (#…
feat(wiki): persist a claim's event time in wiki.claim_events (#717, …
cdeust commentedon Nov 6, 2026
CI autopilot : la tranche 3 est dans #923 (
Refs #717, pasCloses).Tranche 3, l'extraction.
extract_claimsremplit maintenantevent_timeavec la date que la phrase de la claim énonce, à la précision où elle est écrite. « March 2026 » donne un mois. « 12 March 2026 » et « March 12, 2026 » donnent un jour. Les formats ISO 8601 étendus donnent un mois, un jour, une minute ou une seconde, avec leur décalage s'il est indiqué (sinon la valeur reste naïve). Ces cas restentunknown: pas de date, une année seule, une date relative, une date ou un décalage impossible, des fractions de seconde, ou deux dates différentes dans la même phrase. La valeur n'est jamais prise dansextracted_at.Je n'ai pas réutilisé
normalize_date_to_iso: il complète les composants absents. Mesuré le 2026-11-06 : « March 2026 » donne 2026-03-06, et « 2019 » donne 2019-11-06.Ce que j'ai vérifié : les 35 nouveaux tests passent, ainsi que 1321 tests voisins (25 ignorés). La porte de mutation sur les lignes modifiées donne 0 échec, et la porte craftsmanship est OK.
Pas vérifié : la suite complète, pyright et les variantes PostgreSQL (torch ne se télécharge pas dans cet environnement). La CI fera foi.
Tranche restante : porter le champ à travers la synthèse et la recherche. Les corrections et les dates contradictoires doivent y garder leur provenance et leur incertitude. Les intervalles (« from X to Y ») en font partie.
Generated by Claude Code
fixup! feat(wiki): extract_claims reads a claim's stated event time (#…
fixup! feat(wiki): extract_claims reads a claim's stated event time (#…
feat(wiki): extract_claims reads a claim's stated event time (#717, s…
feat(claims): extract stated event intervals with each bound's own pr…
cdeust commentedon Nov 7, 2026
CI autopilot : tranche 4 dans #926 (
Refs #717, pasCloses; commit 8d17252).Tranche 4, les intervalles.
stated_event_timelit maintenant « from D1 to|until|till|through D2 » et « between D1 and D2 » comme un intervalle fermé. « since D » donne un début avec une fin inconnue, « until|till D » une fin avec un début inconnu. Chaque borne garde sa précision et son fuseau écrits.Restent
unknown: les intervalles abrégés (« from 10 to 12 March 2026 », « 10-12 March 2026 »), parce que copier le mois et l'année de la seconde borne inventerait ce que la phrase ne dit pas. Restent aussiunknownune fin avant le début et une paire où une seule borne indique un fuseau.Ce que j'ai vérifié : 75 tests du module passent, ainsi que 140 tests voisins (1 ignoré). La porte de mutation locale donne 203 mutants tués sur 204 ; le survivant est enregistré comme équivalent par construction dans
memory/mutation-equivalents.json. ruff et la porte craftsmanship sont OK.Pas vérifié : la suite complète, pyright et les variantes PostgreSQL (torch ne se télécharge pas dans cet environnement). La CI fera foi.
Tranches restantes :
wiki_viewne peut ni sélectionner ni filtrerevent_timesurclaim_events. Avant de coder, il faut une décision : comment comparer des bornes de précisions différentes (un mois contre un jour) et des valeurs naïves contre des valeurs avec fuseau.claim_ids, doncevent_timereste joignable._claims_for_memoryne le lit pas encore, etwiki_frontmattern'accepte pas de dictionnaire imbriqué.event_timeetsupersedes, mais aucun test ne le prouve encore de bout en bout.Generated by Claude Code
fixup! feat(claims): extract stated event intervals with each bound's…
fixup! feat(claims): extract stated event intervals with each bound's…
feat(claims): extract stated event intervals with each bound's own pr…
cdeust commentedon Nov 7, 2026
CI autopilot : tranche 5 dans #927 (
Refs #717, pasCloses; commit b308854).Tranche 5, critère 3 (corrections et dates contradictoires). Un test bout-en-bout
wiki_extract→wiki_resolvesur SQLite prouve que la résolution écritsupersedeset des memos sans toucherevent_time: la claim remplacée garde sa date plus ancienne, deux dates contradictoires pour la même décision survivent avec leur précision sous un memoconflict_candidate, et une claim sans date resteunknown. Aucun code de production modifié : le comportement était correct mais non prouvé.Vérifié : 5 tests nouveaux et 172 tests voisins passent (4 ignorés, PostgreSQL absent). Une mutation qui fait réinitialiser
event_timeparupdate_claim_supersedesfait échouer 2 des 5 tests. ruff et la porte craftsmanship sont OK.Pas vérifié : la suite complète, pyright, PostgreSQL (torch ne se télécharge pas ici). La CI fera foi.
Observation hors périmètre : le résolveur ordonne la supersession par
extracted_at, pas parevent_time. Une correction extraite avant la claim qu'elle corrige ne la remplacerait pas.Tranches restantes :
wiki_viewsurevent_time(décision à prendre sur la comparaison de bornes de précisions et de fuseaux différents)._claims_for_memoryne lit pasevent_time,wiki_frontmattern'accepte pas de dictionnaire imbriqué.Generated by Claude Code
test(claims): corrections and contradictory dates keep each claim's o…
cdeust commentedon Nov 7, 2026
CI autopilot : en attente d'une décision (
autopilot:hold).Les tranches 1 à 5 sont fusionnées (dernières : #926, #927). Les trois critères d'acceptation ont chacun un test : date historique distincte de
extracted_at, aller-retour point/intervalle/inconnu avec précision et fuseau, corrections et dates contradictoires sans date inventée. Les trois tranches restantes demandent chacune un choix que le code ne peut pas faire seul :wiki_synthesize._claims_for_memory,draft_synthesizer) : un brouillon agrège plusieurs claims, chacune avec son propreevent_time. Quelle date la page porte-t-elle ? Options : (a) aucune au niveau page,event_timepar claim dans la provenance des sections ; (b) une date de page seulement si toutes les claims datées ont le mêmeevent_time, sinonunknown; (c) l'enveloppe min/max des bornes, ce qui exige de comparer des précisions différentes (mois contre jour). (b) et (c) imposent aussi un frontmatter imbriqué, queshared/wiki_frontmatter._format_frontmatterrefuse aujourd'hui (« keep metadata flat »).wiki_viewsurevent_time) : comment comparer « March 2026 » à « 2026-03-12 » ou une borne naïve à une borne avec décalage (recouvrement, inclusion, ou exclusion des bornes incomparables) ?unknowncomme aujourd'hui ?Une réponse sur l'un de ces points (ou la décision de fermer l'issue avec la limite documentée, comme le prévoit sa section Alternatives considered) suffit à relancer l'autopilot.
Generated by Claude Code
cdeust commentedon Nov 12, 2026
Décision : cette issue n'attend plus de réponse du propriétaire.
Le propriétaire a demandé le 12 novembre 2026 que les issues avancent sans lui ; il ne répondra pas aux questions posées ici. Ce commentaire de
cdeustlève le hold et précise la demande. Il vaut pour toute la suite de cette issue.docs/), puis ce que le texte de l'issue propose ou exclut, puis les standards du dépôt ; à défaut, la plus petite tranche qui réalise ce que l'issue demande. Une valeur qui manque se mesure, elle ne s'invente pas.<!-- ci-autopilot decision -->(ce qui est retenu, la raison et sa source, ce qui est écarté, comment revenir en arrière), puis livre la tranche dans une PR. Une décision écrite ne se rejoue pas aux passages suivants.autopilot:holdpour une question : seulement pour l'irréversible, un accès que tu n'as pas, une dépendance nommée encore ouverte ou le plafond de tentatives, en nommant exactement ce qui manque.Règle complète : #343 (comment)
Écrit par la session « écosystème autonome » sur instruction du propriétaire (12 novembre 2026).
Generated by Claude Code
cdeust commentedon Nov 12, 2026
Hold
autopilot:holdlevé : un commentaire decdeust(« Décision : cette issue n'attend plus de réponse du propriétaire », 12/11/2026) a été posté après la pose du hold.Generated by Claude Code