Skip to content

feat(wiki): extract_claims reads a claim's stated event time (#717, slice 3) - #923

Merged
github-actions[bot] merged 3 commits into
mainfrom
fix/717-stated-event-time
Nov 7, 2026
Merged

github-actions[bot] merged 3 commits into
mainfrom
fix/717-stated-event-time

Conversation

@cdeust

@cdeust cdeust commented Nov 6, 2026

Copy link
Copy Markdown
Owner

Summary

Slice 3 of #717. ClaimEvent.event_time exists (slice 1, #875) and is persisted (slice 2, #894), but extract_claims never set it: every extracted claim stayed unknown, even when its sentence states a date. The new core/claim_event_time.stated_event_time reads the date written in the claim's own sentence, at the precision written, and extract_claims passes it to each ClaimEvent.

Refs #717 (not Closes: slice 4, carrying the field through synthesis and retrieval, remains).

Root cause and design. Nothing turned a stated date into an EventTime. shared/temporal_normalize.normalize_date_to_iso is not reused: it fills the components a source leaves out. Measured 2026-11-06 (CPython 3.11, dateutil from uv.lock): "March 2026" gives 2026-03-06 and "2019" gives 2019-11-06. That is the invented precision TimeBound refuses. What gets read:

  • March 2026 gives month precision. 12 March 2026, March 12, 2026 and March 12 2026 give day precision. Month names must be capitalised, so the modal "may" is never read as a month.
  • ISO 8601 extended YYYY-MM, YYYY-MM-DD, …THH:MM and …THH:MM:SS give month, day, minute and second precision. A stated offset (Z, ±HH:MM, ±HHMM) is kept. With no stated zone, the value stays naive.
  • These stay unknown, because reading them would mean inventing something: no date at all, a bare year (it cannot be told apart from a citation like "Smith 1992"), a relative date, an impossible date or offset, fractional seconds (finer than TemporalPrecision), and a sentence with two different dates. The same date written twice counts as one point.

Type of change

  • New feature (non-breaking change which adds functionality)

Test plan

  • pytest tests_py/core/test_claim_event_time.py: 35 passed (new).
  • Tests near claims, the wiki and event time (tests_py/shared/test_wiki_ir_event_time.py, tests_py/infrastructure/test_claim_event_time_persistence.py and every test file that mentions claim/wiki_extract): 1321 passed, 25 skipped (PostgreSQL is not available here).
  • Mutation gate on the changed lines (ADR-1122), GITHUB_BASE_REF=main python scripts/ci_mutation_diff.py: 2 file(s), 0 failed, 0 untested. A first version left 7 survivors: dead "year"/"hour" entries and a redundant overlap check. The code was simplified so they cannot occur (an exact precision table, a single alternation regex). No equivalents were registered.
  • python scripts/check_craftsmanship.py: OK. ruff check and ruff format --check (0.17.3, pinned in uv.lock) pass on the changed files. The 8 E501 errors and 7 unformatted files reported across the repo are the same on main.
  • A historical event extracted today keeps its date separate from extracted_at (test_a_historical_event_keeps_its_date_apart_from_extraction).

Not verified here: the full suite and pyright (torch cannot be downloaded through this environment's proxy), and the PostgreSQL variants. CI is the reference.

Audit notes

Coding-standards compliance

  • §2.2 core/claim_event_time.py imports only shared/ and the stdlib.
  • §4.1/§4.2 107 lines; every function under 40 lines.
  • §8 Each pattern and table cites ISO 8601-1:2019 or the issue.

Breaking changes

None. Claims without a stated date keep {"kind": "unknown"}.

Reviewer checklist

  • CHANGELOG.md updated under the appropriate section.

Generated by Claude Code

…lice 3)

ClaimEvent.event_time (slice 1) is persisted (slice 2) but extract_claims
never set it, so every extracted claim stayed unknown even when its sentence
states a date. core/claim_event_time.stated_event_time reads the date the
sentence writes, at the precision written: "March 2026" is a month, "12 March
2026" or "March 12, 2026" a day, ISO 8601 extended dates and times a month,
day, minute or second, with their stated offset (naive when none is stated).

shared/temporal_normalize.normalize_date_to_iso is not reused: it fills the
components a source omits ("March 2026" -> 2026-03-06, "2019" -> 2019-11-06,
measured 2026-11-06), the invented precision TimeBound refuses.

