Compare commits

..

1 Commits

Author SHA1 Message Date
codex-bot 3f0ac694a0 Correct early ACL source candidates and record official index limits
Metadata integrity checks / metadata (push) Successful in 14m52s
2026-11-09 02:28:51 +08:00
8 changed files with 251 additions and 299 deletions
-2
View File
@@ -60,8 +60,6 @@ paper-atlas collect colm --cache /data/paper-index/raw/http-cache \
--out /data/paper-index/collected
```
早期主系列的Workshop名称按[ICML/IROS精确届次证据](docs/coverage/historical-primary-series-2026-11-09.md)识别,保留原名与范围证据;代码支持不代表已补齐生产数据。
`paper-atlas collect --help` 查看来源;`paper-atlas import --help` 查看导入方式。完整批次步骤见[使用指南](docs/usage.md)。
共享实例名为 `foundry-postgres`,数据位于 `foundry_data` 库的 `research` schema;其他项目可按权限复用同一组表。库名通过 libpq service 配置、schema 通过 search_path 或 `--pg-schema` 指定,不写死在查询中。PostgreSQL 凭据放在服务器权限为 `0600` 的 libpq service 文件中;命令行只使用服务名称。`paper-atlas maintain postgres --help` 提供迁移入口:先完整核验 21 张业务表,再发布目标 schema。SQLite FTS5 内部表由 PostgreSQL GIN 索引替代。切换后 SQLite 为只读备份;`import records`、`import arxiv` 和 `maintain backfill` 使用 `--pg-service foundry-research` 写入主库,整个写入会话只允许一个协调写入者,会议文件失败时整体回滚并保留失败批次记录。
+3 -1
View File
@@ -191,4 +191,6 @@ WWW事件标识生产迁移已独立验收(报告SHA `f5dbb8a8`):保留139
IJCAI 联办届次的逐条后续核查见 [2018/2022 分区与目录差集](ijcai-sections-2026-11-08.md) 和 [稳定 ID 映射](ijcai-sections-2026-11-08.json)。已定位 345 条非 main 分类及 2022 官方 HTML 缺失但官方文件仍存在的一条记录;生产分类尚未修正,不能把整卷数量作为 main 覆盖率。
2026年11月9日的[当前历史年度缺口核对](historical-gaps-2026-11-09.md)单列135个历史会议—年份、14个2026年度及89个初步候选来源年度;它使用当前生产edition/别名快照,保留原固定快照不变。年度有记录不等于逐篇、逐track或公开拒稿历史完整。
2026年11月9日的[当前历史年度缺口核对](historical-gaps-2026-11-09.md)单列135个历史会议—年份、14个2026年度及85个经范围修正的初步候选来源年度;它使用当前生产edition/别名快照,保留原固定快照不变。年度有记录不等于逐篇、逐track或公开拒稿历史完整。
[早期NLP来源范围复核](historical-source-scope-2026-11-09.md)保留3份官方网页的响应哈希,排除4个COLING卷对ACL缺口的误匹配,并区分会议举办记录、目录可获取性与论文级覆盖;尚未导入或关闭这些年度缺口。
+4 -2
View File
@@ -27,9 +27,11 @@
## 候选来源与下一步
另一次只读目录核查在现有、已校验的DBLP快照中,为135个历史年度中的**89个**匹配到初步候选论文集,另**46个**尚未按本轮规则匹配到,需要继续识别目录键或寻找官方来源。未匹配不等于会议没举办、未出版或没有公开来源。
另一次只读目录核查在现有、已校验的DBLP快照中,为135个历史年度中的**85个**匹配到初步候选论文集,另**50个**尚未按本轮规则匹配到,需要继续识别目录键或寻找官方来源。未匹配不等于会议没举办、未出版或没有公开来源。
[候选卷清单](historical-source-candidates-2026-11-09.json) 保留卷key、标题、出版年份、原始bibliographic counts和出版者链接。匹配只使用同family的四位卷key年份或卷标题唯一显式年份;两位键、出版年份与会议年份差异、前身系列及其他目录命名可能漏匹配。原始计数可能含workshop、前言、索引或多个卷,**不能当可直接导入的录用论文数量**。
[候选卷清单](historical-source-candidates-2026-11-09.json) 保留卷key、标题、出版年份、原始bibliographic counts和出版者链接。初筛使用目标family映射内的四位卷key年份或卷标题唯一显式年份,再按具体会议身份复核;两位键、出版年份与会议年份差异、前身系列及其他目录命名可能漏匹配。原始计数可能含workshop、前言、索引或多个卷,**不能当可直接导入的录用论文数量**。
后续[来源范围复核](historical-source-scope-2026-11-09.md)排除了4个误归ACL的COLING卷,因此候选年度由89修正为85、未匹配年度由46增至50。原卷及排除理由保留在JSON中;135个历史年度缺口不因此改变。ACL1963–1978与COLING1971/1976/1978在当前Anthology目录未列出,继续记为来源待核实,不能一律称作已公开但漏采的论文集。
优先核查已有候选卷较集中的CVPR22年、ICCV12年、ECCV14年和ICML25年。其中ICML早期workshop名称可能属于官方主系列前身,也可能是附属workshop,须对照官方届次证据逐卷区分,不能靠标题包含workshop一刀切。所有候选须经过范围、稳定标识、重复/冲突、原始字段和覆盖预检;这一步没有导入候选卷。
@@ -1,33 +0,0 @@
# ICML 与 IROS 早期主系列的来源范围
本轮修正采集阶段的届次识别,不修改任何现有生产投稿轨道或历史。正式主系列曾以Workshop命名,不等于附属workshop;也不能反过来把所有旧workshop升为主会。
## 已核实的精确范围
| 会议 | 论文集键 | 依据与行为 |
| --- | --- | --- |
| ICML | `conf/icml/1988`、`1989`、`1990`、`1991`、`1992` | [官方历史](https://icml.cc/Conferences/2008/past_icmls.shtml.html)将其列为第5–9届,年份与举办地对应固定目录中的完整标题。1989/1991/1992的Workshop名称不再导致主系列被默认排除;1988/1990保留main并增加来源范围证据 |
| IROS | `conf/iros/1988`、`1989`、`1990` | [IEEE RAS官方历届目录](https://www.ieee-ras.org/conferences-workshops/financially-co-sponsored/iros/iros-past-and-future-venues/)列出三届与论文集链接,地点及日期对应固定目录标题;这些是IROS主系列 |
规则同时要求family、booktitle基础别名(ML或IROS)、空轨道后缀、完整精确论文集键、匹配的事件年份及固定完整标题。仍执行原有书目年份核查:与事件年不同且标题无明确事件年时拒绝推断。ML91原始标题没有四位年份,使用精确1991卷键、完整标题、逐篇书目年和官方第8届记录,不从两位标题代码猜世纪。
`1991w`/`1988w`等卷键、booktitle中的Workshops后缀、不同届次/地点/完整标题、未列入的年份均不会获得上述主系列豁免。AISTATS/COLT既有精确规则保留;真正的附属workshop仍受默认不采集workshop的边界约束。
## 原始字段、决定与后续导入
采集器仍保存原始proceedings标题(包括Workshop)、书目年、原始作者名、完整来源书目字段及稳定标识;新增 `track_scope_note` 与官方 `track_scope_evidence_url`。接受状态仍只源自该论文的inproceedings书目证据;不从历史目录生成占位论文或拒稿,也不重新导入已经存在的记录。
新规则的输出必须重新做原始来源/标题/作者/稳定标识与现有库冲突预检,再按增量导入。此前被隔离的ICML1988/1990记录不能仅凭代码规则而直接解除全部冲突。当前正在运行的历史批次使用原固定版本和文件,不能在运行中替换其源码或输入。
## 验证与证据
新增回归覆盖:ICML三届Workshop名称、IROS最初三届、ICML原Conference名称的两届、错误卷键/后缀/标题/未知年份,以及归一化记录经过原生文件导入后保留轨道证据。构建与测试仅在已授权的ces-control远程runner执行,本机仅做语法和文本/JSON一致性检查;结果以相应commit的CI回执为准。
官方HTML在工作证据目录 `paper-index/historical-primary-series-evidence-v1/`,附响应状态、字节数、时间与SHA256;仅取元数据网页,没有下载论文全文。
| 来源 | UTC采样时间 | HTTP | 字节数 | SHA256 |
| --- | --- | ---: | ---: | --- |
| [icml-history](https://icml.cc/Conferences/2008/past_icmls.shtml.html) | 2026-11-08T18:36:43.043135+00:00 | 200 | 11993 | `80cce886fe985551339a52b13c4077acf827e8fcc01555f854dc24077bdebdf0` |
| [iros-history](https://www.ieee-ras.org/conferences-workshops/financially-co-sponsored/iros/iros-past-and-future-venues/) | 2026-11-08T18:36:45.687171+00:00 | 200 | 466059 | `fdb4594621e68567e1099f5c88aae53de835b7b8146025148c3b1968df990697` |
本次不关闭历史年度缺口,也不替代全部导入后的全库去重、来源/年度/track覆盖、摘要和实际查询验收。
@@ -6,8 +6,8 @@
"catalogue_readonly": true,
"database_written": false,
"years_total": 135,
"years_with_candidate_volumes": 89,
"years_without_candidate_volumes": 46,
"years_with_candidate_volumes": 85,
"years_without_candidate_volumes": 50,
"venues": [
{
"venue": "ICML",
@@ -950,136 +950,26 @@
1977,
1978
],
"years_with_candidate_volumes": [
1965,
1967,
1969,
1973
],
"years_with_candidate_volumes": [],
"years_without_candidate_volumes": [
1963,
1964,
1965,
1966,
1967,
1968,
1969,
1970,
1971,
1972,
1973,
1974,
1975,
1976,
1977,
1978
],
"candidate_volumes": [
{
"key": "conf/coling/1965",
"family": "coling",
"candidate_event_year": 1965,
"year_basis": "four_digit_volume_key",
"title": "First International Conference on Computational Linguistics, COLING 1965, New York, USA, 1965",
"publication_year": [
"1965"
],
"publisher": [],
"primary_links": [
"https://aclanthology.org/volumes/C65-1/",
"https://aclanthology.org/C65-1000/"
],
"original_dblp_page": [
"db/conf/coling/coling1965.html"
],
"bibliographic_counts": [
{
"bibliographic_year": "1965",
"booktitle": "COLING",
"record_type": "inproceedings",
"count": 24
}
]
},
{
"key": "conf/coling/1967",
"family": "coling",
"candidate_event_year": 1967,
"year_basis": "four_digit_volume_key",
"title": "Second Conference Internationale Sur Le Traitement Automatique Des Langues, COLING 1967, Grenoble, France, August 1967",
"publication_year": [
"1967"
],
"publisher": [],
"primary_links": [
"https://aclanthology.org/volumes/C67-1/",
"https://aclanthology.org/C67-1000/"
],
"original_dblp_page": [
"db/conf/coling/coling1967.html"
],
"bibliographic_counts": [
{
"bibliographic_year": "1967",
"booktitle": "COLING",
"record_type": "inproceedings",
"count": 37
}
]
},
{
"key": "conf/coling/1969",
"family": "coling",
"candidate_event_year": 1969,
"year_basis": "four_digit_volume_key",
"title": "Third International Conference on Computational Linguistics, COLING 1969, Stockholm, Sweden, September 1-4, 1969",
"publication_year": [
"1969"
],
"publisher": [],
"primary_links": [
"https://aclanthology.org/volumes/C69-10/",
"https://aclanthology.org/C69-1000/"
],
"original_dblp_page": [
"db/conf/coling/coling1969.html"
],
"bibliographic_counts": [
{
"bibliographic_year": "1969",
"booktitle": "COLING",
"record_type": "inproceedings",
"count": 94
}
]
},
{
"key": "conf/coling/1973",
"family": "coling",
"candidate_event_year": 1973,
"year_basis": "four_digit_volume_key",
"title": "Computational And Mathematical Linguistics: Proceedings of the 5th International Conference on Computational Linguistics, COLING 1973, Pisa, Italy, August 27 - September 1, 1973",
"publication_year": [
"1973"
],
"publisher": [
"ACL"
],
"primary_links": [
"https://aclanthology.org/volumes/C73-1/",
"https://aclanthology.org/volumes/C73-2/",
"https://aclanthology.org/C73-1000/",
"https://aclanthology.org/C73-2000/"
],
"original_dblp_page": [
"db/conf/coling/coling1973.html"
],
"bibliographic_counts": [
{
"bibliographic_year": "1973",
"booktitle": "COLING",
"record_type": "inproceedings",
"count": 115
}
]
}
]
"candidate_volumes": []
},
{
"venue": "COLING",
@@ -5013,5 +4903,208 @@
"candidate_volumes": []
}
],
"scope": "Potentialbibliographicvolumesonly;notproofmaintrack,formalpublication,paperacceptance,canonicaleventyearorcompletehistory. Workshop/predecessor/multivolume/frontmatter/identifierboundariesneedseparatereview.Noautomaticimport."
"scope": "Potentialbibliographicvolumesonly;notproofmaintrack,formalpublication,paperacceptance,canonicaleventyearorcompletehistory. Workshop/predecessor/multivolume/frontmatter/identifierboundariesneedseparatereview.Noautomaticimport.",
"excluded_cross_venue_candidates": [
{
"requested_venue": "ACL",
"reason": "COLING-only proceedings; no explicit joint ACL edition evidence for this year. Publisher or broad family mapping does not establish event membership.",
"candidate": {
"key": "conf/coling/1965",
"family": "coling",
"candidate_event_year": 1965,
"year_basis": "four_digit_volume_key",
"title": "First International Conference on Computational Linguistics, COLING 1965, New York, USA, 1965",
"publication_year": [
"1965"
],
"publisher": [],
"primary_links": [
"https://aclanthology.org/volumes/C65-1/",
"https://aclanthology.org/C65-1000/"
],
"original_dblp_page": [
"db/conf/coling/coling1965.html"
],
"bibliographic_counts": [
{
"bibliographic_year": "1965",
"booktitle": "COLING",
"record_type": "inproceedings",
"count": 24
}
]
}
},
{
"requested_venue": "ACL",
"reason": "COLING-only proceedings; no explicit joint ACL edition evidence for this year. Publisher or broad family mapping does not establish event membership.",
"candidate": {
"key": "conf/coling/1967",
"family": "coling",
"candidate_event_year": 1967,
"year_basis": "four_digit_volume_key",
"title": "Second Conference Internationale Sur Le Traitement Automatique Des Langues, COLING 1967, Grenoble, France, August 1967",
"publication_year": [
"1967"
],
"publisher": [],
"primary_links": [
"https://aclanthology.org/volumes/C67-1/",
"https://aclanthology.org/C67-1000/"
],
"original_dblp_page": [
"db/conf/coling/coling1967.html"
],
"bibliographic_counts": [
{
"bibliographic_year": "1967",
"booktitle": "COLING",
"record_type": "inproceedings",
"count": 37
}
]
}
},
{
"requested_venue": "ACL",
"reason": "COLING-only proceedings; no explicit joint ACL edition evidence for this year. Publisher or broad family mapping does not establish event membership.",
"candidate": {
"key": "conf/coling/1969",
"family": "coling",
"candidate_event_year": 1969,
"year_basis": "four_digit_volume_key",
"title": "Third International Conference on Computational Linguistics, COLING 1969, Stockholm, Sweden, September 1-4, 1969",
"publication_year": [
"1969"
],
"publisher": [],
"primary_links": [
"https://aclanthology.org/volumes/C69-10/",
"https://aclanthology.org/C69-1000/"
],
"original_dblp_page": [
"db/conf/coling/coling1969.html"
],
"bibliographic_counts": [
{
"bibliographic_year": "1969",
"booktitle": "COLING",
"record_type": "inproceedings",
"count": 94
}
]
}
},
{
"requested_venue": "ACL",
"reason": "COLING-only proceedings; no explicit joint ACL edition evidence for this year. Publisher or broad family mapping does not establish event membership.",
"candidate": {
"key": "conf/coling/1973",
"family": "coling",
"candidate_event_year": 1973,
"year_basis": "four_digit_volume_key",
"title": "Computational And Mathematical Linguistics: Proceedings of the 5th International Conference on Computational Linguistics, COLING 1973, Pisa, Italy, August 27 - September 1, 1973",
"publication_year": [
"1973"
],
"publisher": [
"ACL"
],
"primary_links": [
"https://aclanthology.org/volumes/C73-1/",
"https://aclanthology.org/volumes/C73-2/",
"https://aclanthology.org/C73-1000/",
"https://aclanthology.org/C73-2000/"
],
"original_dblp_page": [
"db/conf/coling/coling1973.html"
],
"bibliographic_counts": [
{
"bibliographic_year": "1973",
"booktitle": "COLING",
"record_type": "inproceedings",
"count": 115
}
]
}
}
],
"scope_review": {
"checked_at": "2026-11-08T18:27:14.883908+00:00",
"previous_candidate_file_sha256": "7861148ed17728999ed1d277dd5effeb20b0fbc9bb6409988c0206077692ced7",
"previous_years_with_candidate_volumes": 89,
"previous_years_without_candidate_volumes": 46,
"current_candidate_counts": [
85,
50
],
"production_database_written": false,
"historical_year_gaps_unchanged": 135,
"evidence": [
{
"name": "acl-venue",
"url": "https://aclanthology.org/venues/acl/",
"resolved_url": "https://aclanthology.org/venues/acl/",
"status": 200,
"sha256": "d04c188c0769e065f18ca9c0246f70086e2f7027ce3efe5ea0f2cdc641796b72",
"bytes": 45678,
"checked_at": "2026-11-08T18:27:10.721711+00:00"
},
{
"name": "coling-venue",
"url": "https://aclanthology.org/venues/coling/",
"resolved_url": "https://aclanthology.org/venues/coling/",
"status": 200,
"sha256": "8e7ec0a2915bfbccaa26b7a7558a9cf977c4aadc119794516ecebb826f61623f",
"bytes": 43203,
"checked_at": "2026-11-08T18:27:12.992120+00:00"
},
{
"name": "iccl-history",
"url": "https://ufal.mff.cuni.cz/iccl-old",
"resolved_url": "https://ufal.mff.cuni.cz/iccl-old",
"status": 200,
"sha256": "c5286dc51236c90685d22543ff1f7b209adcb3eedb82a7b1ac2115c8dd0169fc",
"bytes": 246933,
"checked_at": "2026-11-08T18:27:14.883908+00:00"
}
],
"rule": "A candidate needs evidence of target event membership for the particular year. Publisher ACL and COLING family alone do not imply an ACL annual meeting. Explicit joint editions remain supported; no blanket cross-family rejection.",
"unresolved_source_limits": [
{
"venue": "ACL",
"years": [
1963,
1964,
1965,
1966,
1967,
1968,
1969,
1970,
1971,
1972,
1973,
1974,
1975,
1976,
1977,
1978
],
"status": "not_listed_in_current_official_anthology_venue_index",
"note": "Official index starts at 1979. Earlier meeting dates do not establish a missing published volume or a count of missing papers. Keep historical census slots pending separate publication/source evidence."
},
{
"venue": "COLING",
"years": [
1971,
1976,
1978
],
"status": "organizer_confirms_meetings_but_not_listed_in_current_anthology_venue_index",
"note": "Keep source gaps open. No unpublished/no-paper inference, no manufactured acceptance/rejection records."
}
]
}
}
@@ -0,0 +1,32 @@
# 早期 NLP 来源范围复核
核查时间:2026-11-08 18:27 UTC(北京时间11月9日)。本轮只修正来源候选和记录可获得性,没有操作生产数据库。
## 跨会议候选修正
先前候选清单将 `conf/coling/1965`、`1967`、`1969`、`1973` 匹配到 ACL 年会缺口。这四卷标题明确属于 COLING;[COLING 官方 Anthology 目录](https://aclanthology.org/venues/coling/)将它们列在 COLING 下。出版者写作 ACL 或目标映射包含 COLING,不足以证明某一年是 ACL 联办届次。
从 ACL 候选中排除上述四卷,原始卷字段和排除理由保留在[候选JSON](historical-source-candidates-2026-11-09.json)的 `excluded_cross_venue_candidates` 中。135个历史会议—年份位置仍未关闭;有初步候选来源的年度由89修正为85,尚未匹配的由46增至50。这些数字是目录初筛结果,不是已验证可导入的论文数。
联合届次仍按具体年度的明确会议身份处理,例如有官方联办证据的卷可以属于多个会议。不能一律排除跨family卷,也不能把联合卷重复导入为两批论文。
## 来源待核实的早期年份
| 范围 | 本轮官方来源观察 | 处理 |
| --- | --- | --- |
| ACL 1963–1978,共16年 | [ACL 官方 Anthology 目录](https://aclanthology.org/venues/acl/)目前从1979年列起 | 保留历史举办清单;逐年核实是否有可索引发表材料,不能据会议举办就断言漏采正式论文集,也不据目录缺失断言未出版 |
| COLING 1971、1976、1978 | [主办委员会历史](https://ufal.mff.cuni.cz/iccl-old)列出这三届;当前Anthology COLING目录未列出 | 来源缺口继续开放,需要主办方或出版者逐篇索引;不生成占位论文或录用/拒稿记录 |
这19个位置不能用其他会议的卷补齐,也不能因本轮未找到目录而删除。公开拒稿可获得性是独立核查,不从论文集或录用清单缺失推断。
## 证据与复核
三份原始HTML及 `receipts.json` 保存在工作证据目录 `paper-index/nlp-history-source-review-v1/`;结构化响应URL、时间、状态、字节数和完整SHA256收录于候选JSON的 `scope_review.evidence`。三次响应均为HTTP200;未获取论文全文。
| 官方来源 | 响应SHA256 |
| --- | --- |
| [acl-venue](https://aclanthology.org/venues/acl/) | `d04c188c0769e065f18ca9c0246f70086e2f7027ce3efe5ea0f2cdc641796b72` |
| [coling-venue](https://aclanthology.org/venues/coling/) | `8e7ec0a2915bfbccaa26b7a7558a9cf977c4aadc119794516ecebb826f61623f` |
| [iccl-history](https://ufal.mff.cuni.cz/iccl-old) | `c5286dc51236c90685d22543ff1f7b209adcb3eedb82a7b1ac2115c8dd0169fc` |
复核时先校验保存的原始响应哈希,再读取目录中的会议身份和年度。实时网页若已变化,应另存新响应和时间,不能把新内容套用旧哈希。本次不改最初会议年度清单或生产年度快照,不代表第14步覆盖验收或第16步最终全库审计完成。
-27
View File
@@ -54,34 +54,7 @@ HISTORICAL_WORKSHOP_TITLES = {
}
# Exact pinned volume titles corroborated by official series histories. The
# original title (including Workshop) remains in source metadata. In particular
# ML91 has no four-digit year in its title; its exact key/title and bibliographic
# year are checked independently, rather than guessing a title year.
HISTORICAL_PRIMARY_EVIDENCE = {
'icml': ('ML', 'https://icml.cc/Conferences/2008/past_icmls.shtml.html'),
'iros': ('IROS', 'https://www.ieee-ras.org/conferences-workshops/financially-co-sponsored/iros/iros-past-and-future-venues/'),
}
HISTORICAL_PRIMARY_TITLES = {
('icml', 1988): 'Machine Learning, Proceedings of the Fifth International Conference on Machine Learning, Ann Arbor, Michigan, USA, June 12-14, 1988',
('icml', 1989): 'Proceedings of the Sixth International Workshop on Machine Learning (ML 1989), Cornell University, Ithaca, New York, USA, June 26-27, 1989',
('icml', 1990): 'Machine Learning, Proceedings of the Seventh International Conference on Machine Learning, Austin, Texas, USA, June 21-23, 1990',
('icml', 1991): 'Proceedings of the Eighth International Workshop (ML91), Northwestern University, Evanston, Illinois, USA',
('icml', 1992): 'Proceedings of the Ninth International Workshop on Machine Learning (ML 1992), Aberdeen, Scotland, UK, July 1-3, 1992',
('iros', 1988): "IEEE International Workshop on Intelligent Robots and Systems '88, Proceedings. IROS 1988, Tokyo, Japan, October 31 - November 2, 1988",
('iros', 1989): "IEEE International Workshop on Intelligent Robots and Systems '89, Proceedings. IROS 1989, September 4-6, 1989, Tsukuba, Japan",
('iros', 1990): "IEEE International Workshop on Intelligent Robots and Systems '90, Towards a New Frontier of Applications, Proceedings. IROS 1990, July 3-6, 1990, Ibaraki, Japan",
}
def historical_track(family, base, suffix, volume_key, year, title):
primary = HISTORICAL_PRIMARY_EVIDENCE.get(family)
if (primary and not suffix and base.casefold() == primary[0].casefold()
and volume_key == f'conf/{family}/{year}'
and title == HISTORICAL_PRIMARY_TITLES.get((family, year))):
return ('main',
'Historical primary series; exact proceedings key, complete title and bibliographic/event year corroborated by official series history. Workshop in this original title is not an affiliated track.',
primary[1])
if suffix or base.casefold() != family or volume_key != f'conf/{family}/{year}':
return None
prefix = HISTORICAL_WORKSHOP_TITLES.get((family, year))
-115
View File
@@ -1,115 +0,0 @@
"""Regression coverage for primary series once named Workshop, with strict scope boundaries."""
from contextlib import closing
import hashlib
import json
from pathlib import Path
import sqlite3
import tempfile
import unittest
from paper_atlas.collectors.dblp_records import normalize_row
from paper_atlas.collectors.dblp_scope import scope
from paper_atlas.ingestion.records import ingest_file
ICML_HISTORY = 'https://icml.cc/Conferences/2008/past_icmls.shtml.html'
IROS_HISTORY = 'https://www.ieee-ras.org/conferences-workshops/financially-co-sponsored/iros/iros-past-and-future-venues/'
class HistoricalPrimarySeriesTests(unittest.TestCase):
def example(self, family, year, title, book=None, key=None):
key = key or f'conf/{family}/{year}'
book = book or ('ML' if family == 'icml' else 'IROS')
row = {'record_type':'inproceedings', 'key':f'conf/{family}/Paper{year}', 'publtype':None,
'fields':{'title':['An independently identified historical research paper'],
'author':['Jane Doe'], 'booktitle':[book], 'year':[str(year)],
'crossref':[key], 'ee':[f'https://doi.org/10.1234/{family}.{year}']}}
volume = {'record_type':'proceedings', 'key':key,
'fields':{'title':[title], 'year':[str(year)]}}
return row, volume
def test_icml_workshop_primary_editions_are_not_silently_filtered(self):
examples = {
1989:'Proceedings of the Sixth International Workshop on Machine Learning (ML 1989), Cornell University, Ithaca, New York, USA, June 26-27, 1989',
1991:'Proceedings of the Eighth International Workshop (ML91), Northwestern University, Evanston, Illinois, USA',
1992:'Proceedings of the Ninth International Workshop on Machine Learning (ML 1992), Aberdeen, Scotland, UK, July 1-3, 1992',
}
for year, title in examples.items():
with self.subTest(year=year):
row, volume = self.example('icml', year, title)
record, reason = normalize_row(row, {volume['key']:volume}, {'ICML'})
self.assertIsNone(reason)
self.assertEqual((record['venue'],record['year'],record['track'],record['status']), ('ICML',year,'main','accepted'))
self.assertEqual(record['metadata']['proceedings_title'], title)
self.assertEqual(record['metadata']['track_scope_evidence_url'], ICML_HISTORY)
self.assertEqual(record['metadata']['bibliographic_year'], year)
def test_iros_first_three_editions_are_primary_series(self):
examples = {
1988:"IEEE International Workshop on Intelligent Robots and Systems '88, Proceedings. IROS 1988, Tokyo, Japan, October 31 - November 2, 1988",
1989:"IEEE International Workshop on Intelligent Robots and Systems '89, Proceedings. IROS 1989, September 4-6, 1989, Tsukuba, Japan",
1990:"IEEE International Workshop on Intelligent Robots and Systems '90, Towards a New Frontier of Applications, Proceedings. IROS 1990, July 3-6, 1990, Ibaraki, Japan",
}
for year, title in examples.items():
with self.subTest(year=year):
row, volume = self.example('iros', year, title)
record, reason = normalize_row(row, {volume['key']:volume}, {'IROS'})
self.assertIsNone(reason)
self.assertEqual((record['venue'],record['year'],record['track']), ('IROS',year,'main'))
self.assertEqual(record['metadata']['proceedings_title'], title)
self.assertEqual(record['metadata']['track_scope_evidence_url'], IROS_HISTORY)
def test_main_named_icml_predecessors_also_carry_primary_scope_provenance(self):
examples = {
1988:'Machine Learning, Proceedings of the Fifth International Conference on Machine Learning, Ann Arbor, Michigan, USA, June 12-14, 1988',
1990:'Machine Learning, Proceedings of the Seventh International Conference on Machine Learning, Austin, Texas, USA, June 21-23, 1990',
}
for year, title in examples.items():
row, volume = self.example('icml', year, title)
edition, reason = scope(row, volume)
self.assertIsNone(reason)
self.assertEqual(edition['track'], 'main')
self.assertEqual(edition['track_scope_evidence_url'], ICML_HISTORY)
def test_wrong_keys_titles_suffixes_and_unknown_years_keep_workshop_boundary(self):
title = 'Proceedings of the Eighth International Workshop (ML91), Northwestern University, Evanston, Illinois, USA'
for year, changed, book, key in [
(1991,title,'ML','conf/icml/1991w'),
(1991,title,'ML (Workshops)','conf/icml/1991'),
(1991,title.replace('Eighth','Ninth'),'ML','conf/icml/1991'),
(1991,title + ', Affiliated Workshop','ML','conf/icml/1991'),
(1987,'Machine Learning Workshop 1987, Irvine','ML','conf/icml/1987'),
]:
with self.subTest(year=year, book=book, key=key, title=changed):
row, volume = self.example('icml',year,changed,book,key)
record, reason = normalize_row(row,{volume['key']:volume},{'ICML'})
self.assertIsNone(record)
self.assertEqual(reason,'separate_workshop')
self.assertNotIn('track_scope_evidence_url',scope(row,volume)[0])
title = "IEEE International Workshop on Intelligent Robots and Systems '88, Proceedings. IROS 1988, Tokyo, Japan, October 31 - November 2, 1988"
for changed, book, key in [
(title,'IROS','conf/iros/1988w'),
(title,'IROS (Workshops)','conf/iros/1988'),
(title.replace('Tokyo','Another city'),'IROS','conf/iros/1988'),
]:
row, volume = self.example('iros',1988,changed,book,key)
self.assertEqual(normalize_row(row,{volume['key']:volume},{'IROS'})[1],'separate_workshop')
def test_primary_scope_proof_survives_native_file_ingestion(self):
title = 'Proceedings of the Eighth International Workshop (ML91), Northwestern University, Evanston, Illinois, USA'
row, volume = self.example('icml',1991,title)
record, reason = normalize_row(row,{volume['key']:volume},{'ICML'})
self.assertIsNone(reason)
with tempfile.TemporaryDirectory() as temporary:
root=Path(temporary);path=root/'records.jsonl';path.write_text(json.dumps(record)+'\n')
path.with_suffix('.manifest.json').write_text(json.dumps({'source':'dblp','count':1,'list_url':ICML_HISTORY,'file_sha256':hashlib.sha256(path.read_bytes()).hexdigest()}))
ingest_file(root/'test.sqlite',path)
with closing(sqlite3.connect(root/'test.sqlite')) as connection:
self.assertEqual(connection.execute('SELECT track FROM editions').fetchone()[0],'main')
self.assertEqual(connection.execute('SELECT status FROM decisions').fetchone()[0],'accepted')
metadata=json.loads(connection.execute('SELECT metadata_json FROM source_records').fetchone()[0])
self.assertEqual(metadata['proceedings_title'],title)
self.assertEqual(metadata['track_scope_evidence_url'],ICML_HISTORY)
if __name__ == '__main__':
unittest.main()