paperlint 6.2.1 → 6.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/submit-paper/references/venues/agenticdev.md +12 -7
- package/skills/verify-citations/SKILL.md +8 -4
- package/skills/verify-citations/SKILL.md.spec.ts +7 -3
- package/skills/verify-citations/scripts/verify-cites.mjs +23 -5
- package/skills/verify-citations/scripts/verify-cites.test.mjs +76 -5
package/package.json
CHANGED
|
@@ -118,6 +118,10 @@ the preamble, the copyright block, CCS, source files). Here — only what's spec
|
|
|
118
118
|
|
|
119
119
|
## Attendance and the talk (2026 edition)
|
|
120
120
|
|
|
121
|
+
**Every year: the deadline and the upload channel come from the parent conference's
|
|
122
|
+
not-in-person page, not from this card.** Look that page up again for the new edition; the dates
|
|
123
|
+
below are 2026's.
|
|
124
|
+
|
|
121
125
|
**Remote is allowed, but there is no live slot.** On 2026-08-27 the chairs told accepted authors
|
|
122
126
|
who cannot travel (by email) that the workshop adopts ASE 2026's
|
|
123
127
|
[Not-in-Person Presentations](https://conf.researchr.org/track/ase-2026/ase-2026-not-in-person-presentations)
|
|
@@ -128,19 +132,20 @@ policy. That page, verbatim:
|
|
|
128
132
|
|
|
129
133
|
Instead the author sends:
|
|
130
134
|
|
|
131
|
-
| artifact | what the page says | deadline |
|
|
132
|
-
| --------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
|
133
|
-
| video | "made available via a dedicated page on the conference website (recommendation: 10 min duration, mp4 file format, HD resolution)" |
|
|
134
|
-
| one-slide | "shown during one of the conference sessions"; no size or format stated | same as the video
|
|
135
|
-
| poster | optional for the workshop; ASE prints it | ASE page: 2026-09-21
|
|
135
|
+
| artifact | what the page says | deadline (2026) |
|
|
136
|
+
| --------- | --------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
|
|
137
|
+
| video | "made available via a dedicated page on the conference website (recommendation: 10 min duration, mp4 file format, HD resolution)" | 2026-10-08 (ASE page; the chairs first asked for 10-01, then deferred to the page) |
|
|
138
|
+
| one-slide | "shown during one of the conference sessions"; no size or format stated | same as the video |
|
|
139
|
+
| poster | optional for the workshop; ASE prints it | ASE page: 2026-09-21 |
|
|
136
140
|
|
|
137
141
|
**Where to upload.** The page says: "find the submission link on the submission page for your paper
|
|
138
142
|
(see author-kit e-mail from Conference Publishing Consulting)". That is the same personal page used
|
|
139
143
|
for the camera-ready. On it, the block "Optional Archive/Appendix/Video/Picture Submissions … Submit
|
|
140
144
|
Material to ACM" uploads straight into the ACM system, once per file. "All submitted material will be
|
|
141
145
|
published in the ACM DL if the publishing-rights agreement gives permission for this", so tick
|
|
142
|
-
permission for auxiliary material when filling in eRights.
|
|
143
|
-
|
|
146
|
+
permission for auxiliary material when filling in eRights. Asked where to send the files, the
|
|
147
|
+
chairs answered (2026-10-01) only with a link to the ASE page, so the page governs: channel and
|
|
148
|
+
deadline both come from it, and email attachments are not needed.
|
|
144
149
|
|
|
145
150
|
**The slot.** Per the chairs' email to all authors (2026-09-29), a short paper gets 10 minutes in
|
|
146
151
|
total: approximately 6–7 for the presentation and 3–4 for questions. It is stated as approximate,
|
|
@@ -4,7 +4,7 @@ description: Verify every citation is a real work with correct metadata, and tha
|
|
|
4
4
|
allowed-tools: [Read, Write, Edit, Grep, Glob, Bash, WebSearch, WebFetch, Agent]
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
<!-- vigiles:sha256:
|
|
7
|
+
<!-- vigiles:sha256:faf8d55c8ddb82ed compiled from skills/verify-citations/SKILL.md.spec.ts -->
|
|
8
8
|
|
|
9
9
|
# verify-citations — every cite real, the delta explicit
|
|
10
10
|
|
|
@@ -102,7 +102,7 @@ not-found, not mistaken for an unrelated paper.
|
|
|
102
102
|
| verdict | when | meaning |
|
|
103
103
|
|---|---|---|
|
|
104
104
|
| `true` | any resolver **matched** (match always wins) | found, metadata matches |
|
|
105
|
-
| `false` | no match **and** an *authoritative* disproof: doi.org says the DOI is `responseCode 100`, the reachable arXiv API definitively rejects the id, NVD has no such CVE, **or**
|
|
105
|
+
| `false` | no match **and** an *authoritative* disproof: doi.org says the DOI is `responseCode 100`, the reachable arXiv API definitively rejects the id, NVD has no such CVE, **or** the id's own registry (arXiv for an arXiv id or arXiv DOI, Crossref for any other DOI) puts it on a *confidently-different* paper (`DOI_MISMATCH`) | fabrication — the only thing we call fabrication |
|
|
106
106
|
| `unresolvable` | title-misses, registry-404s with no authority disproof, uncomparable titles, and/or unreachable resolvers | couldn't verify, but **no positive disproof** |
|
|
107
107
|
|
|
108
108
|
The whole point: **a title you simply can't find is NOT fabrication** → `unresolvable`, never `false`. A
|
|
@@ -217,13 +217,17 @@ by design, the gate **declines** in three situations rather than risk a false ac
|
|
|
217
217
|
emit `DOI_MISMATCH` — the id counts as resolved (`true`) or, absent other confirmation, `unresolvable`.
|
|
218
218
|
Never `false`. The `doi_mismatch → false` verdict fires **only** for two confidently-comparable titles that
|
|
219
219
|
are genuinely different.
|
|
220
|
+
- **An aggregator (OpenAlex, Semantic Scholar) that alone puts the id on another paper** →
|
|
221
|
+
`unresolvable` with `DOI_MISMATCH unconfirmed`. Aggregators copy metadata and do attach DOIs to the
|
|
222
|
+
wrong work; on 2026-10-01 OpenAlex mapped the arXiv DOIs of SWE-bench and ReAct to unrelated papers while
|
|
223
|
+
arXiv was rate-limiting. Only the id's own registry can disprove it.
|
|
220
224
|
- **A DOI that resolves at doi.org but has no content-registry metadata** (DataCite/Zenodo, fresh 2026 DOIs)
|
|
221
225
|
→ `unresolvable`, because the work exists but its metadata (title/year) cannot be cross-checked here. This
|
|
222
226
|
is the correct verdict for a paper's own artifact DOI; treat `unresolvable` as advisory, not a failure.
|
|
223
227
|
|
|
224
228
|
**Known narrow residue (rare, treat a lone `DOI_MISMATCH → false` as advisory, eyeball it).** Two edge cases
|
|
225
|
-
can still mis-fire: (a) a correct DOI whose *
|
|
226
|
-
proceedings title instead of the paper's — reads as "unrelated" (mitigated when any
|
|
229
|
+
can still mis-fire: (a) a correct DOI whose *own* registry records junk metadata — e.g. the container /
|
|
230
|
+
proceedings title instead of the paper's — reads as "unrelated" (mitigated when any other registry has the real
|
|
227
231
|
title, since a match wins); (b) a translated-journal title in the *same script* (transliterated Latin vs
|
|
228
232
|
English) that shares no tokens. Both need semantics the gate doesn't have; both are near-zero frequency in an
|
|
229
233
|
English CS bib. Identifier-prefix / trailing-punctuation mangling (`doi:`, `arXiv:`, a bib-swallowed `.`) is
|
|
@@ -118,7 +118,7 @@ not-found, not mistaken for an unrelated paper.
|
|
|
118
118
|
| verdict | when | meaning |
|
|
119
119
|
|---|---|---|
|
|
120
120
|
| \`true\` | any resolver **matched** (match always wins) | found, metadata matches |
|
|
121
|
-
| \`false\` | no match **and** an *authoritative* disproof: doi.org says the DOI is \`responseCode 100\`, the reachable arXiv API definitively rejects the id, NVD has no such CVE, **or**
|
|
121
|
+
| \`false\` | no match **and** an *authoritative* disproof: doi.org says the DOI is \`responseCode 100\`, the reachable arXiv API definitively rejects the id, NVD has no such CVE, **or** the id's own registry (arXiv for an arXiv id or arXiv DOI, Crossref for any other DOI) puts it on a *confidently-different* paper (\`DOI_MISMATCH\`) | fabrication — the only thing we call fabrication |
|
|
122
122
|
| \`unresolvable\` | title-misses, registry-404s with no authority disproof, uncomparable titles, and/or unreachable resolvers | couldn't verify, but **no positive disproof** |
|
|
123
123
|
|
|
124
124
|
The whole point: **a title you simply can't find is NOT fabrication** → \`unresolvable\`, never \`false\`. A
|
|
@@ -233,13 +233,17 @@ by design, the gate **declines** in three situations rather than risk a false ac
|
|
|
233
233
|
emit \`DOI_MISMATCH\` — the id counts as resolved (\`true\`) or, absent other confirmation, \`unresolvable\`.
|
|
234
234
|
Never \`false\`. The \`doi_mismatch → false\` verdict fires **only** for two confidently-comparable titles that
|
|
235
235
|
are genuinely different.
|
|
236
|
+
- **An aggregator (OpenAlex, Semantic Scholar) that alone puts the id on another paper** →
|
|
237
|
+
\`unresolvable\` with \`DOI_MISMATCH unconfirmed\`. Aggregators copy metadata and do attach DOIs to the
|
|
238
|
+
wrong work; on 2026-10-01 OpenAlex mapped the arXiv DOIs of SWE-bench and ReAct to unrelated papers while
|
|
239
|
+
arXiv was rate-limiting. Only the id's own registry can disprove it.
|
|
236
240
|
- **A DOI that resolves at doi.org but has no content-registry metadata** (DataCite/Zenodo, fresh 2026 DOIs)
|
|
237
241
|
→ \`unresolvable\`, because the work exists but its metadata (title/year) cannot be cross-checked here. This
|
|
238
242
|
is the correct verdict for a paper's own artifact DOI; treat \`unresolvable\` as advisory, not a failure.
|
|
239
243
|
|
|
240
244
|
**Known narrow residue (rare, treat a lone \`DOI_MISMATCH → false\` as advisory, eyeball it).** Two edge cases
|
|
241
|
-
can still mis-fire: (a) a correct DOI whose *
|
|
242
|
-
proceedings title instead of the paper's — reads as "unrelated" (mitigated when any
|
|
245
|
+
can still mis-fire: (a) a correct DOI whose *own* registry records junk metadata — e.g. the container /
|
|
246
|
+
proceedings title instead of the paper's — reads as "unrelated" (mitigated when any other registry has the real
|
|
243
247
|
title, since a match wins); (b) a translated-journal title in the *same script* (transliterated Latin vs
|
|
244
248
|
English) that shares no tokens. Both need semantics the gate doesn't have; both are near-zero frequency in an
|
|
245
249
|
English CS bib. Identifier-prefix / trailing-punctuation mangling (\`doi:\`, \`arXiv:\`, a bib-swallowed \`.\`) is
|
|
@@ -159,6 +159,15 @@ export function normalizeArxiv(arxiv) {
|
|
|
159
159
|
/** arXiv registers a DataCite DOI for every paper: `10.48550/arXiv.<id>`. */
|
|
160
160
|
const ARXIV_DOI = /^10\.48550\/arxiv\.(.+)$/i;
|
|
161
161
|
|
|
162
|
+
/** The one source whose record of an identifier is the identifier's own metadata: arXiv for an
|
|
163
|
+
* arXiv id or an arXiv DOI, Crossref for any other DOI. OpenAlex and Semantic Scholar are
|
|
164
|
+
* aggregators: they copy that metadata and can attach a DOI to the wrong work (OpenAlex did, for
|
|
165
|
+
* SWE-bench and ReAct, on 2026-10-01), so a title they disagree on is not proof of anything. */
|
|
166
|
+
function identifierAuthority(citation, query) {
|
|
167
|
+
if (query === "arxiv") return "arxiv";
|
|
168
|
+
return citation.doi && ARXIV_DOI.test(citation.doi) ? "arxiv" : "crossref";
|
|
169
|
+
}
|
|
170
|
+
|
|
162
171
|
/** Shallow copy of a citation with doi/arxiv identifiers normalized. Applied at the
|
|
163
172
|
* verify boundary so BOTH JSON input and .bib-parsed input are clean before any
|
|
164
173
|
* network / authority lookup.
|
|
@@ -367,6 +376,7 @@ export function classifyResolver(citation, response) {
|
|
|
367
376
|
db,
|
|
368
377
|
status: "doi_mismatch",
|
|
369
378
|
foundTitle: response.record.title,
|
|
379
|
+
authoritative: identifierAuthority(citation, response.query) === db,
|
|
370
380
|
};
|
|
371
381
|
}
|
|
372
382
|
}
|
|
@@ -473,8 +483,9 @@ export function checkCommit(citation) {
|
|
|
473
483
|
* commit flags, produce the final verdict.
|
|
474
484
|
*
|
|
475
485
|
* true iff ANY evidence is `matched` (a match always WINS)
|
|
476
|
-
* false iff NOT matched AND ≥1 evidence is `id_unmatched` or
|
|
477
|
-
* (a resolvable id that fails, or
|
|
486
|
+
* false iff NOT matched AND ≥1 evidence is an authoritative `id_unmatched` or
|
|
487
|
+
* `doi_mismatch` (a resolvable id that fails, or an id that its own registry
|
|
488
|
+
* puts on the wrong paper)
|
|
478
489
|
* unresolvable otherwise (only `title_miss` and/or `unreachable` — no disproof)
|
|
479
490
|
*/
|
|
480
491
|
export function reduceVerdict(citation, evidence, commitFlags = []) {
|
|
@@ -500,8 +511,13 @@ export function reduceVerdict(citation, evidence, commitFlags = []) {
|
|
|
500
511
|
);
|
|
501
512
|
}
|
|
502
513
|
|
|
503
|
-
// A DOI/arXiv id that resolves to a CONFIDENTLY-DIFFERENT paper → misdirection.
|
|
504
|
-
const mismatch = ev.find(
|
|
514
|
+
// A DOI/arXiv id that resolves to a CONFIDENTLY-DIFFERENT paper AT ITS AUTHORITY → misdirection.
|
|
515
|
+
const mismatch = ev.find(
|
|
516
|
+
(e) => e.status === "doi_mismatch" && e.authoritative,
|
|
517
|
+
);
|
|
518
|
+
const aggregatorMismatch = ev.find(
|
|
519
|
+
(e) => e.status === "doi_mismatch" && !e.authoritative,
|
|
520
|
+
);
|
|
505
521
|
if (mismatch) {
|
|
506
522
|
return out(
|
|
507
523
|
"false",
|
|
@@ -553,7 +569,9 @@ export function reduceVerdict(citation, evidence, commitFlags = []) {
|
|
|
553
569
|
// ── No positive disproof → unresolvable, with the most informative reason ──
|
|
554
570
|
const reachable = ev.some((e) => e.status !== "unreachable");
|
|
555
571
|
let reason;
|
|
556
|
-
if (
|
|
572
|
+
if (aggregatorMismatch) {
|
|
573
|
+
reason = `DOI_MISMATCH unconfirmed: ${aggregatorMismatch.db} maps the identifier to "${aggregatorMismatch.foundTitle}" (claimed "${citation.title}"), but ${aggregatorMismatch.db} only aggregates metadata and the identifier's own registry did not confirm it — eyeball the entry → unresolvable, not false`;
|
|
574
|
+
} else if (doiIdMiss && authorityPresent) {
|
|
557
575
|
reason = `DOI ${citation.doi} resolves at doi.org but no content registry (Crossref/OpenAlex/Semantic Scholar) has metadata for it — common for DataCite/Zenodo and freshly-minted DOIs; the work EXISTS, its metadata is just unindexed → unresolvable, NOT fabrication`;
|
|
558
576
|
} else if (doiIdMiss) {
|
|
559
577
|
reason = `DOI ${citation.doi} not found in any content registry, and the DOI authority (doi.org) was not reachable to confirm non-existence — cannot assert fabrication → unresolvable, never false`;
|
|
@@ -104,17 +104,88 @@ console.log(
|
|
|
104
104
|
title: "A Formal Verification Framework for Autonomous Agents",
|
|
105
105
|
year: 2021,
|
|
106
106
|
};
|
|
107
|
-
const
|
|
108
|
-
|
|
107
|
+
const wrongRecord = {
|
|
108
|
+
title: "Photosynthesis in Deep-Sea Bacteria",
|
|
109
|
+
year: 2009,
|
|
110
|
+
};
|
|
111
|
+
const crossref = {
|
|
112
|
+
db: "crossref",
|
|
109
113
|
transport: "ok",
|
|
110
114
|
query: "doi",
|
|
111
|
-
record:
|
|
115
|
+
record: wrongRecord,
|
|
112
116
|
};
|
|
113
|
-
const ev = classifyResolver(cite,
|
|
117
|
+
const ev = classifyResolver(cite, crossref);
|
|
114
118
|
eq(ev.status, "doi_mismatch", "classify → doi_mismatch");
|
|
115
119
|
const v = reduceVerdict(cite, [ev], checkCommit(cite));
|
|
116
|
-
eq(v.verdict, "false", "
|
|
120
|
+
eq(v.verdict, "false", "the DOI's own registry (Crossref) disagrees → false");
|
|
117
121
|
ok(/DOI_MISMATCH/.test(v.reason), "reason names DOI_MISMATCH");
|
|
122
|
+
|
|
123
|
+
// An aggregator alone is not proof: it can attach a DOI to the wrong work.
|
|
124
|
+
const openalex = {
|
|
125
|
+
db: "openalex",
|
|
126
|
+
transport: "ok",
|
|
127
|
+
query: "doi",
|
|
128
|
+
record: wrongRecord,
|
|
129
|
+
};
|
|
130
|
+
const agg = reduceVerdict(cite, [classifyResolver(cite, openalex)]);
|
|
131
|
+
eq(
|
|
132
|
+
agg.verdict,
|
|
133
|
+
"unresolvable",
|
|
134
|
+
"only OpenAlex disagrees → unresolvable, not false",
|
|
135
|
+
);
|
|
136
|
+
ok(
|
|
137
|
+
/DOI_MISMATCH unconfirmed/.test(agg.reason),
|
|
138
|
+
"reason says the mismatch is unconfirmed",
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// ── (2b) 2026-10-01: OpenAlex mapped the SWE-bench arXiv DOI to another paper while
|
|
143
|
+
// arXiv answered 429. The entry is correct; it must not be called fabricated.
|
|
144
|
+
console.log(
|
|
145
|
+
"\n(2b) aggregator mismatch on an arXiv DOI, arXiv rate-limited → unresolvable:",
|
|
146
|
+
);
|
|
147
|
+
{
|
|
148
|
+
const cite = normalizeIdentifiers({
|
|
149
|
+
id: "jimenez2024swebench",
|
|
150
|
+
doi: "10.48550/arXiv.2310.06770",
|
|
151
|
+
title: "SWE-bench: Can Language Models Resolve Real-World GitHub Issues?",
|
|
152
|
+
year: 2024,
|
|
153
|
+
});
|
|
154
|
+
const openalex = {
|
|
155
|
+
db: "openalex",
|
|
156
|
+
transport: "ok",
|
|
157
|
+
query: "doi",
|
|
158
|
+
record: {
|
|
159
|
+
title: "GardenBench: A lightweight, daily evaluation of LLM capabilities",
|
|
160
|
+
year: 2025,
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
const arxiv = {
|
|
164
|
+
db: "arxiv",
|
|
165
|
+
transport: "error",
|
|
166
|
+
query: "arxiv",
|
|
167
|
+
record: null,
|
|
168
|
+
};
|
|
169
|
+
const s2 = {
|
|
170
|
+
db: "semantic_scholar",
|
|
171
|
+
transport: "error",
|
|
172
|
+
query: "doi",
|
|
173
|
+
record: null,
|
|
174
|
+
};
|
|
175
|
+
const v = reduceVerdict(
|
|
176
|
+
cite,
|
|
177
|
+
[openalex, arxiv, s2].map((r) => classifyResolver(cite, r)),
|
|
178
|
+
);
|
|
179
|
+
eq(
|
|
180
|
+
v.verdict,
|
|
181
|
+
"unresolvable",
|
|
182
|
+
"correct entry with a corrupted aggregator record → unresolvable",
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
// …and arXiv itself putting the id on another paper is still misdirection.
|
|
186
|
+
const arxivWrong = { ...arxiv, transport: "ok", record: openalex.record };
|
|
187
|
+
const w = reduceVerdict(cite, [classifyResolver(cite, arxivWrong)]);
|
|
188
|
+
eq(w.verdict, "false", "arXiv (the id's registry) disagrees → false");
|
|
118
189
|
}
|
|
119
190
|
|
|
120
191
|
// ── (3) made-up arXiv id that resolves to nothing → false ────────────────────
|