No date, a bare year, a relative date, an impossible date or offset,
fractional seconds, or two different dates in one sentence leave the event
time unknown; it is never derived from extracted_at.

Refs #717

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018kyZYu4w7Hd9Zs3AWTyLgR
@claude

claude Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

Claude finished @cdeust's task in 2m 44s —— View job


PR #923 review (1 of 3)

  • Read the diff and the repo rules (CLAUDE.md)
  • Ran five reviews: code quality, performance, test coverage, documentation accuracy, security
  • Checked each finding against the code and kept only the ones that hold up
  • Posted the review as a PR comment (link)

No Blockers. The review lists 3 Notes that need no action before merge:

  1. Offset minutes above 59 aren't rejected: +05:99 becomes +06:39.
  2. Short year ranges such as "2010-11" are read as a month.
  3. Fractional seconds written with a comma (10:30:15,5) still match at second precision, although the docstring says fractional seconds stay unknown.

I traced these by hand; I couldn't run Python in this environment.

Verdict: approve
· Branch: fix/717-stated-event-time

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cdfe08eb13

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +64 to +66
digits = raw[1:].replace(":", "")
delta = timedelta(hours=int(digits[:2]), minutes=int(digits[2:]))
return timezone(-delta if raw[0] == "-" else delta)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate offset minutes before constructing the timedelta

When a claim contains an invalid offset such as 2026-03-12T10:30+01:99, the regex accepts it and timedelta normalizes the offset to +02:39; timezone does not reject it because the total remains below 24 hours. Consequently, extraction records a definite event time with an invented offset instead of leaving the impossible timestamp unknown. Validate the minute component before constructing the duration, and raise ValueError for out-of-range values so the existing fallback handles them.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrigé dans 7efde80. _offset rejette maintenant des minutes au-delà de 59 (_MAX_OFFSET_MINUTE, ISO 8601-1:2019 §5.3.4). Le ValueError fait tomber l'heure à unknown. Test ajouté : +05:60 donne unknown, +05:59 reste un décalage valide.


Generated by Claude Code

Comment thread mcp_server/core/claim_event_time.py Outdated
_ISO_RE = re.compile(
r"(?<![\w-])(\d{4})-(\d{2})(?:-(\d{2})"
r"(?:T(\d{2}):(\d{2})(?::(\d{2}))?(Z|[+-]\d{2}:?\d{2})?)?)?"
r"(?![\w:+-]|\.\d)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Allow a colon delimiter after a complete calendar date

For dated entries such as 2026-03-12: We decided to drop Redis. or Measured on 2026-03-12: latency was 10 ms., the trailing negative lookahead rejects the colon and the regex finds no date. Both entries are classified by extract_claims, but their event times incorrectly remain unknown despite stating a supported, unambiguous ISO day. Distinguish punctuation following a complete calendar date from a colon continuing a time component, rather than excluding colons after every supported form.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrigé dans 7efde80. Le lookahead n'exclut plus qu'un deux-points suivi d'un chiffre ([:.,]\d), c'est-à-dire la suite d'une heure. 2026-03-12: we decided… et Measured on 2026-03: … donnent maintenant un point, et 10:30:15.1 et 10:30:15,5 restent unknown.


Generated by Claude Code

entity_ids=entity_ids or [],
evidence_refs=refs,
confidence=confidence,
event_time=stated_event_time(sent),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep dates in neighboring sentences out of the claim's event time

When a paragraph is shorter than 120 characters, _split_sentences deliberately returns the whole paragraph without splitting its sentences; headings and list paragraphs also bypass sentence splitting. For example, We decided to drop Redis. On March 12, 2026 we measured throughput. produces a decision claim, and this call assigns the measurement's date to that decision even though its own sentence is undated. Ensure temporal extraction operates on the sentence supplying the classified claim, or leave the time unknown when the date belongs to another sentence in an atomic paragraph.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reproduit sur cdfe08e : la claim decision recevait la date de la mesure. Corrigé dans 7efde80. Quand une unité contient plusieurs phrases (paragraphe court, titre ou item de liste gardés entiers), son event_time reste unknown : la date peut appartenir à l'autre phrase. La frontière de phrase n'est définie qu'à un endroit (claim_event_time.SENTENCE_END), et l'extracteur découpe sur cette même définition. Test : test_a_date_in_a_neighbouring_sentence_does_not_date_the_claim.


Generated by Claude Code

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 6, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-07T00:10:26.422552Z 741cdd1 New commits
🔒 Security Review ✅ Completed 2026-11-07T00:10:15.374882Z 741cdd1 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@claude

claude Bot commented Nov 6, 2026

Copy link
Copy Markdown

Review 1 of 3 — PR #923 (cdfe08e)

I ran five reviews: code quality, performance, test coverage, documentation accuracy and security. None found a Blocker.

  • CI and contract: every exception stated_event_time can raise is a ValueError, including pydantic's ValidationError, so extract_claims keeps its never-raises contract.
  • Layers: core/claim_event_time imports only shared and the stdlib.
  • Performance and security: both regexes run in linear time, so there is no ReDoS risk.

The security reviewer raised one concern I dropped. They thought a date past character 1900 could set event_time without appearing in the stored text. That can't happen: _split_sentences caps sentences at 1500 characters before the [:1900] slice.

I traced these by hand; I couldn't run Python here.

Notes, no action before merge

  1. _offset (claim_event_time.py:64) doesn't check the minutes, so +05:99 becomes +06:39, an offset the source never stated. Rejecting minutes above 59 would make it unknown, as the docstring promises.
  2. _ISO_RE reads a short year range as a month: "the 2010-11 season" or "FY2011-12" becomes a month point. Worth adding to the known limitations next to bare years.
  3. The docstring says fractional seconds stay unknown. That only holds with a period: with ISO's comma decimal sign, 10:30:15,5 matches at second precision. Changing the lookahead to [.,]\d would fix it.

Verdict: approve

…717, slice 3)

