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
Release v3.5.1: read the lunar columns as numbers, not as text
The Hijri columns are DOUBLE in the parquet, and every code path that rendered
them as text cast straight to VARCHAR. CAST(3.0 AS VARCHAR) is '3.0', and
DuckDB's lpad TRUNCATES a string already longer than the target width instead of
leaving it alone, so lpad(CAST(hijri_month AS VARCHAR), 2, '0') produced '3.'
rather than '03'. Months 10, 11 and 12 came out '10', '11', '12' by accident,
which is exactly why the fault survived: three of the twelve buckets looked
right.
get_temporal_distribution(granularity=lunar_month) therefore returned nine keys
no month_labels entry matches, and the charts.html lunar view drew three bars out
of twelve — 4,563 of the 13,261 dated articles. Nothing errored anywhere. The
chart's annotation then divided that truncated total by twelve and reported "Dhu
al-Hijja leads at 1854 (+388% vs an even split)", a figure produced entirely by
the missing bars: Ramadan actually leads at 1918, and the real spread is +74%.
The hijri month and year branches were malformed the same way, as '1420.0-3.'
and '1420.0'.
HIJRI_DATE_EXPR carried the identical bug with a wider blast radius. It builds
the hijri_date field on every article and publication row, and because the year
part is unpadded there was no accidental-pass case at all: all 13,261 values were
malformed, reading 1440.0-3.-29 instead of 1440-03-29. That is the one users saw
most and the one nothing was checking.
Both now go through hijriPart(), which carries the DOUBLE -> INTEGER cast in one
place with the reason attached, so the two call sites cannot drift apart again.
It is also robust to the columns changing type: CAST('03' AS INTEGER) is still 3.
The reason the suite never caught any of this is the fixture, not the assertions.
make-fixtures declared the three columns BIGINT while the real parquet stores
DOUBLE, and CAST(3 AS VARCHAR) is '3' — so the fixtures rendered every bucket and
every date correctly no matter how the SQL was written, and could not reproduce
this class of bug at all. Typing them DOUBLE reproduces all four failures on
unmodified source. That change is worth more than the fix it caught.
On top of it, the lunar_month check now asserts the two key sets as a contract:
month_labels is exactly 01..12, and every distribution key is present in it. A
bucket key that misses is not an error anywhere in the stack — it is a bar that
silently never draws — so it has to be asserted rather than inferred from counts.
The weekly live smoke test pins counts but never cross-checked the two sets,
which is why its pins stayed green throughout.
The README and skill figures are re-measured against the corrected output:
Ramadan +74%, Dhu al-Hijja +68%, Shawwal +42% over 13,261 fully-dated articles,
with the six ordinary months 24-32% below an even split. Rabi' I holds at -5%, so
the Maouloud finding is unchanged. The stated conversion rate moves 98.9% -> 99%
with the current dataset; that one is drift, not this bug.
Copy file name to clipboardExpand all lines: .agents/skills/iwac-mcp/SKILL.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -247,4 +247,4 @@ only items that happen to mention it.
247
247
7.**Publications are mostly entire issues.** Individual articles within an issue are not separated; use the table of contents where one exists (17 of 25 series) and `get_publication_fulltext` keyword excerpts to localise content inside an issue.
248
248
8.**Mind the 1990-91 press-system break.** Pre-1991 articles (~11% of the corpus) come almost entirely from state or single-party organs; the private press only emerges with political liberalisation. Temporal comparisons crossing 1990 compare two different press systems (see biases-and-limitations.md §6).
249
249
9.**Full text is masked per item, and the newest items are not yet enriched.** The server reads the *public* dataset, where OCR ships only for items whose content is public on islam.zmo.de — about **56% of articles** (7,546/13,397) and **86% of publications** (1,298/1,501). Titles and subjects cover every item; AI abstracts cover every item the enrichment pass has reached. Ingestion runs ahead of that pass, so the most recent arrivals (~1,050 articles at the 2026-08 refresh) carry metadata only — no OCR, no `description_ai`, no sentiment, no topic — and because results come back newest-first, they occupy page 1 of an unfiltered `search_articles`. Nothing is invisible to discovery, but a triage pass built on `description_ai` should bound its dates rather than assume every row carries one. Read `fulltext_coverage` from `get_collection_stats`, treat keyword totals as a **floor rather than a census**, and say so whenever a count carries an argument.
250
-
10.**A lunar-month count is not seasonality.**`granularity="lunar_month"` pools every Hijri year, so it deliberately mixes Gregorian seasons: a Ramadan peak is an observance effect, never a weather or school-year one. It also needs a complete `YYYY-MM-DD` — items dated only to a year or month land in `imprecise_date_count` and are **absent from the bars, not zero** (98.9% of articles and 82.9% of publications convert). Lunar dates do not exist for `references`.
250
+
10.**A lunar-month count is not seasonality.**`granularity="lunar_month"` pools every Hijri year, so it deliberately mixes Gregorian seasons: a Ramadan peak is an observance effect, never a weather or school-year one. It also needs a complete `YYYY-MM-DD` — items dated only to a year or month land in `imprecise_date_count` and are **absent from the bars, not zero** (99% of articles and 82.9% of publications convert). Lunar dates do not exist for `references`.
Copy file name to clipboardExpand all lines: .agents/skills/iwac-mcp/references/tools-by-phase.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -63,7 +63,7 @@ Primary search tool for the 12,287 newspaper articles.
63
63
-`newspaper` (optional): substring match
64
64
-`subject` (optional): substring match on the pipe-separated curated tags
65
65
-`date_from` / `date_to` (optional): `YYYY-MM-DD` or `YYYY` (day precision)
66
-
-`hijri_month` / `hijri_year` (optional) *(v1.3.0+)*: Islamic (Umm al-Qura) lunar date. `hijri_month` takes 1–12 or a name in either transliteration (`Ramadan`, `Chaabane`, `Chawwal`, `Dhou al-hijja`), accent- and case-folded; a misspelling errors with `valid_values`. Matches only articles with a complete `YYYY-MM-DD` (98.9%). This is how you read the items behind a `granularity="lunar_month"` peak — and it beats keyword-searching an observance name, which finds items *mentioning* it rather than items *published during* it.
66
+
-`hijri_month` / `hijri_year` (optional) *(v1.3.0+)*: Islamic (Umm al-Qura) lunar date. `hijri_month` takes 1–12 or a name in either transliteration (`Ramadan`, `Chaabane`, `Chawwal`, `Dhou al-hijja`), accent- and case-folded; a misspelling errors with `valid_values`. Matches only articles with a complete `YYYY-MM-DD` (99%). This is how you read the items behind a `granularity="lunar_month"` peak — and it beats keyword-searching an observance name, which finds items *mentioning* it rather than items *published during* it.
67
67
-`with_description` (optional, boolean): include each article's ~500-char AI abstract (`description_ai`) — ~125 tokens/row, pair with limit ≤ 10
68
68
-`limit` (default 20, max 100 — 10 and 25 with `with_description`, since 100 rows carrying abstracts overrun the client's tool-result cap), `offset`
@@ -215,12 +215,12 @@ Counts of matching items per year (or month) — one call replaces paging throug
215
215
216
216
#### The Islamic calendar *(v1.3.0+)*
217
217
218
-
**Reach for `granularity="lunar_month"` for any observance question.** It pools every year into the twelve lunar months, and it is the only bucket a Gregorian axis structurally cannot produce: the Hijri year drifts ~11 days annually, so across 1961–2025 each observance smears over all twelve Gregorian months and disappears. Measured over the 12,220 fully-dated articles, the archive's rhythm is unmistakable — **Ramadan +72 %, Dhu al-Hijja +70 %** (hajj and Tabaski), **Shawwal +44 %** (Korité, 1 Shawwal) against an even split, with the six ordinary months 24–35 % below it. **Rabi' I is flat (−5 %)**, so Maouloud is *not* treated as a news event the way the others are — a finding in its own right.
218
+
**Reach for `granularity="lunar_month"` for any observance question.** It pools every year into the twelve lunar months, and it is the only bucket a Gregorian axis structurally cannot produce: the Hijri year drifts ~11 days annually, so across 1961–2025 each observance smears over all twelve Gregorian months and disappears. Measured over the 13,261 fully-dated articles, the archive's rhythm is unmistakable — **Ramadan +74 %, Dhu al-Hijja +68 %** (hajj and Tabaski), **Shawwal +42 %** (Korité, 1 Shawwal) against an even split, with the six ordinary months 24–32 % below it. **Rabi' I is flat (−5 %)**, so Maouloud is *not* treated as a news event the way the others are — a finding in its own right.
219
219
220
220
-`lunar_month` implies `calendar="hijri"`; you do not have to pass both (and `lunar_month` + `calendar="gregorian"` is refused as incoherent).
221
221
-`calendar="hijri"` with `granularity="year"` or `"month"` gives a Hijri *time series* instead (`1440`, `1440-09`).
222
222
- Keys are zero-padded month numbers (`"01"`…`"12"`) so they sort; `month_labels` maps them to names — use it rather than hard-coding a transliteration.
223
-
-**Precision.** Lunar dates need a complete `YYYY-MM-DD`. Items dated only to a year or month (or a `1981-04/1981-06` range) appear in `imprecise_date_count` and are **absent from the distribution, not zero** — 98.9 % of articles and 82.9 % of publications convert, so the gap is small but must be disclosed when a count carries an argument.
223
+
-**Precision.** Lunar dates need a complete `YYYY-MM-DD`. Items dated only to a year or month (or a `1981-04/1981-06` range) appear in `imprecise_date_count` and are **absent from the distribution, not zero** — 99 % of articles and 82.9 % of publications convert, so the gap is small but must be disclosed when a count carries an argument.
224
224
-**Not seasonality.** Pooling by lunar month deliberately mixes Gregorian seasons; a Ramadan peak is an observance effect, never a weather or school-year one.
225
225
-**Not available on `references`** — an academic imprint date has no meaningful lunar reading, so asking returns `{error, note}` naming the subsets that do carry lunar dates (articles, publications, documents, audiovisual, images).
226
226
-**Converter.** Umm al-Qura, precomputed in the dataset pipeline with `hijridate` — the same converter (and therefore the same buckets) as the on-this-day block on islam.zmo.de. This matters: ICU/`Intl` disagrees with it on **75 % of this collection's pre-2000 dates**, though on only 0.86 % of the *month* assignments, so month-level aggregates are robust while day-level labels are not.
Copy file name to clipboardExpand all lines: mcpb/manifest.json
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -2,7 +2,7 @@
2
2
"manifest_version": "0.3",
3
3
"name": "iwac-mcp-server",
4
4
"display_name": "Islam West Africa Collection (IWAC)",
5
-
"version": "3.5.0",
5
+
"version": "3.5.1",
6
6
"description": "Read-only access to the Islam West Africa Collection via Hugging Face datasets.",
7
7
"long_description": "Search and analyse the Islam West Africa Collection (IWAC): ~12,000 newspaper articles, 1,500 Islamic publications (searchable by keyword, subject, series, and table of contents), 4,700 index entries, plus audiovisual recordings, fieldwork photographs, archival documents, and academic references. Includes AI sentiment analysis (polarity/centrality/subjectivity, scored independently by gpt-5-6-luna, mistral-small-2603, deepseek-v4-flash-0731, gemma-4-31b-it and qwen3-8-27b), per-article AI abstracts, and per-year coverage timelines. All matching is accent- and case-insensitive.\n\n**No API key is required for the core tools** (cross-subset search/fetch, keyword search, filtering, statistics, timelines, item details). Three optional semantic-search tools use Gemini embeddings — over all articles, the publication series with tables of contents, and the photographs (cross-modal: describe what an image shows) — and need a free Google/Gemini API key; these are disabled by default.\n\nOn first use the server downloads ~250 MB of parquet data from Hugging Face into a local cache.",
0 commit comments