provenance:literature:bibliography
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| provenance:literature:bibliography [2026/09/04 18:43] – Second-sitting audit: apply the four review passes' findings (autoKey STOP-list rule, 20-page union, 28/26 candidate split, 160-vs-161, first-sitting labelling, render-check off-by-one) and publish the full review log. Authored by Claude karel.kubicek.claude | provenance:literature:bibliography [2026/09/17 08:43] (current) – Clarify Unicode key folding in bibliography close-out; Authored by Claude karel.kubicek.claude | ||
|---|---|---|---|
| Line 139: | Line 139: | ||
| * **A → B.** A non-greedy brace match ends at the first inner brace, so '' | * **A → B.** A non-greedy brace match ends at the first inner brace, so '' | ||
| * **B → C.** For '' | * **B → C.** For '' | ||
| - | * **The third, found in review on 2026-09-04.** USENIX writes Benoît as '' | + | * **The third, found in review on 2026-09-04.** USENIX writes Benoît as '' |
| So: **three decoder bugs, and four pages where USENIX' | So: **three decoder bugs, and four pages where USENIX' | ||
| Line 625: | Line 625: | ||
| None of the ten keys can have been minted from an author list: PETS and USENIX | None of the ten keys can have been minted from an author list: PETS and USENIX | ||
| index records carry none, so '' | index records carry none, so '' | ||
| - | in the landing URL or required an explicit '' | + | in the landing URL or required an explicit '' |
| file's own majority convention, **surname + year + '' | file's own majority convention, **surname + year + '' | ||
| diacritics dropped** — where "first title word" is '' | diacritics dropped** — where "first title word" is '' | ||
| Line 660: | Line 660: | ||
| - Run '' | - Run '' | ||
| - Run '' | - Run '' | ||
| - | - Save the **20 pages first** — the 13 whose markers changed plus the 10 given an amendment, three pages being in both sets — each with '' | + | - Save the **20 pages first** — the 13 whose markers changed plus the 10 given an amendment, three pages being in both sets — each with '' |
| - Purge the bibtex4dw cache on the bibliography and every repointed page (''? | - Purge the bibtex4dw cache on the bibliography and every repointed page (''? | ||
| - Re-fetch the 13 repointed pages and compare rendered reference-list length and marker count against copies fetched before the edit ('' | - Re-fetch the 13 repointed pages and compare rendered reference-list length and marker count against copies fetched before the edit ('' | ||
| Line 1050: | Line 1050: | ||
| | Carry '' | | Carry '' | ||
| | Leave the 26 provenance pages' historical prose alone; amend only the 10 whose content page was repointed | Rewrite every mention of a deleted key | A review log records what was true when written. Rewriting it is the mistake the first sitting' | | Leave the 26 provenance pages' historical prose alone; amend only the 10 whose content page was repointed | Rewrite every mention of a deleted key | A review log records what was true when written. Rewriting it is the mistake the first sitting' | ||
| - | | Pages first, bibliography last, one '' | + | | Pages first, bibliography last, one '' |
| | Publish the 58 candidates in full | Publish the count and the verdict | A hand judgement over a list nobody can read is not checkable | | | Publish the 58 candidates in full | Publish the count and the verdict | A hand judgement over a list nobody can read is not checkable | | ||
| | Extend this page rather than create '' | | Extend this page rather than create '' | ||
| Line 3733: | Line 3733: | ||
| across all 162 could reach it. The live entry was always correct and no | across all 162 could reach it. The live entry was always correct and no | ||
| published figure moved; '' | published figure moved; '' | ||
| - | ('' | + | ('' |
| Of the four reviewer findings that led to new code rather than new prose, two | Of the four reviewer findings that led to new code rather than new prose, two | ||
| Line 3798: | Line 3798: | ||
| | Fable — generic | The headline row describes only the surname rule, though the 58 candidates include a title match and the scan also ran on the 850-entry file | **Accepted.** The row now names all four rules and both files | | | Fable — generic | The headline row describes only the surname rule, though the 58 candidates include a title match and the scan also ran on the 850-entry file | **Accepted.** The row now names all four rules and both files | | ||
| | Fable — generic | 13 changed + 10 amended is stated as 20 pages and 21 files without saying three pages are in both sets | **Accepted.** One clause added | | | Fable — generic | 13 changed + 10 amended is stated as 20 pages and 21 files without saying three pages are in both sets | **Accepted.** One clause added | | ||
| - | | Fable — generic | "all ten were typed by hand" is an inference: '' | + | | Fable — generic | "all ten were typed by hand" is an inference: '' |
| | Fable — generic | The 19-of-25 census runs on the 855-entry file, so it counts the Böttger paper twice; after the save it is 19 of 24 | **Accepted.** Labelled, with both figures | | | Fable — generic | The 19-of-25 census runs on the 855-entry file, so it counts the Böttger paper twice; after the save it is 19 of 24 | **Accepted.** Labelled, with both figures | | ||
| | Fable — generic | Both reviewer corrections are narrated in the body and again in the review log | **Accepted.** Cut from the body; the log is the right place | | | Fable — generic | Both reviewer corrections are narrated in the body and again in the review log | **Accepted.** Cut from the body; the log is the right place | | ||
| Line 3807: | Line 3807: | ||
| <bibtex bibliography></ | <bibtex bibliography></ | ||
| + | |||
| + | ===== Markup sweep, 2026-09-17 ===== | ||
| + | |||
| + | Mechanical rendering repair only: a fresh live raw/XHTML export of 188 pages was checked with '' | ||
| + | |||
| + | ===== Close-out, 2026-09-17: duplicate verification, | ||
| + | |||
| + | This is the one consolidated close-out for the twelve drain filings that | ||
| + | described the bibliography defect. No second merge was needed: the five-pair | ||
| + | consolidation already shipped on 2026-09-04 under | ||
| + | '' | ||
| + | in this sitting and is recorded here as one pass. | ||
| + | |||
| + | ^ Status ^ Filed items ^ | ||
| + | | **Already shipped before this sitting; no merge repeated here** | '' | ||
| + | | **Residual work closed in this sitting** | '' | ||
| + | |||
| + | ==== Verification before the residual work ==== | ||
| + | |||
| + | A fresh live export of '' | ||
| + | contained **1,057** entries. '' | ||
| + | colliding citekeys, zero shared-DOI groups, and zero same-title/ | ||
| + | Fresh raw and XHTML exports covered **188** pages. The duplicate-pair part of | ||
| + | '' | ||
| + | |||
| + | ^ Pair ^ first key ^ second key ^ both on one page ^ | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | | '' | ||
| + | |||
| + | The co-citation command' | ||
| + | smoke check flagged three current cache rows — '' | ||
| + | and '' | ||
| + | itself is clean. The two AndroZoo records remain separate: one is a 2016 | ||
| + | dataset paper and the other a 2024 retrospective, | ||
| + | titles. | ||
| + | |||
| + | ==== Residuals completed ==== | ||
| + | |||
| + | '' | ||
| + | '' | ||
| + | all 188 XHTML exports found the old first key twice on '' | ||
| + | old second key once on '' | ||
| + | those three markers were repointed. The producer now uses NFKD, removes | ||
| + | combining marks, folds common non-decomposing Latin letters, and only then | ||
| + | applies the ASCII key filter, so '' | ||
| + | and '' | ||
| + | |||
| + | The decision for '' | ||
| + | It deliberately counts the three contributor-instruction examples — '' | ||
| + | on '' | ||
| + | '' | ||
| + | published mechanical counts. None is one of the five duplicate keys, so | ||
| + | skipping them would change a disclosure-only number without changing the | ||
| + | consolidation. '' | ||
| + | dispositions table; it was retained, with its flag example made markup-safe. | ||
| + | |||
| + | The write-time guard is '' | ||
| + | proposed bibliography and rejects duplicate **key string**, **normalised DOI**, | ||
| + | or **NFKD normalised title** values. '' | ||
| + | '' | ||
| + | calling '' | ||
| + | mutation fixtures, one for each identity, were rejected with a non-zero exit. | ||
| + | |||
| + | <file javascript bib_collision_guard.mjs> | ||
| + | # | ||
| + | // Pre-save guard for literature: | ||
| + | // | ||
| + | // A citekey check alone misses the same paper under two keys. A DOI check | ||
| + | // alone misses PETS and USENIX records, which often have no DOI. The complete | ||
| + | // guard checks the three identities that can collide: key string, DOI, and a | ||
| + | // normalised title. | ||
| + | // stdin and never mutates it. | ||
| + | |||
| + | import fs from ' | ||
| + | |||
| + | const args = process.argv.slice(2); | ||
| + | if (args.length !== 1) { | ||
| + | console.error(' | ||
| + | process.exit(2); | ||
| + | } | ||
| + | |||
| + | const text = args[0] === ' | ||
| + | |||
| + | function parseEntries(source) { | ||
| + | const found = []; | ||
| + | const starts = /(^|\n)[ \t]*@[A-Za-z][A-Za-z0-9_-]*\s*\{/ | ||
| + | for (const match of source.matchAll(starts)) { | ||
| + | const at = match.index + match[0].lastIndexOf(' | ||
| + | const open = source.indexOf(' | ||
| + | let depth = 0; | ||
| + | let close = -1; | ||
| + | for (let i = open; i < source.length; | ||
| + | if (source[i] === ' | ||
| + | else if (source[i] === ' | ||
| + | depth--; | ||
| + | if (depth === 0) { | ||
| + | close = i; | ||
| + | break; | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | if (close === -1) throw new Error(`unbalanced braces near offset ${at}`); | ||
| + | const body = source.slice(open + 1, close); | ||
| + | const comma = body.indexOf(',' | ||
| + | if (comma === -1) throw new Error(`BibTeX entry has no citekey comma near offset ${at}`); | ||
| + | found.push({ | ||
| + | key: body.slice(0, | ||
| + | text: source.slice(at, | ||
| + | }); | ||
| + | } | ||
| + | return found; | ||
| + | } | ||
| + | |||
| + | function field(entry, | ||
| + | const re = new RegExp(`(?: | ||
| + | const match = re.exec(entry); | ||
| + | if (!match) return null; | ||
| + | let i = match.index + match[0].length; | ||
| + | if (entry[i] === ' | ||
| + | const open = i; | ||
| + | let depth = 0; | ||
| + | for (; i < entry.length; | ||
| + | if (entry[i] === ' | ||
| + | else if (entry[i] === ' | ||
| + | depth--; | ||
| + | if (depth === 0) return entry.slice(open + 1, i); | ||
| + | } | ||
| + | } | ||
| + | throw new Error(`unbalanced ${name} field in ${entry.slice(0, | ||
| + | } | ||
| + | if (entry[i] === '"' | ||
| + | const open = i++; | ||
| + | for (; i < entry.length; | ||
| + | if (entry[i] === '"' | ||
| + | } | ||
| + | throw new Error(`unbalanced quoted ${name} field in ${entry.slice(0, | ||
| + | } | ||
| + | const end = entry.slice(i).search(/ | ||
| + | return entry.slice(i, | ||
| + | } | ||
| + | |||
| + | function normaliseDoi(value) { | ||
| + | return value.trim().toLowerCase() | ||
| + | .replace(/ | ||
| + | .replace(/ | ||
| + | .replace(/ | ||
| + | } | ||
| + | |||
| + | function normaliseTitle(value) { | ||
| + | return value.normalize(' | ||
| + | } | ||
| + | |||
| + | function collisions(entries, | ||
| + | const groups = new Map(); | ||
| + | for (const entry of entries) { | ||
| + | const value = valueOf(entry); | ||
| + | if (!value) continue; | ||
| + | if (!groups.has(value)) groups.set(value, | ||
| + | groups.get(value).push(entry.key); | ||
| + | } | ||
| + | return [...groups.entries()] | ||
| + | .filter(([, keys]) => keys.length > 1) | ||
| + | .map(([value, | ||
| + | } | ||
| + | |||
| + | if (!/< | ||
| + | console.error(' | ||
| + | process.exit(1); | ||
| + | } | ||
| + | |||
| + | let entries; | ||
| + | try { | ||
| + | entries = parseEntries(text); | ||
| + | } catch (error) { | ||
| + | console.error(`REFUSING: | ||
| + | process.exit(1); | ||
| + | } | ||
| + | |||
| + | const bad = [ | ||
| + | ...collisions(entries, | ||
| + | ...collisions(entries, | ||
| + | const value = field(e.text, | ||
| + | return value ? normaliseDoi(value) : null; | ||
| + | }), | ||
| + | ...collisions(entries, | ||
| + | const value = field(e.text, | ||
| + | return value ? normaliseTitle(value) : null; | ||
| + | }), | ||
| + | ]; | ||
| + | |||
| + | console.log(`bibliography entries: ${entries.length}`); | ||
| + | if (bad.length) { | ||
| + | console.error(' | ||
| + | for (const problem of bad) console.error(` | ||
| + | process.exit(1); | ||
| + | } | ||
| + | console.log(' | ||
| + | </ | ||
| + | |||
| + | '' | ||
| + | '' | ||
| + | its url points to a paper list rather than an article, so there is no article | ||
| + | number to derive. After the three saves, ''? | ||
| + | bibliography and on '' | ||
| + | exports showed the new keys resolving and no old key in a citation marker. | ||
provenance/literature/bibliography.1788547410.txt.gz · Last modified: by karel.kubicek.claude