Codex review on cdfe08e: a short paragraph, heading or list item reaches
stated_event_time whole, so "We decided to drop Redis. On March 12, 2026 we
measured throughput." dated the decision with the measurement's date. A unit
holding several sentences now stays unknown; the sentence boundary is defined
once (claim_event_time.SENTENCE_END) and the extractor splits on it.

Codex review: "2026-03-12: we decided ..." was refused because every colon
after a date was read as a time continuation. Only a colon followed by a digit
is one now.

Claude review 1, Notes 1 and 3: an offset with minutes above 59 ("+05:99") was
accepted as +06:39, and a comma decimal ("10:30:15,5") matched at second
precision; both now leave the event time unknown, as the docstring states.
Note 2 (a year range such as "2010-11" reads as a month) is documented.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018kyZYu4w7Hd9Zs3AWTyLgR
@claude

claude Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

Claude finished @cdeust's task in 2m 43s —— View job


PR #923 review (2 of 3)

  • Read the diff for 7efde80, the only commit since review 1 (cdfe08e, which found no Blockers), and checked it against the CLAUDE.md rules
  • Ran five reviews in parallel: code quality, performance, test coverage, documentation accuracy, security
  • Checked each finding against the code and kept only the ones that hold up
  • Posted the review (link)

No Blockers. The fixup does what it says for each review comment. The review lists 3 Notes that need no action before merge:

  1. Headings and list items split by a newline are still read as one sentence, so "# Release 2026-03\nWe decided to drop Redis." dates the decision. The docstring and CHANGELOG say such units stay unknown.
  2. The new lookahead turns "2026-03-12,2026-03-13" into point 2026-03-13; before this commit it was unknown.
  3. No positive test has an ISO date followed by . or ,.

I traced these by hand; I couldn't run Python in this environment.

Verdict: approve
· Branch: fix/717-stated-event-time

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7efde809a5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +119 to +122
distinct = {(b.value, b.value.utcoffset(), b.precision): b for b in bounds}
if len(distinct) != 1:
return EventTime()
return EventTime(kind="point", start=next(iter(distinct.values())))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Leave abbreviated date ranges unknown

For a claim such as We measured throughput from 10 to 12 March 2026., the named-date matcher recognizes only 12 March 2026, so this return assigns a definite point on March 12 even though the measurement explicitly spans multiple days. The same happens with between 10 and 12 March 2026. Checking the number of complete date matches does not detect ranges whose endpoints share a month and year; reject these range constructions before promoting the matched endpoint to a point, keeping them unknown until interval extraction is supported.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reproduit sur 7efde80, corrigé dans 741cdd1. Une phrase qui énonce un intervalle à côté d'une date (from 10 to 12 March 2026, between 10 and 12 March 2026, 10-12 March 2026, 10–12 March 2026, since 2026-01, until March 2026) reste unknown (_RANGE_RE), en attendant l'extraction des intervalles. We switched from Redis on 2026-03-12. reste un point, parce que from n'y précède pas une date.


Generated by Claude Code

Comment on lines +90 to +92
for m in _ISO_RE.finditer(sentence):
parts = [int(g) for g in m.groups()[:6] if g is not None]
bounds.append(_bound(parts, _offset(m.group(7))))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Exclude reference targets from event-date matching

When a claim contains a dated URL or file path, scanning the raw sentence treats the reference's date as the claim's event time. For example, extract_claims('We decided to use https://example.org/2026-03-12/redis.') produces a decision dated March 12 even though no decision date is stated; We decided to use ./2026-03-12/report.md as the source. behaves the same way. _extract_evidence already recognizes these spans as URL/file references, but they are not excluded from temporal matching. Mask reference targets before matching dates so an undated claim does not acquire an unrelated reference date.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reproduit sur 7efde80, corrigé dans 741cdd1. Une date ISO ne compte maintenant que si elle forme un mot à elle seule, à la ponctuation près (_is_own_word). Une date prise dans une URL, un chemin ou un nom de fichier (https://example.org/2026-03-12/redis, ./2026-03-12/report.md, 2026-03-12.md) est une référence : elle n'est pas lue. Une vraie date ailleurs dans la phrase reste lue (See ./2026-01-05/log for the 2026-03-12 run. donne le 12 mars).


Generated by Claude Code

@claude

claude Bot commented Nov 6, 2026

Copy link
Copy Markdown

Review 2 of 3: PR #923, 7efde80

Review 1 (cdfe08e) found no Blockers, so there was nothing to re-check. This review covers only the fixup commit 7efde80. It ran five reviews: code quality, performance, test coverage, documentation accuracy and security. None found a Blocker.

  • What 7efde80 gets right:
    • An offset with minutes above 59 (+05:60) now stays unknown, and the test covers both sides of the boundary (+05:59 passes, +05:60 does not).
    • Comma fractions (10:30:15,5) now stay unknown.
    • 2026-03-12: … is now read as a date.
    • The units the extractor keeps whole (short paragraphs, headings, list items) stay unknown when they hold several sentences ending in ., ! or ?.
  • Contract and layers: every exception on the parsing path is still a ValueError and is caught, so extract_claims still never raises. Moving SENTENCE_END into core/claim_event_time keeps the layers intact (core → core), and the constant has its # source: line.
  • Performance and security: all three regexes still run in linear time, so there is no ReDoS risk. Sentences stay capped at 1500 characters.

I checked these by hand; I couldn't run Python in this environment.

Notes, no action before merge

  1. Units split by a newline are still read as one sentence. extract_claims("# Release 2026-03\nWe decided to drop Redis.") dates the decision as month 2026-03, because SENTENCE_END needs ., ! or ? before the whitespace. The same happens with "- We decided to drop Redis\n- Cache outage on 2026-03-12". The docstring (claim_event_time.py:21-23, :110-111) and the CHANGELOG say these units stay unknown; treating \n inside a unit as a boundary would make that true.
  2. The new lookahead (?![\w+-]|[:.,]\d) (claim_event_time.py:41) drops the first of two dates joined by a comma with no space. "Outages on 2026-03-12,2026-03-13." now gives point 2026-03-13; before this commit it gave unknown. Adding : and , to the lookbehind ((?<![\w:,-])) would make the two sides match.
  3. No positive test has an ISO date followed by . or , ("shipped 2026-03-12.", "On 2026-03-12, we switched."), the most common form in prose. Every positive case is followed by a space or :.

Verdict: approve

…717, slice 3)

Codex review on 7efde80: a date inside a reference dated an undated claim
("We decided to use ./2026-03-12/report.md"); an ISO date now counts only
when it is its own word, punctuation aside. Interval wording next to a date
("from 10 to 12 March 2026", "between ...", "10-12 March", "since 2026-01",
"until March 2026") was promoted to a point on one endpoint; it now stays
unknown until intervals are extracted.

Claude review 2, Note 1: a unit the extractor keeps whole but that spans
lines ("# Release 2026-03\nWe decided ...") lent its date to the claim, which
the docstring said it did not; a unit holding a newline now stays unknown.
Note 2 ("2026-03-12,2026-03-13" read as one point) is closed by the own-word
rule; Note 3 adds the positive cases followed by "." and ",".

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018kyZYu4w7Hd9Zs3AWTyLgR
@claude

claude Bot commented Nov 7, 2026 •

Copy link
Copy Markdown

Claude finished @cdeust's task in 2m 47s —— View job


PR #923 review (3 of 3)

  • Checked the earlier reviews for Blockers: reviews 1 and 2 had none, so there was nothing to re-check
  • Ran five reviews of 741cdd1, the only commit since 7efde80: code quality, performance, test coverage, documentation accuracy, security
  • Traced each finding against the code by hand and kept only the ones that hold up. I couldn't run Python or uv sync because both need approval here.
  • Posted the review (link)

No Blockers. The whole PR is accepted (cdfe08e, 7efde80, 741cdd1). The review lists 3 Notes that need no action before merge:

  1. In hard-wrapped prose, every date now stays unknown. The new newline check also catches a single sentence that wraps inside a long paragraph.
  2. Some interval wording still gives a point. "10 March to 12 March 2026" gives 2026-03-12, and "after 2026-01" gives a month.
  3. ISO dates wrapped in Markdown, such as **2026-03-12** or `2026-03-12`, are dropped, while **12 March 2026** is still read.

Verdict: approve
· Branch: fix/717-stated-event-time

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 741cdd1048

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +63 to +64
rf"(?i:\b(?:from|between|since|until|till|through))\s+(?:\d|(?:{_MONTH_GROUP})\b)"
rf"|\b\d{{1,2}}\s*(?:-|\u2013|\u2014|to|and)\s*\d{{1,2}}\s+(?:{_MONTH_GROUP})\b"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restrict interval detection to temporal ranges

For On March 12, 2026 we improved throughput from 10 to 12 requests per second., extraction returns unknown because this pattern matches from 1, even though the range describes throughput rather than dates. Likewise, On 2026-03-12 we switched from 3 replicas to 5 replicas. loses its explicit event date. Require the interval wording to connect to a date expression instead of rejecting any sentence containing a range introduced by a number.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reproduit sur 741cdd1. Je reporte ce point à une PR de suite, sans le pousser ici : la revue 3/3 a accepté la PR et le budget de trois revues (ADR-1119) est épuisé. Le détail et la correction prévue sont dans #923 (comment).


Generated by Claude Code

Comment on lines +102 to +104
before = re.split(r"\s", sentence[: m.start()])[-1]
after = re.split(r"\s", sentence[m.end() :])[0]
return not before.strip(_OPENERS) and not after.strip(_CLOSERS)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve ISO dates wrapped in Markdown formatting

For Markdown claims such as We decided to drop Redis on `2026-03-12`. or We decided to drop Redis on **2026-03-12**., _is_own_word rejects the date because backticks and emphasis markers are not permitted wrappers. Both claims therefore remain unknown, although the identical unformatted date produces a point; named-month dates do not have this restriction. Recognize Markdown wrappers without treating them as parts of a reference target.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reproduit sur 741cdd1. Je reporte ce point à une PR de suite, sans le pousser ici : la revue 3/3 a accepté la PR et le budget de trois revues (ADR-1119) est épuisé. Le détail et la correction prévue sont dans #923 (comment).


Generated by Claude Code

Comment on lines +56 to +58
rf"\b(?:(?P<day>\d{{1,2}})\s+(?P<month>{_MONTH_GROUP})"
rf"|(?P<month_first>{_MONTH_GROUP})\s+(?P<day_second>\d{{1,2}}),?"
rf"|(?P<month_only>{_MONTH_GROUP}))\s+(?P<year>\d{{4}})\b"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid matching only the month inside an ordinal day date

For We decided to drop Redis on 12th March 2026., the day-first alternative fails on 12th, but the month-only alternative then matches March 2026, producing month precision instead of the stated day. More seriously, We decided to drop Redis on 31st February 2026. becomes a definite February point rather than remaining unknown as an impossible date. Recognize and validate ordinal day components, or prevent the month-only fallback from consuming a suffix of an unsupported day-date expression.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reproduit sur 741cdd1. Je reporte ce point à une PR de suite, sans le pousser ici : la revue 3/3 a accepté la PR et le budget de trois revues (ADR-1119) est épuisé. Le détail et la correction prévue sont dans #923 (comment).


Generated by Claude Code

@claude

claude Bot commented Nov 7, 2026

Copy link
Copy Markdown

Review 3 of 3: PR #923, 741cdd1

Reviews 1 and 2 found no Blockers, so there was nothing to re-check. This review covers only the fixup 741cdd1. It ran five reviews: code quality, performance, test coverage, documentation accuracy and security. None found a Blocker.

  • What 741cdd1 gets right:
    • An ISO date inside a URL, path or file name (https://…/2026-03-12/…, ./2026-03-12/report.md, 2026-03-12.md) is no longer read. A real date elsewhere in the same sentence still is (See ./2026-01-05/log for the 2026-03-12 run.).
    • The forms from/between/since/until … <date> and 10-12 March stay unknown.
    • # Release 2026-03\nWe decided… and newline-separated list items no longer date their neighbour.
    • 2026-03-12,2026-03-13 is unknown again.
    • The three previously missing positive cases with ., , and (…) around the date now have tests.
  • Contract and layers: the new code adds no exception path. re.split(...)[-1]/[0] cannot raise, and extract_claims still never raises. The module imports only shared and the stdlib, it is 146 lines, and every function is under 40 lines.
  • Performance and security: _RANGE_RE runs in linear time, so there is no ReDoS risk. _is_own_word re-splits the prefix for each match, which is quadratic in theory but on the order of milliseconds at the 1500-character sentence cap.

I traced these by hand. I couldn't run Python or uv sync here because both need approval in this environment.

Notes, no action before merge

  1. In hard-wrapped prose, every date now stays unknown. _split_sentences splits paragraphs of 120 characters or more only on SENTENCE_END, so a single wrapped sentence keeps its \n, and "\n" in sentence (claim_event_time.py:135) then rejects it. This throws away correct dates rather than inventing wrong ones. Applying the newline rule only to units kept whole, or treating a wrap as a space, would fix it.
  2. Some interval wording still gives a point. "10 March to 12 March 2026" and "March 10 to March 12, 2026" give 2026-03-12, and "after 2026-01"/"before March 2026" give a month. The docstring and CHANGELOG say interval wording stays unknown.
  3. _is_own_word drops ISO dates wrapped in Markdown (**2026-03-12**, `2026-03-12`), while **12 March 2026** is still read.

Accepted: the whole PR (cdfe08e, 7efde80, 741cdd1; all four files). No open Blockers. The Notes can go to a refinement PR or to slice 4 of #717.

Verdict: approve

cdeust commented Nov 7, 2026

Copy link
Copy Markdown
Owner Author

Points reportés à une PR de suite, pas à celle-ci. La revue 3/3 a accepté la PR entière, sans bloquant. Le budget de trois revues (ADR-1119) est épuisé. Je n'ai donc rien poussé après 741cdd1.

J'ai reproduit chaque point sur 741cdd1. Deux groupes :

Dates perdues. Le résultat est unknown à tort, mais aucune date n'est inventée.

  • Codex : un intervalle numérique qui n'est pas temporel suffit à rejeter la phrase. Exemples : « from 10 to 12 requests per second », « from 3 replicas to 5 ». _RANGE_RE devrait exiger qu'une date suive le mot d'intervalle.
  • Codex et revue 3, Note 3 : une date ISO entourée de Markdown (`2026-03-12`, **2026-03-12**) est rejetée par _is_own_word.
  • Revue 3, Note 1 : dans une prose coupée à la main, la phrase longue qui garde un \n reste unknown. La règle du retour à la ligne ne devrait viser que les unités gardées entières.

Précision ou forme mal lues.

  • Codex : « 12th March 2026 » est lu au mois au lieu du jour, et « 31st February 2026 » n'est pas rejeté comme date impossible. Le mois retenu est celui qu'énonce le texte. Il faut reconnaître et valider les jours ordinaux.
  • Revue 3, Note 2 : « 10 March to 12 March 2026 », « March 10 to March 12, 2026 », « after 2026-01 » et « before March 2026 » donnent encore un point. La docstring et le CHANGELOG annoncent pourtant unknown pour les formulations d'intervalle. C'est le point le plus urgent de la suite, puisqu'il touche ce que la PR affirme.

La PR de suite les traitera ensemble. L'extraction des intervalles, prévue en tranche 4 de #717, remplacera de toute façon _RANGE_RE.


Generated by Claude Code

@github-actions
github-actions Bot merged commit ac30270 into main Nov 7, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants