From 5692ad40d8e40d2c81ea5fb5cbdbc4833398fe13 Mon Sep 17 00:00:00 2001 From: Dan Knauss Date: Wed, 17 Jun 2026 00:43:23 -0600 Subject: [PATCH 1/2] test(benchmark): salvage large-bibliography benchmark tooling Recovered from stale local branch experiment/large-bibliography-benchmark (tip b20cbe9, 41 commits behind main). Adds the standalone PHP formatter latency benchmark, the deterministic CSL-JSON fixture generator, the 200-entry fixture, and the results memo. Dev tooling only; no runtime code. Co-Authored-By: Claude Opus 4.8 --- .../large-bibliography-benchmark-results.md | 122 +++++++ scripts/benchmark-formatter.php | 309 ++++++++++++++++ scripts/generate-benchmark-fixtures.js | 335 ++++++++++++++++++ src/benchmarks/fixtures/csl-200.json | 202 +++++++++++ 4 files changed, 968 insertions(+) create mode 100644 docs/planning/large-bibliography-benchmark-results.md create mode 100644 scripts/benchmark-formatter.php create mode 100644 scripts/generate-benchmark-fixtures.js create mode 100644 src/benchmarks/fixtures/csl-200.json diff --git a/docs/planning/large-bibliography-benchmark-results.md b/docs/planning/large-bibliography-benchmark-results.md new file mode 100644 index 0000000..f4f0f96 --- /dev/null +++ b/docs/planning/large-bibliography-benchmark-results.md @@ -0,0 +1,122 @@ +# Large bibliography benchmark results + +Generated: 2026-05-10 +Branch: `experiment/large-bibliography-benchmark` +Machine: macOS (M-series), local dev environment +Fixture: `src/benchmarks/fixtures/csl-200.json` — 200 CSL-JSON entries, realistic type mix (article-journal 40%, book 20%, chapter 15%, thesis 10%, webpage 10%, report 5%) + +## Summary + +**No latency cliff was found up to 200 entries.** Both the PHP formatter (real citeproc-php) and the JS orchestration layer (sort, state management, cache lookup) remain well within the SPEC budget thresholds at every tested size — 50, 75, 100, 150, and 200 entries. + +The 250 ms style-switch and 150 ms mutation p95 budgets from SPEC §Rate Limiting & Resource Caps were never approached. The highest p95 observed was 31 ms (PHP warm, notes, 200 entries). + +## PHP formatter — real citeproc-php (not mocked) + +5 runs per cell. Cold = new CiteProc instance each run. Warm = instance reused. + +| Size | Family | Style | Cold p50 (ms) | Cold p95 (ms) | Warm p50 (ms) | Warm p95 (ms) | +| ---: | --- | --- | ---: | ---: | ---: | ---: | +| 50 | notes | chicago-notes-bibliography | 8.1 | 34.4 | 4.8 | 6.9 | +| 50 | author-date | chicago-author-date | 6.1 | 11.2 | 7.0 | 10.1 | +| 50 | numeric | ieee | 5.2 | 10.9 | 5.1 | 16.4 | +| 75 | notes | chicago-notes-bibliography | 4.4 | 5.8 | 4.3 | 5.2 | +| 75 | author-date | chicago-author-date | 5.2 | 6.7 | 4.1 | 5.8 | +| 75 | numeric | ieee | 4.4 | 6.5 | 5.1 | 5.6 | +| 100 | notes | chicago-notes-bibliography | 5.7 | 9.2 | 6.6 | 7.4 | +| 100 | author-date | chicago-author-date | 8.7 | 11.6 | 9.8 | 16.1 | +| 100 | numeric | ieee | 5.9 | 7.3 | 6.7 | 7.9 | +| 150 | notes | chicago-notes-bibliography | 7.0 | 8.0 | 8.4 | 13.1 | +| 150 | author-date | chicago-author-date | 11.1 | 17.9 | 11.5 | 26.6 | +| 150 | numeric | ieee | 7.3 | 8.6 | 7.6 | 8.4 | +| 200 | notes | chicago-notes-bibliography | 11.9 | 19.0 | 16.4 | 31.0 | +| 200 | author-date | chicago-author-date | 11.4 | 14.0 | 11.0 | 14.7 | +| 200 | numeric | ieee | 9.7 | 12.9 | 10.1 | 10.5 | + +Budget: p95 < 250 ms. All cells: **ok**. + +The 50-entry cold p95 spike (34.4 ms for notes) reflects first-run JIT / class-loading overhead for citeproc-php, not list-size scaling. At 75+ entries the cold p95 drops and scales linearly, reaching ~19 ms at 200 entries. + +Author-date warm p95 grows from 10 ms at 50 entries to 27 ms at 150 entries (notes warms from 7 ms to 31 ms at 200). This variance is real but the ceiling at 200 entries (31 ms) remains 8× under the 250 ms budget. + +**What this benchmark does not measure:** the HTTP round-trip from the WordPress editor REST call (serialization, WordPress middleware, plugin boot, network). Those costs would add to the numbers above on a live site. Shared hosting with a cold PHP-FPM pool could add 50–200 ms to the cold rows. + +## JS orchestration — mock formatter (sort, state, cache lookup) + +5 runs per cell. apiFetch is mocked; all measurements are JS-side orchestration (sort comparator, array operations, cache lookup). The mock returns instantly, so this isolates the JavaScript work from the PHP formatter round-trip. + +### Style switch (full reformat trigger, JS side only) + +| Size | Family | p50 (ms) | p95 (ms) | +| ---: | --- | ---: | ---: | +| 75 | notes | 3.6 | 4.5 | +| 75 | author-date | 3.5 | 3.9 | +| 75 | numeric | 3.4 | 3.6 | +| 100 | notes | 4.6 | 4.8 | +| 100 | author-date | 4.5 | 4.7 | +| 100 | numeric | 4.5 | 4.6 | +| 150 | notes | 7.0 | 7.1 | +| 150 | author-date | 7.0 | 7.1 | +| 150 | numeric | 6.9 | 7.1 | +| 200 | notes | 9.3 | 9.4 | +| 200 | author-date | 9.3 | 9.5 | +| 200 | numeric | 9.3 | 9.5 | + +Budget: p95 < 250 ms. All cells: **ok**. JS orchestration overhead is ~0.05 ms per entry and scales linearly with no cliff. + +### Mutations + +| Size | Operation | p50 (ms) | p95 (ms) | +| ---: | --- | ---: | ---: | +| 75 | add — notes (full reformat) | 5.4 | 7.7 | +| 75 | delete — author-date (full reformat)| 5.2 | 5.4 | +| 75 | delete — numeric (no reformat) | 0.0 | 0.0 | +| 100 | add — notes (full reformat) | 6.8 | 7.1 | +| 100 | delete — author-date (full reformat)| 6.9 | 7.0 | +| 100 | delete — numeric (no reformat) | 0.0 | 0.0 | +| 150 | add — notes (full reformat) | 10.8 | 11.1 | +| 150 | delete — author-date (full reformat)| 10.4 | 10.5 | +| 150 | delete — numeric (no reformat) | 0.0 | 0.0 | +| 200 | add — notes (full reformat) | 14.8 | 15.1 | +| 200 | delete — author-date (full reformat)| 14.4 | 14.7 | +| 200 | delete — numeric (no reformat) | 0.0 | 0.0 | + +Budget: p95 < 150 ms. All cells: **ok**. The numeric delete (no-reformat path) is effectively zero at all sizes — this confirms the optimization is worth keeping at any cap level. + +## Interpretation + +### What the data shows + +Neither citeproc-php nor the JS orchestration layer is a bottleneck at 200 entries on local hardware. The format work itself is cheap — under 20 ms p95 cold for any style family at 200 entries. + +### What the data does not show + +1. **HTTP round-trip on shared hosting.** A cold PHP-FPM pool, WordPress boot, REST dispatch, and network serialization add latency that is not captured here. On shared hosting, the cold total could plausibly be 150–300 ms for 100–200 entries. +2. **Block attribute payload size.** 200 CSL-JSON entries at ~800 bytes each is ~160 KB of block attribute data stored in `post_content`. WordPress saves this as a full HTML comment on every post save. This is a database and page-load concern independent of formatter speed. +3. **Editor perceived responsiveness.** The JS benchmark measures orchestration time after the REST response arrives. The full editor mutation perceived latency is `JS orchestration time + REST round-trip`. Only the JS part is measured here. +4. **Memory under load.** citeproc-php instantiation at high entry counts on shared hosting with a low `memory_limit` is not tested. + +## Recommendation — REQ-C1 option + +**Adopt Option 2: raise the soft cap to 100 entries with a persistent warning, keep 200 as an absolute hard cap.** + +Rationale: + +- The PHP formatter and JS orchestration work proves neither is a ceiling at 200 entries on capable hardware. The 250 ms style-switch and 150 ms mutation budgets are not threatened by local citeproc execution cost. +- The real uncertainty is REST round-trip on shared hosting (unknown) and block attribute payload size (a separate concern from formatter speed). +- A 100-entry soft cap with an explicit editor warning gives users a practical upgrade from 50 while remaining cautious about shared-hosting round-trips. The warning documents the performance expectation and transfers responsibility to the user if they exceed it. +- A hard cap at 200 entries prevents pathological cases that could trigger WordPress `post_content` size limits or PHP memory exhaustion on constrained hosts. +- Option 1 (raise the hard cap without a soft cap) would remove a useful warning layer. Option 3 (streaming/batched formatting) is not justified by the data — the bottleneck is HTTP round-trip, not citeproc execution time, and batching only helps citeproc execution. + +### Recommended implementation steps (not in scope for this spike) + +1. Update `BIBLIOGRAPHY_BUILDER_MAX_FORMAT_ITEMS` in PHP and the JS cap constant from 50 to 200 (hard cap). +2. Add a JS soft-cap warning at 100 entries (distinct from the hard-cap error). +3. Measure REST round-trip on a representative shared-hosting environment before advertising the 200 cap publicly. +4. Update SPEC REQ-C1 to document the new cap values and the soft-cap threshold. + +## Caveats and next steps + +- These numbers are from a local M-series Mac with warm OS caches. Re-run on a constrained VM (1–2 vCPU, 512 MB PHP memory limit) to get shared-hosting representative numbers before committing to any new cap value. +- The citeproc-php PHP 8.x deprecation warnings (nullable parameter declarations) do not affect correctness or timing but will become errors under PHP 9. Track the upstream fix schedule. +- The fixture is synthetic. Real scholarly content with long author lists, many co-authors, and complex title casing may format slower; re-run with a real bibliography export before finalising the cap. diff --git a/scripts/benchmark-formatter.php b/scripts/benchmark-formatter.php new file mode 100644 index 0000000..423945e --- /dev/null +++ b/scripts/benchmark-formatter.php @@ -0,0 +1,309 @@ + argument. +$vendor_opt = getopt( '', [ 'vendor-dir:' ] ); +if ( isset( $vendor_opt['vendor-dir'] ) ) { + $candidate = rtrim( $vendor_opt['vendor-dir'], '/' ) . '/autoload.php'; + if ( file_exists( $candidate ) ) { + $autoload = $candidate; + } +} + +if ( null === $autoload ) { + fwrite( STDERR, "Error: vendor/autoload.php not found. Run composer install in the repo root.\n" ); + exit( 1 ); +} + +require_once $autoload; + +if ( ! class_exists( '\Seboettg\CiteProc\CiteProc' ) ) { + fwrite( STDERR, "Error: citeproc-php not available after autoload.\n" ); + exit( 1 ); +} + +// --------------------------------------------------------------------------- +// CLI arguments +// --------------------------------------------------------------------------- + +$opts = getopt( '', [ 'sizes:', 'runs:', 'output-dir:' ] ); +$sizes = isset( $opts['sizes'] ) + ? array_map( 'intval', explode( ',', $opts['sizes'] ) ) + : [ 50, 75, 100, 150, 200 ]; +$runs = isset( $opts['runs'] ) ? max( 1, (int) $opts['runs'] ) : 5; + +$output_dir = $opts['output-dir'] ?? ( $plugin_root . '/output/benchmarks' ); +if ( ! is_dir( $output_dir ) ) { + mkdir( $output_dir, 0755, true ); +} + +// --------------------------------------------------------------------------- +// Style definitions (one per family, same as bibliography-builder.php) +// --------------------------------------------------------------------------- + +// vendor/ is beside autoload.php +$vendor_dir = dirname( $autoload ); +$styles_dir = $vendor_dir . '/citation-style-language/styles/'; + +$style_families = [ + [ + 'styleKey' => 'chicago-notes-bibliography', + 'family' => 'notes', + 'template' => 'chicago-notes-bibliography', + 'locale' => 'en-US', + ], + [ + 'styleKey' => 'chicago-author-date', + 'family' => 'author-date', + 'template' => 'chicago-author-date', + 'locale' => 'en-US', + ], + [ + 'styleKey' => 'ieee', + 'family' => 'numeric', + 'template' => 'ieee', + 'locale' => 'en-US', + ], +]; + +// Verify style files are readable. +foreach ( $style_families as $style ) { + $style_path = $styles_dir . $style['template'] . '.csl'; + if ( ! is_readable( $style_path ) ) { + fwrite( STDERR, "Error: style file not readable: {$style_path}\n" ); + exit( 1 ); + } +} + +// --------------------------------------------------------------------------- +// Fixture loading +// --------------------------------------------------------------------------- + +$fixture_path = $plugin_root . '/src/benchmarks/fixtures/csl-200.json'; + +if ( ! file_exists( $fixture_path ) ) { + fwrite( STDERR, "Error: fixture not found: {$fixture_path}\n" ); + fwrite( STDERR, "Run: node scripts/generate-benchmark-fixtures.js\n" ); + exit( 1 ); +} + +$all_csl_items = json_decode( file_get_contents( $fixture_path ), false ); + +if ( ! is_array( $all_csl_items ) || count( $all_csl_items ) < max( $sizes ) ) { + fwrite( + STDERR, + sprintf( + "Error: fixture has %d entries but largest requested size is %d.\n", + count( $all_csl_items ), + max( $sizes ) + ) + ); + exit( 1 ); +} + +// --------------------------------------------------------------------------- +// Benchmark helpers +// --------------------------------------------------------------------------- + +/** @return float seconds (float) */ +function micro_now(): float { + return microtime( true ); +} + +function summarize( array $values_ms ): array { + sort( $values_ms ); + $n = count( $values_ms ); + $sum = array_sum( $values_ms ); + $p50_i = (int) min( $n - 1, ceil( $n * 0.50 ) - 1 ); + $p95_i = (int) min( $n - 1, ceil( $n * 0.95 ) - 1 ); + + return [ + 'runs' => array_map( fn( $v ) => round( $v, 2 ), $values_ms ), + 'minMs' => round( $values_ms[0], 2 ), + 'maxMs' => round( $values_ms[ $n - 1 ], 2 ), + 'avgMs' => round( $sum / $n, 2 ), + 'p50Ms' => round( $values_ms[ $p50_i ], 2 ), + 'p95Ms' => round( $values_ms[ $p95_i ], 2 ), + ]; +} + +// --------------------------------------------------------------------------- +// Budget thresholds (mirror SPEC §Rate Limiting & Resource Caps) +// --------------------------------------------------------------------------- + +const BUDGET_STYLE_SWITCH_P95_MS = 250; + +// --------------------------------------------------------------------------- +// Run benchmark +// --------------------------------------------------------------------------- + +fprintf( STDOUT, "PHP formatter benchmark — citeproc-php\n" ); +fprintf( STDOUT, "Sizes: %s Runs per cell: %d\n\n", implode( ', ', $sizes ), $runs ); + +$results = []; + +foreach ( $sizes as $size ) { + $items = array_slice( $all_csl_items, 0, $size ); + + // Re-assign sequential IDs. + foreach ( $items as $index => $item ) { + $item->id = 'bm-' . ( $index + 1 ); + } + + $size_result = [ 'size' => $size, 'byFamily' => [] ]; + + foreach ( $style_families as $style_def ) { + $style_path = $styles_dir . $style_def['template'] . '.csl'; + $style_xml = file_get_contents( $style_path ); + + $cold_runs = []; + $warm_runs = []; + + for ( $run = 0; $run < $runs; $run++ ) { + // Cold: construct a fresh CiteProc instance each time. + $t0 = micro_now(); + $formatter = new \Seboettg\CiteProc\CiteProc( $style_xml, $style_def['locale'] ); + $formatter->render( $items, 'bibliography' ); + $cold_runs[] = ( micro_now() - $t0 ) * 1000; + + // Warm: reuse the same instance (re-rendering the same items). + $t0 = micro_now(); + $formatter->render( $items, 'bibliography' ); + $warm_runs[] = ( micro_now() - $t0 ) * 1000; + } + + $cold_stats = summarize( $cold_runs ); + $warm_stats = summarize( $warm_runs ); + + $size_result['byFamily'][] = [ + 'styleKey' => $style_def['styleKey'], + 'family' => $style_def['family'], + 'cold' => array_merge( $cold_stats, [ + 'exceedsBudget' => $cold_stats['p95Ms'] > BUDGET_STYLE_SWITCH_P95_MS, + ] ), + 'warm' => array_merge( $warm_stats, [ + 'exceedsBudget' => $warm_stats['p95Ms'] > BUDGET_STYLE_SWITCH_P95_MS, + ] ), + ]; + + fprintf( + STDOUT, + " size=%-3d %-30s cold p50=%6.1f ms p95=%6.1f ms warm p50=%6.1f ms p95=%6.1f ms%s\n", + $size, + $style_def['styleKey'], + $cold_stats['p50Ms'], + $cold_stats['p95Ms'], + $warm_stats['p50Ms'], + $warm_stats['p95Ms'], + $cold_stats['p95Ms'] > BUDGET_STYLE_SWITCH_P95_MS ? ' ** OVER BUDGET **' : '' + ); + } + + $results[] = $size_result; +} + +// --------------------------------------------------------------------------- +// Write output +// --------------------------------------------------------------------------- + +$report = [ + 'generatedAt' => date( 'c' ), + 'formatterMode' => 'real-citeproc-php', + 'budgets' => [ 'styleSwitchColdP95Ms' => BUDGET_STYLE_SWITCH_P95_MS ], + 'sizes' => $sizes, + 'runs' => $runs, + 'results' => $results, +]; + +$json_path = $output_dir . '/php-formatter.json'; +file_put_contents( $json_path, json_encode( $report, JSON_PRETTY_PRINT ) . "\n" ); + +// Markdown summary. +$md = [ '# PHP formatter latency benchmark', '' ]; +$md[] = sprintf( 'Generated: %s', $report['generatedAt'] ); +$md[] = sprintf( 'Formatter: real citeproc-php Runs: %d', $runs ); +$md[] = ''; +$md[] = '## Cold format (new CiteProc instance each run)'; +$md[] = ''; +$md[] = sprintf( 'Budget: p95 < %d ms', BUDGET_STYLE_SWITCH_P95_MS ); +$md[] = ''; +$md[] = '| Size | Family | Style | p50 (ms) | p95 (ms) | Budget |'; +$md[] = '| ---: | --- | --- | ---: | ---: | --- |'; +foreach ( $results as $row ) { + foreach ( $row['byFamily'] as $f ) { + $md[] = sprintf( + '| %d | %s | %s | %s | %s | %s |', + $row['size'], + $f['family'], + $f['styleKey'], + $f['cold']['p50Ms'], + $f['cold']['p95Ms'], + $f['cold']['exceedsBudget'] ? 'OVER' : 'ok' + ); + } +} +$md[] = ''; +$md[] = '## Warm format (reuse CiteProc instance)'; +$md[] = ''; +$md[] = sprintf( 'Budget: p95 < %d ms', BUDGET_STYLE_SWITCH_P95_MS ); +$md[] = ''; +$md[] = '| Size | Family | Style | p50 (ms) | p95 (ms) | Budget |'; +$md[] = '| ---: | --- | --- | ---: | ---: | --- |'; +foreach ( $results as $row ) { + foreach ( $row['byFamily'] as $f ) { + $md[] = sprintf( + '| %d | %s | %s | %s | %s | %s |', + $row['size'], + $f['family'], + $f['styleKey'], + $f['warm']['p50Ms'], + $f['warm']['p95Ms'], + $f['warm']['exceedsBudget'] ? 'OVER' : 'ok' + ); + } +} + +$md_path = $output_dir . '/php-formatter.md'; +file_put_contents( $md_path, implode( "\n", $md ) . "\n" ); + +fprintf( STDOUT, "\nWrote JSON report to %s\n", $json_path ); +fprintf( STDOUT, "Wrote Markdown report to %s\n", $md_path ); diff --git a/scripts/generate-benchmark-fixtures.js b/scripts/generate-benchmark-fixtures.js new file mode 100644 index 0000000..d530a46 --- /dev/null +++ b/scripts/generate-benchmark-fixtures.js @@ -0,0 +1,335 @@ +#!/usr/bin/env node +/** + * Generates src/benchmarks/fixtures/csl-200.json — 200 CSL-JSON entries + * spanning all supported source types with varied authors and years. + * + * Usage: node scripts/generate-benchmark-fixtures.js + */ + +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +const SURNAMES = [ + 'Abbott', + 'Achebe', + 'Adorno', + 'Ahmad', + 'Arendt', + 'Atwood', + 'Azoulay', + 'Barad', + 'Barthes', + 'Beauvoir', + 'Benjamin', + 'Berlant', + 'Bourdieu', + 'Butler', + 'Chakrabarty', + 'Chomsky', + 'Crenshaw', + 'Crimp', + 'Damasio', + 'Dean', + 'Deleuze', + 'Derrida', + 'Dolar', + 'Douglas', + 'Eagleton', + 'Elden', + 'Ellison', + 'Fanon', + 'Foucault', + 'Fraser', + 'Freud', + 'Geertz', + 'Gilroy', + 'Gramsci', + 'Hall', + 'Haraway', + 'Harvey', + 'Hayles', + 'Hegel', + 'Heidegger', + 'hooks', + 'Irigaray', + 'Jameson', + 'Kant', + 'Kristeva', + 'Lacan', + 'Latour', + 'Levi-Strauss', + 'Lorde', + 'Lukacs', + 'Lyotard', + 'Marx', + 'Massey', + 'Mbembe', + 'Merleau-Ponty', + 'Mignolo', + 'Moraga', + 'Morrison', + 'Mouffe', + 'Nancy', + 'Nussbaum', + 'Ong', + 'Parisi', + 'Peirce', + 'Polanyi', + 'Quijano', + 'Ranciere', + 'Rawls', + 'Ricoeur', + 'Said', + 'Saussure', + 'Sedgwick', + 'Senghor', + 'Sharpe', + 'Simmel', + 'Smith', + 'Spivak', + 'Taylor', + 'Tsing', + 'Turner', + 'Vattimo', + 'Virilio', + 'Wallerstein', + 'Weber', + 'West', + 'Williams', + 'Wittgenstein', + 'Wynter', + 'Zizek', +]; + +const GIVEN = [ + 'Alex', + 'Jordan', + 'Morgan', + 'Robin', + 'Sam', + 'Taylor', + 'Quinn', + 'Drew', +]; +const JOURNALS = [ + 'Journal of Comparative Literature', + 'Critical Inquiry', + 'New Left Review', + 'Social Text', + 'PMLA', + 'American Literature', + 'Cultural Studies', + 'Theory, Culture & Society', + 'Feminist Review', + 'Postcolonial Studies', + 'boundary 2', + 'Representations', +]; +const PUBLISHERS = [ + 'University of Chicago Press', + 'Duke University Press', + 'Verso', + 'Routledge', + 'Polity Press', + 'MIT Press', + 'Oxford University Press', + 'Princeton University Press', + 'Columbia University Press', + 'Harvard University Press', +]; +const PLACES = [ + 'Chicago', + 'Durham', + 'London', + 'New York', + 'Cambridge', + 'Oxford', +]; +const INSTITUTIONS = [ + 'University of Chicago', + 'Duke University', + 'Columbia University', + 'Harvard University', + 'MIT', +]; +const DOMAINS = [ + 'www.jstor.org', + 'www.muse.jhu.edu', + 'www.tandfonline.com', + 'www.cambridge.org', + 'www.wiley.com', +]; + +function pick(arr, index) { + return arr[index % arr.length]; +} + +function year(index) { + return 1990 + (index % 35); +} + +function doi(index) { + return `10.9999/benchmark.${String(index + 1).padStart(4, '0')}`; +} + +function url(index) { + return `https://${pick(DOMAINS, index)}/article/${String( + index + 1 + ).padStart(6, '0')}`; +} + +function author(index, offset = 0) { + return { + family: pick(SURNAMES, index + offset), + given: pick(GIVEN, index), + }; +} + +function issued(index) { + return { 'date-parts': [[year(index)]] }; +} + +function makeArticle(i) { + return { + id: `benchmark-${i + 1}`, + type: 'article-journal', + title: `Benchmark article title ${i + 1}: a critical reading`, + author: [author(i), author(i, 10)], + 'container-title': pick(JOURNALS, i), + volume: String(10 + (i % 30)), + issue: String(1 + (i % 4)), + page: `${100 + i * 3}–${103 + i * 3}`, + issued: issued(i), + DOI: doi(i), + }; +} + +function makeBook(i) { + return { + id: `benchmark-${i + 1}`, + type: 'book', + title: `Benchmark book title ${i + 1}: a scholarly monograph`, + author: [author(i)], + publisher: pick(PUBLISHERS, i), + 'publisher-place': pick(PLACES, i), + issued: issued(i), + }; +} + +function makeChapter(i) { + return { + id: `benchmark-${i + 1}`, + type: 'chapter', + title: `Benchmark chapter title ${i + 1}: situated knowledge`, + author: [author(i)], + editor: [author(i, 20)], + 'container-title': `Benchmark edited volume ${1 + (i % 15)}`, + publisher: pick(PUBLISHERS, i), + 'publisher-place': pick(PLACES, i), + page: `${50 + i * 2}–${70 + i * 2}`, + issued: issued(i), + }; +} + +function makeThesis(i) { + return { + id: `benchmark-${i + 1}`, + type: 'thesis', + title: `Benchmark thesis ${ + i + 1 + }: interdisciplinary approaches to knowledge`, + author: [author(i)], + publisher: pick(INSTITUTIONS, i), + genre: i % 2 === 0 ? 'PhD dissertation' : "Master's thesis", + issued: issued(i), + }; +} + +function makeWebpage(i) { + return { + id: `benchmark-${i + 1}`, + type: 'webpage', + title: `Benchmark online source ${ + i + 1 + }: digital humanities perspectives`, + author: [author(i)], + 'container-title': `Benchmark Journal Online ${1 + (i % 8)}`, + issued: issued(i), + accessed: { 'date-parts': [[2024, 1, 15]] }, + URL: url(i), + }; +} + +function makeReport(i) { + return { + id: `benchmark-${i + 1}`, + type: 'report', + title: `Benchmark report ${ + i + 1 + }: empirical findings and policy implications`, + author: [author(i)], + publisher: pick(INSTITUTIONS, i), + number: String(100 + i), + issued: issued(i), + URL: url(i), + }; +} + +function generate(count) { + const entries = []; + // Proportional mix: ~40% article, 20% book, 15% chapter, 10% thesis, 10% webpage, 5% report + const types = [ + { make: makeArticle, share: 40 }, + { make: makeBook, share: 20 }, + { make: makeChapter, share: 15 }, + { make: makeThesis, share: 10 }, + { make: makeWebpage, share: 10 }, + { make: makeReport, share: 5 }, + ]; + + const total = types.reduce((sum, t) => sum + t.share, 0); + let globalIndex = 0; + let remainder = count; + + for (const [typeIndex, type] of types.entries()) { + const isLast = typeIndex === types.length - 1; + const n = isLast ? remainder : Math.round((type.share / total) * count); + remainder -= n; + for (let j = 0; j < n; j++) { + entries.push(type.make(globalIndex)); + globalIndex++; + } + } + + // Shuffle so types are interleaved (deterministic Fisher-Yates) + let seed = 42; + function rand(n) { + // eslint-disable-next-line no-bitwise -- deterministic LCG PRNG for reproducible fixtures + seed = (seed * 1664525 + 1013904223) & 0xffffffff; + return Math.abs(seed) % n; + } + for (let i = entries.length - 1; i > 0; i--) { + const j = rand(i + 1); + [entries[i], entries[j]] = [entries[j], entries[i]]; + } + + // Re-assign IDs after shuffle so they are 1-based sequential + return entries.map((entry, i) => ({ ...entry, id: `benchmark-${i + 1}` })); +} + +const outDir = path.join(__dirname, '..', 'src', 'benchmarks', 'fixtures'); +const entries = generate(200); +const outPath = path.join(outDir, 'csl-200.json'); +// One entry per line so the file is readable but stays under commit size limits. +const lines = [ + '[', + ...entries.map( + (e, i) => JSON.stringify(e) + (i < entries.length - 1 ? ',' : '') + ), + ']', +]; +fs.writeFileSync(outPath, lines.join('\n') + '\n'); +// eslint-disable-next-line no-console -- CLI generator script intentionally reports output path +console.log(`Wrote ${entries.length} entries to ${outPath}`); diff --git a/src/benchmarks/fixtures/csl-200.json b/src/benchmarks/fixtures/csl-200.json new file mode 100644 index 0000000..39e529c --- /dev/null +++ b/src/benchmarks/fixtures/csl-200.json @@ -0,0 +1,202 @@ +[ +{"id":"benchmark-1","type":"article-journal","title":"Benchmark article title 25: a critical reading","author":[{"family":"Eagleton","given":"Alex"},{"family":"Hall","given":"Alex"}],"container-title":"Journal of Comparative Literature","volume":"34","issue":"1","page":"172–175","issued":{"date-parts":[[2014]]},"DOI":"10.9999/benchmark.0025"}, +{"id":"benchmark-2","type":"article-journal","title":"Benchmark article title 65: a critical reading","author":[{"family":"Polanyi","given":"Alex"},{"family":"Simmel","given":"Alex"}],"container-title":"PMLA","volume":"14","issue":"1","page":"292–295","issued":{"date-parts":[[2019]]},"DOI":"10.9999/benchmark.0065"}, +{"id":"benchmark-3","type":"book","title":"Benchmark book title 95: a scholarly monograph","author":[{"family":"Atwood","given":"Quinn"}],"publisher":"Polity Press","publisher-place":"Cambridge","issued":{"date-parts":[[2014]]}}, +{"id":"benchmark-4","type":"chapter","title":"Benchmark chapter title 146: situated knowledge","author":[{"family":"Moraga","given":"Jordan"}],"editor":[{"family":"Spivak","given":"Jordan"}],"container-title":"Benchmark edited volume 11","publisher":"MIT Press","publisher-place":"Durham","page":"340–360","issued":{"date-parts":[[1995]]}}, +{"id":"benchmark-5","type":"webpage","title":"Benchmark online source 187: digital humanities perspectives","author":[{"family":"Barthes","given":"Morgan"}],"container-title":"Benchmark Journal Online 3","issued":{"date-parts":[[2001]]},"accessed":{"date-parts":[[2024,1,15]]},"URL":"https://www.muse.jhu.edu/article/000187"}, +{"id":"benchmark-6","type":"article-journal","title":"Benchmark article title 59: a critical reading","author":[{"family":"Mouffe","given":"Morgan"},{"family":"Ricoeur","given":"Morgan"}],"container-title":"boundary 2","volume":"38","issue":"3","page":"274–277","issued":{"date-parts":[[2013]]},"DOI":"10.9999/benchmark.0059"}, +{"id":"benchmark-7","type":"chapter","title":"Benchmark chapter title 145: situated knowledge","author":[{"family":"Mignolo","given":"Alex"}],"editor":[{"family":"Smith","given":"Alex"}],"container-title":"Benchmark edited volume 10","publisher":"Polity Press","publisher-place":"Chicago","page":"338–358","issued":{"date-parts":[[1994]]}}, +{"id":"benchmark-8","type":"article-journal","title":"Benchmark article title 37: a critical reading","author":[{"family":"Harvey","given":"Sam"},{"family":"Latour","given":"Sam"}],"container-title":"Journal of Comparative Literature","volume":"16","issue":"1","page":"208–211","issued":{"date-parts":[[1991]]},"DOI":"10.9999/benchmark.0037"}, +{"id":"benchmark-9","type":"webpage","title":"Benchmark online source 183: digital humanities perspectives","author":[{"family":"Arendt","given":"Quinn"}],"container-title":"Benchmark Journal Online 7","issued":{"date-parts":[[1997]]},"accessed":{"date-parts":[[2024,1,15]]},"URL":"https://www.tandfonline.com/article/000183"}, +{"id":"benchmark-10","type":"webpage","title":"Benchmark online source 181: digital humanities perspectives","author":[{"family":"Adorno","given":"Sam"}],"container-title":"Benchmark Journal Online 5","issued":{"date-parts":[[1995]]},"accessed":{"date-parts":[[2024,1,15]]},"URL":"https://www.jstor.org/article/000181"}, +{"id":"benchmark-11","type":"book","title":"Benchmark book title 82: a scholarly monograph","author":[{"family":"Virilio","given":"Jordan"}],"publisher":"Duke University Press","publisher-place":"New York","issued":{"date-parts":[[2001]]}}, +{"id":"benchmark-12","type":"article-journal","title":"Benchmark article title 15: a critical reading","author":[{"family":"Chakrabarty","given":"Quinn"},{"family":"Eagleton","given":"Quinn"}],"container-title":"New Left Review","volume":"24","issue":"3","page":"142–145","issued":{"date-parts":[[2004]]},"DOI":"10.9999/benchmark.0015"}, +{"id":"benchmark-13","type":"article-journal","title":"Benchmark article title 63: a critical reading","author":[{"family":"Parisi","given":"Quinn"},{"family":"Senghor","given":"Quinn"}],"container-title":"New Left Review","volume":"12","issue":"3","page":"286–289","issued":{"date-parts":[[2017]]},"DOI":"10.9999/benchmark.0063"}, +{"id":"benchmark-14","type":"book","title":"Benchmark book title 110: a scholarly monograph","author":[{"family":"Deleuze","given":"Taylor"}],"publisher":"Harvard University Press","publisher-place":"Durham","issued":{"date-parts":[[1994]]}}, +{"id":"benchmark-15","type":"report","title":"Benchmark report 191: empirical findings and policy implications","author":[{"family":"Bourdieu","given":"Quinn"}],"publisher":"University of Chicago","number":"290","issued":{"date-parts":[[2005]]},"URL":"https://www.jstor.org/article/000191"}, +{"id":"benchmark-16","type":"article-journal","title":"Benchmark article title 36: a critical reading","author":[{"family":"Haraway","given":"Robin"},{"family":"Lacan","given":"Robin"}],"container-title":"Representations","volume":"15","issue":"4","page":"205–208","issued":{"date-parts":[[1990]]},"DOI":"10.9999/benchmark.0036"}, +{"id":"benchmark-17","type":"report","title":"Benchmark report 199: empirical findings and policy implications","author":[{"family":"Deleuze","given":"Quinn"}],"publisher":"Harvard University","number":"298","issued":{"date-parts":[[2013]]},"URL":"https://www.cambridge.org/article/000199"}, +{"id":"benchmark-18","type":"book","title":"Benchmark book title 85: a scholarly monograph","author":[{"family":"West","given":"Sam"}],"publisher":"Polity Press","publisher-place":"Chicago","issued":{"date-parts":[[2004]]}}, +{"id":"benchmark-19","type":"book","title":"Benchmark book title 87: a scholarly monograph","author":[{"family":"Wittgenstein","given":"Quinn"}],"publisher":"Oxford University Press","publisher-place":"London","issued":{"date-parts":[[2006]]}}, +{"id":"benchmark-20","type":"book","title":"Benchmark book title 81: a scholarly monograph","author":[{"family":"Vattimo","given":"Alex"}],"publisher":"University of Chicago Press","publisher-place":"London","issued":{"date-parts":[[2000]]}}, +{"id":"benchmark-21","type":"webpage","title":"Benchmark online source 171: digital humanities perspectives","author":[{"family":"Virilio","given":"Morgan"}],"container-title":"Benchmark Journal Online 3","issued":{"date-parts":[[2020]]},"accessed":{"date-parts":[[2024,1,15]]},"URL":"https://www.jstor.org/article/000171"}, +{"id":"benchmark-22","type":"article-journal","title":"Benchmark article title 28: a critical reading","author":[{"family":"Fanon","given":"Robin"},{"family":"Hayles","given":"Robin"}],"container-title":"Social Text","volume":"37","issue":"4","page":"181–184","issued":{"date-parts":[[2017]]},"DOI":"10.9999/benchmark.0028"}, +{"id":"benchmark-23","type":"article-journal","title":"Benchmark article title 9: a critical reading","author":[{"family":"Barthes","given":"Alex"},{"family":"Damasio","given":"Alex"}],"container-title":"Feminist Review","volume":"18","issue":"1","page":"124–127","issued":{"date-parts":[[1998]]},"DOI":"10.9999/benchmark.0009"}, +{"id":"benchmark-24","type":"article-journal","title":"Benchmark article title 47: a critical reading","author":[{"family":"Latour","given":"Quinn"},{"family":"Moraga","given":"Quinn"}],"container-title":"boundary 2","volume":"26","issue":"3","page":"238–241","issued":{"date-parts":[[2001]]},"DOI":"10.9999/benchmark.0047"}, +{"id":"benchmark-25","type":"article-journal","title":"Benchmark article title 31: a critical reading","author":[{"family":"Freud","given":"Quinn"},{"family":"hooks","given":"Quinn"}],"container-title":"Cultural Studies","volume":"10","issue":"3","page":"190–193","issued":{"date-parts":[[2020]]},"DOI":"10.9999/benchmark.0031"}, +{"id":"benchmark-26","type":"article-journal","title":"Benchmark article title 20: a critical reading","author":[{"family":"Dean","given":"Robin"},{"family":"Fraser","given":"Robin"}],"container-title":"Theory, Culture & Society","volume":"29","issue":"4","page":"157–160","issued":{"date-parts":[[2009]]},"DOI":"10.9999/benchmark.0020"}, +{"id":"benchmark-27","type":"article-journal","title":"Benchmark article title 21: a critical reading","author":[{"family":"Deleuze","given":"Sam"},{"family":"Freud","given":"Sam"}],"container-title":"Feminist Review","volume":"30","issue":"1","page":"160–163","issued":{"date-parts":[[2010]]},"DOI":"10.9999/benchmark.0021"}, +{"id":"benchmark-28","type":"article-journal","title":"Benchmark article title 79: a critical reading","author":[{"family":"Tsing","given":"Quinn"},{"family":"Zizek","given":"Quinn"}],"container-title":"Cultural Studies","volume":"28","issue":"3","page":"334–337","issued":{"date-parts":[[1998]]},"DOI":"10.9999/benchmark.0079"}, +{"id":"benchmark-29","type":"chapter","title":"Benchmark chapter title 124: situated knowledge","author":[{"family":"Hall","given":"Robin"}],"editor":[{"family":"Merleau-Ponty","given":"Robin"}],"container-title":"Benchmark edited volume 4","publisher":"Routledge","publisher-place":"New York","page":"296–316","issued":{"date-parts":[[2008]]}}, +{"id":"benchmark-30","type":"thesis","title":"Benchmark thesis 162: interdisciplinary approaches to knowledge","author":[{"family":"Senghor","given":"Jordan"}],"publisher":"Duke University","genre":"Master's thesis","issued":{"date-parts":[[2011]]}}, +{"id":"benchmark-31","type":"chapter","title":"Benchmark chapter title 133: situated knowledge","author":[{"family":"Kant","given":"Sam"}],"editor":[{"family":"Peirce","given":"Sam"}],"container-title":"Benchmark edited volume 13","publisher":"Verso","publisher-place":"Chicago","page":"314–334","issued":{"date-parts":[[2017]]}}, +{"id":"benchmark-32","type":"article-journal","title":"Benchmark article title 24: a critical reading","author":[{"family":"Douglas","given":"Drew"},{"family":"Gramsci","given":"Drew"}],"container-title":"Representations","volume":"33","issue":"4","page":"169–172","issued":{"date-parts":[[2013]]},"DOI":"10.9999/benchmark.0024"}, +{"id":"benchmark-33","type":"article-journal","title":"Benchmark article title 11: a critical reading","author":[{"family":"Benjamin","given":"Morgan"},{"family":"Deleuze","given":"Morgan"}],"container-title":"boundary 2","volume":"20","issue":"3","page":"130–133","issued":{"date-parts":[[2000]]},"DOI":"10.9999/benchmark.0011"}, +{"id":"benchmark-34","type":"report","title":"Benchmark report 196: empirical findings and policy implications","author":[{"family":"Crimp","given":"Robin"}],"publisher":"University of Chicago","number":"295","issued":{"date-parts":[[2010]]},"URL":"https://www.jstor.org/article/000196"}, +{"id":"benchmark-35","type":"article-journal","title":"Benchmark article title 5: a critical reading","author":[{"family":"Arendt","given":"Sam"},{"family":"Chakrabarty","given":"Sam"}],"container-title":"PMLA","volume":"14","issue":"1","page":"112–115","issued":{"date-parts":[[1994]]},"DOI":"10.9999/benchmark.0005"}, +{"id":"benchmark-36","type":"book","title":"Benchmark book title 107: a scholarly monograph","author":[{"family":"Crimp","given":"Morgan"}],"publisher":"Oxford University Press","publisher-place":"Cambridge","issued":{"date-parts":[[1991]]}}, +{"id":"benchmark-37","type":"article-journal","title":"Benchmark article title 27: a critical reading","author":[{"family":"Ellison","given":"Morgan"},{"family":"Harvey","given":"Morgan"}],"container-title":"New Left Review","volume":"36","issue":"3","page":"178–181","issued":{"date-parts":[[2016]]},"DOI":"10.9999/benchmark.0027"}, +{"id":"benchmark-38","type":"chapter","title":"Benchmark chapter title 147: situated knowledge","author":[{"family":"Morrison","given":"Morgan"}],"editor":[{"family":"Taylor","given":"Morgan"}],"container-title":"Benchmark edited volume 12","publisher":"Oxford University Press","publisher-place":"London","page":"342–362","issued":{"date-parts":[[1996]]}}, +{"id":"benchmark-39","type":"thesis","title":"Benchmark thesis 154: interdisciplinary approaches to knowledge","author":[{"family":"Polanyi","given":"Jordan"}],"publisher":"Harvard University","genre":"Master's thesis","issued":{"date-parts":[[2003]]}}, +{"id":"benchmark-40","type":"book","title":"Benchmark book title 116: a scholarly monograph","author":[{"family":"Ellison","given":"Robin"}],"publisher":"MIT Press","publisher-place":"Durham","issued":{"date-parts":[[2000]]}}, +{"id":"benchmark-41","type":"article-journal","title":"Benchmark article title 35: a critical reading","author":[{"family":"Hall","given":"Morgan"},{"family":"Kristeva","given":"Morgan"}],"container-title":"boundary 2","volume":"14","issue":"3","page":"202–205","issued":{"date-parts":[[2024]]},"DOI":"10.9999/benchmark.0035"}, +{"id":"benchmark-42","type":"book","title":"Benchmark book title 99: a scholarly monograph","author":[{"family":"Beauvoir","given":"Morgan"}],"publisher":"Columbia University Press","publisher-place":"London","issued":{"date-parts":[[2018]]}}, +{"id":"benchmark-43","type":"webpage","title":"Benchmark online source 189: digital humanities perspectives","author":[{"family":"Benjamin","given":"Sam"}],"container-title":"Benchmark Journal Online 5","issued":{"date-parts":[[2003]]},"accessed":{"date-parts":[[2024,1,15]]},"URL":"https://www.cambridge.org/article/000189"}, +{"id":"benchmark-44","type":"book","title":"Benchmark book title 118: a scholarly monograph","author":[{"family":"Foucault","given":"Taylor"}],"publisher":"Princeton University Press","publisher-place":"New York","issued":{"date-parts":[[2002]]}}, +{"id":"benchmark-45","type":"book","title":"Benchmark book title 119: a scholarly monograph","author":[{"family":"Fraser","given":"Quinn"}],"publisher":"Columbia University Press","publisher-place":"Cambridge","issued":{"date-parts":[[2003]]}}, +{"id":"benchmark-46","type":"book","title":"Benchmark book title 84: a scholarly monograph","author":[{"family":"Weber","given":"Robin"}],"publisher":"Routledge","publisher-place":"Oxford","issued":{"date-parts":[[2003]]}}, +{"id":"benchmark-47","type":"webpage","title":"Benchmark online source 188: digital humanities perspectives","author":[{"family":"Beauvoir","given":"Robin"}],"container-title":"Benchmark Journal Online 4","issued":{"date-parts":[[2002]]},"accessed":{"date-parts":[[2024,1,15]]},"URL":"https://www.tandfonline.com/article/000188"}, +{"id":"benchmark-48","type":"article-journal","title":"Benchmark article title 51: a critical reading","author":[{"family":"Lyotard","given":"Morgan"},{"family":"Nussbaum","given":"Morgan"}],"container-title":"New Left Review","volume":"30","issue":"3","page":"250–253","issued":{"date-parts":[[2005]]},"DOI":"10.9999/benchmark.0051"}, +{"id":"benchmark-49","type":"article-journal","title":"Benchmark article title 49: a critical reading","author":[{"family":"Lorde","given":"Alex"},{"family":"Mouffe","given":"Alex"}],"container-title":"Journal of Comparative Literature","volume":"28","issue":"1","page":"244–247","issued":{"date-parts":[[2003]]},"DOI":"10.9999/benchmark.0049"}, +{"id":"benchmark-50","type":"article-journal","title":"Benchmark article title 48: a critical reading","author":[{"family":"Levi-Strauss","given":"Drew"},{"family":"Morrison","given":"Drew"}],"container-title":"Representations","volume":"27","issue":"4","page":"241–244","issued":{"date-parts":[[2002]]},"DOI":"10.9999/benchmark.0048"}, +{"id":"benchmark-51","type":"article-journal","title":"Benchmark article title 72: a critical reading","author":[{"family":"Sedgwick","given":"Drew"},{"family":"Virilio","given":"Drew"}],"container-title":"Representations","volume":"21","issue":"4","page":"313–316","issued":{"date-parts":[[1991]]},"DOI":"10.9999/benchmark.0072"}, +{"id":"benchmark-52","type":"thesis","title":"Benchmark thesis 153: interdisciplinary approaches to knowledge","author":[{"family":"Peirce","given":"Alex"}],"publisher":"Columbia University","genre":"PhD dissertation","issued":{"date-parts":[[2002]]}}, +{"id":"benchmark-53","type":"article-journal","title":"Benchmark article title 19: a critical reading","author":[{"family":"Damasio","given":"Morgan"},{"family":"Foucault","given":"Morgan"}],"container-title":"Cultural Studies","volume":"28","issue":"3","page":"154–157","issued":{"date-parts":[[2008]]},"DOI":"10.9999/benchmark.0019"}, +{"id":"benchmark-54","type":"article-journal","title":"Benchmark article title 70: a critical reading","author":[{"family":"Said","given":"Taylor"},{"family":"Turner","given":"Taylor"}],"container-title":"Postcolonial Studies","volume":"19","issue":"2","page":"307–310","issued":{"date-parts":[[2024]]},"DOI":"10.9999/benchmark.0070"}, +{"id":"benchmark-55","type":"book","title":"Benchmark book title 89: a scholarly monograph","author":[{"family":"Zizek","given":"Alex"}],"publisher":"Columbia University Press","publisher-place":"Cambridge","issued":{"date-parts":[[2008]]}}, +{"id":"benchmark-56","type":"report","title":"Benchmark report 193: empirical findings and policy implications","author":[{"family":"Chakrabarty","given":"Alex"}],"publisher":"Columbia University","number":"292","issued":{"date-parts":[[2007]]},"URL":"https://www.tandfonline.com/article/000193"}, +{"id":"benchmark-57","type":"article-journal","title":"Benchmark article title 33: a critical reading","author":[{"family":"Gilroy","given":"Alex"},{"family":"Jameson","given":"Alex"}],"container-title":"Feminist Review","volume":"12","issue":"1","page":"196–199","issued":{"date-parts":[[2022]]},"DOI":"10.9999/benchmark.0033"}, +{"id":"benchmark-58","type":"article-journal","title":"Benchmark article title 50: a critical reading","author":[{"family":"Lukacs","given":"Jordan"},{"family":"Nancy","given":"Jordan"}],"container-title":"Critical Inquiry","volume":"29","issue":"2","page":"247–250","issued":{"date-parts":[[2004]]},"DOI":"10.9999/benchmark.0050"}, +{"id":"benchmark-59","type":"chapter","title":"Benchmark chapter title 121: situated knowledge","author":[{"family":"Geertz","given":"Alex"}],"editor":[{"family":"Marx","given":"Alex"}],"container-title":"Benchmark edited volume 1","publisher":"University of Chicago Press","publisher-place":"Chicago","page":"290–310","issued":{"date-parts":[[2005]]}}, +{"id":"benchmark-60","type":"webpage","title":"Benchmark online source 175: digital humanities perspectives","author":[{"family":"Williams","given":"Quinn"}],"container-title":"Benchmark Journal Online 7","issued":{"date-parts":[[2024]]},"accessed":{"date-parts":[[2024,1,15]]},"URL":"https://www.wiley.com/article/000175"}, +{"id":"benchmark-61","type":"article-journal","title":"Benchmark article title 29: a critical reading","author":[{"family":"Foucault","given":"Sam"},{"family":"Hegel","given":"Sam"}],"container-title":"PMLA","volume":"38","issue":"1","page":"184–187","issued":{"date-parts":[[2018]]},"DOI":"10.9999/benchmark.0029"}, +{"id":"benchmark-62","type":"chapter","title":"Benchmark chapter title 125: situated knowledge","author":[{"family":"Haraway","given":"Sam"}],"editor":[{"family":"Mignolo","given":"Sam"}],"container-title":"Benchmark edited volume 5","publisher":"Polity Press","publisher-place":"Cambridge","page":"298–318","issued":{"date-parts":[[2009]]}}, +{"id":"benchmark-63","type":"article-journal","title":"Benchmark article title 1: a critical reading","author":[{"family":"Abbott","given":"Alex"},{"family":"Benjamin","given":"Alex"}],"container-title":"Journal of Comparative Literature","volume":"10","issue":"1","page":"100–103","issued":{"date-parts":[[1990]]},"DOI":"10.9999/benchmark.0001"}, +{"id":"benchmark-64","type":"book","title":"Benchmark book title 111: a scholarly monograph","author":[{"family":"Derrida","given":"Quinn"}],"publisher":"University of Chicago Press","publisher-place":"London","issued":{"date-parts":[[1995]]}}, +{"id":"benchmark-65","type":"book","title":"Benchmark book title 97: a scholarly monograph","author":[{"family":"Barad","given":"Alex"}],"publisher":"Oxford University Press","publisher-place":"Chicago","issued":{"date-parts":[[2016]]}}, +{"id":"benchmark-66","type":"article-journal","title":"Benchmark article title 16: a critical reading","author":[{"family":"Chomsky","given":"Drew"},{"family":"Elden","given":"Drew"}],"container-title":"Social Text","volume":"25","issue":"4","page":"145–148","issued":{"date-parts":[[2005]]},"DOI":"10.9999/benchmark.0016"}, +{"id":"benchmark-67","type":"article-journal","title":"Benchmark article title 41: a critical reading","author":[{"family":"hooks","given":"Alex"},{"family":"Lyotard","given":"Alex"}],"container-title":"PMLA","volume":"20","issue":"1","page":"220–223","issued":{"date-parts":[[1995]]},"DOI":"10.9999/benchmark.0041"}, +{"id":"benchmark-68","type":"article-journal","title":"Benchmark article title 32: a critical reading","author":[{"family":"Geertz","given":"Drew"},{"family":"Irigaray","given":"Drew"}],"container-title":"Theory, Culture & Society","volume":"11","issue":"4","page":"193–196","issued":{"date-parts":[[2021]]},"DOI":"10.9999/benchmark.0032"}, +{"id":"benchmark-69","type":"article-journal","title":"Benchmark article title 71: a critical reading","author":[{"family":"Saussure","given":"Quinn"},{"family":"Vattimo","given":"Quinn"}],"container-title":"boundary 2","volume":"20","issue":"3","page":"310–313","issued":{"date-parts":[[1990]]},"DOI":"10.9999/benchmark.0071"}, +{"id":"benchmark-70","type":"book","title":"Benchmark book title 100: a scholarly monograph","author":[{"family":"Benjamin","given":"Robin"}],"publisher":"Harvard University Press","publisher-place":"New York","issued":{"date-parts":[[2019]]}}, +{"id":"benchmark-71","type":"article-journal","title":"Benchmark article title 45: a critical reading","author":[{"family":"Kristeva","given":"Sam"},{"family":"Merleau-Ponty","given":"Sam"}],"container-title":"Feminist Review","volume":"24","issue":"1","page":"232–235","issued":{"date-parts":[[1999]]},"DOI":"10.9999/benchmark.0045"}, +{"id":"benchmark-72","type":"article-journal","title":"Benchmark article title 73: a critical reading","author":[{"family":"Senghor","given":"Alex"},{"family":"Wallerstein","given":"Alex"}],"container-title":"Journal of Comparative Literature","volume":"22","issue":"1","page":"316–319","issued":{"date-parts":[[1992]]},"DOI":"10.9999/benchmark.0073"}, +{"id":"benchmark-73","type":"chapter","title":"Benchmark chapter title 127: situated knowledge","author":[{"family":"Hayles","given":"Quinn"}],"editor":[{"family":"Morrison","given":"Quinn"}],"container-title":"Benchmark edited volume 7","publisher":"Oxford University Press","publisher-place":"Chicago","page":"302–322","issued":{"date-parts":[[2011]]}}, +{"id":"benchmark-74","type":"book","title":"Benchmark book title 94: a scholarly monograph","author":[{"family":"Arendt","given":"Taylor"}],"publisher":"Routledge","publisher-place":"New York","issued":{"date-parts":[[2013]]}}, +{"id":"benchmark-75","type":"book","title":"Benchmark book title 115: a scholarly monograph","author":[{"family":"Elden","given":"Morgan"}],"publisher":"Polity Press","publisher-place":"Chicago","issued":{"date-parts":[[1999]]}}, +{"id":"benchmark-76","type":"book","title":"Benchmark book title 101: a scholarly monograph","author":[{"family":"Berlant","given":"Sam"}],"publisher":"University of Chicago Press","publisher-place":"Cambridge","issued":{"date-parts":[[2020]]}}, +{"id":"benchmark-77","type":"thesis","title":"Benchmark thesis 165: interdisciplinary approaches to knowledge","author":[{"family":"Smith","given":"Sam"}],"publisher":"MIT","genre":"PhD dissertation","issued":{"date-parts":[[2014]]}}, +{"id":"benchmark-78","type":"thesis","title":"Benchmark thesis 157: interdisciplinary approaches to knowledge","author":[{"family":"Rawls","given":"Sam"}],"publisher":"Duke University","genre":"PhD dissertation","issued":{"date-parts":[[2006]]}}, +{"id":"benchmark-79","type":"webpage","title":"Benchmark online source 173: digital humanities perspectives","author":[{"family":"Weber","given":"Sam"}],"container-title":"Benchmark Journal Online 5","issued":{"date-parts":[[2022]]},"accessed":{"date-parts":[[2024,1,15]]},"URL":"https://www.tandfonline.com/article/000173"}, +{"id":"benchmark-80","type":"thesis","title":"Benchmark thesis 161: interdisciplinary approaches to knowledge","author":[{"family":"Sedgwick","given":"Alex"}],"publisher":"University of Chicago","genre":"PhD dissertation","issued":{"date-parts":[[2010]]}}, +{"id":"benchmark-81","type":"book","title":"Benchmark book title 86: a scholarly monograph","author":[{"family":"Williams","given":"Taylor"}],"publisher":"MIT Press","publisher-place":"Durham","issued":{"date-parts":[[2005]]}}, +{"id":"benchmark-82","type":"chapter","title":"Benchmark chapter title 129: situated knowledge","author":[{"family":"Heidegger","given":"Alex"}],"editor":[{"family":"Nancy","given":"Alex"}],"container-title":"Benchmark edited volume 9","publisher":"Columbia University Press","publisher-place":"London","page":"306–326","issued":{"date-parts":[[2013]]}}, +{"id":"benchmark-83","type":"book","title":"Benchmark book title 105: a scholarly monograph","author":[{"family":"Chomsky","given":"Alex"}],"publisher":"Polity Press","publisher-place":"London","issued":{"date-parts":[[2024]]}}, +{"id":"benchmark-84","type":"article-journal","title":"Benchmark article title 76: a critical reading","author":[{"family":"Smith","given":"Robin"},{"family":"Williams","given":"Robin"}],"container-title":"Social Text","volume":"25","issue":"4","page":"325–328","issued":{"date-parts":[[1995]]},"DOI":"10.9999/benchmark.0076"}, +{"id":"benchmark-85","type":"chapter","title":"Benchmark chapter title 141: situated knowledge","author":[{"family":"Marx","given":"Sam"}],"editor":[{"family":"Sedgwick","given":"Sam"}],"container-title":"Benchmark edited volume 6","publisher":"University of Chicago Press","publisher-place":"London","page":"330–350","issued":{"date-parts":[[1990]]}}, +{"id":"benchmark-86","type":"thesis","title":"Benchmark thesis 168: interdisciplinary approaches to knowledge","author":[{"family":"Tsing","given":"Drew"}],"publisher":"Columbia University","genre":"Master's thesis","issued":{"date-parts":[[2017]]}}, +{"id":"benchmark-87","type":"book","title":"Benchmark book title 92: a scholarly monograph","author":[{"family":"Adorno","given":"Robin"}],"publisher":"Duke University Press","publisher-place":"Durham","issued":{"date-parts":[[2011]]}}, +{"id":"benchmark-88","type":"article-journal","title":"Benchmark article title 2: a critical reading","author":[{"family":"Achebe","given":"Jordan"},{"family":"Berlant","given":"Jordan"}],"container-title":"Critical Inquiry","volume":"11","issue":"2","page":"103–106","issued":{"date-parts":[[1991]]},"DOI":"10.9999/benchmark.0002"}, +{"id":"benchmark-89","type":"thesis","title":"Benchmark thesis 156: interdisciplinary approaches to knowledge","author":[{"family":"Ranciere","given":"Robin"}],"publisher":"University of Chicago","genre":"Master's thesis","issued":{"date-parts":[[2005]]}}, +{"id":"benchmark-90","type":"book","title":"Benchmark book title 98: a scholarly monograph","author":[{"family":"Barthes","given":"Jordan"}],"publisher":"Princeton University Press","publisher-place":"Durham","issued":{"date-parts":[[2017]]}}, +{"id":"benchmark-91","type":"article-journal","title":"Benchmark article title 23: a critical reading","author":[{"family":"Dolar","given":"Quinn"},{"family":"Gilroy","given":"Quinn"}],"container-title":"boundary 2","volume":"32","issue":"3","page":"166–169","issued":{"date-parts":[[2012]]},"DOI":"10.9999/benchmark.0023"}, +{"id":"benchmark-92","type":"webpage","title":"Benchmark online source 176: digital humanities perspectives","author":[{"family":"Wittgenstein","given":"Drew"}],"container-title":"Benchmark Journal Online 8","issued":{"date-parts":[[1990]]},"accessed":{"date-parts":[[2024,1,15]]},"URL":"https://www.jstor.org/article/000176"}, +{"id":"benchmark-93","type":"article-journal","title":"Benchmark article title 67: a critical reading","author":[{"family":"Ranciere","given":"Morgan"},{"family":"Spivak","given":"Morgan"}],"container-title":"Cultural Studies","volume":"16","issue":"3","page":"298–301","issued":{"date-parts":[[2021]]},"DOI":"10.9999/benchmark.0067"}, +{"id":"benchmark-94","type":"chapter","title":"Benchmark chapter title 143: situated knowledge","author":[{"family":"Mbembe","given":"Quinn"}],"editor":[{"family":"Sharpe","given":"Quinn"}],"container-title":"Benchmark edited volume 8","publisher":"Verso","publisher-place":"Cambridge","page":"334–354","issued":{"date-parts":[[1992]]}}, +{"id":"benchmark-95","type":"article-journal","title":"Benchmark article title 77: a critical reading","author":[{"family":"Spivak","given":"Sam"},{"family":"Wittgenstein","given":"Sam"}],"container-title":"PMLA","volume":"26","issue":"1","page":"328–331","issued":{"date-parts":[[1996]]},"DOI":"10.9999/benchmark.0077"}, +{"id":"benchmark-96","type":"report","title":"Benchmark report 194: empirical findings and policy implications","author":[{"family":"Chomsky","given":"Jordan"}],"publisher":"Harvard University","number":"293","issued":{"date-parts":[[2008]]},"URL":"https://www.cambridge.org/article/000194"}, +{"id":"benchmark-97","type":"article-journal","title":"Benchmark article title 17: a critical reading","author":[{"family":"Crenshaw","given":"Alex"},{"family":"Ellison","given":"Alex"}],"container-title":"PMLA","volume":"26","issue":"1","page":"148–151","issued":{"date-parts":[[2006]]},"DOI":"10.9999/benchmark.0017"}, +{"id":"benchmark-98","type":"article-journal","title":"Benchmark article title 38: a critical reading","author":[{"family":"Hayles","given":"Taylor"},{"family":"Levi-Strauss","given":"Taylor"}],"container-title":"Critical Inquiry","volume":"17","issue":"2","page":"211–214","issued":{"date-parts":[[1992]]},"DOI":"10.9999/benchmark.0038"}, +{"id":"benchmark-99","type":"book","title":"Benchmark book title 109: a scholarly monograph","author":[{"family":"Dean","given":"Sam"}],"publisher":"Columbia University Press","publisher-place":"Chicago","issued":{"date-parts":[[1993]]}}, +{"id":"benchmark-100","type":"article-journal","title":"Benchmark article title 62: a critical reading","author":[{"family":"Ong","given":"Taylor"},{"family":"Sedgwick","given":"Taylor"}],"container-title":"Critical Inquiry","volume":"11","issue":"2","page":"283–286","issued":{"date-parts":[[2016]]},"DOI":"10.9999/benchmark.0062"}, +{"id":"benchmark-101","type":"chapter","title":"Benchmark chapter title 122: situated knowledge","author":[{"family":"Gilroy","given":"Jordan"}],"editor":[{"family":"Massey","given":"Jordan"}],"container-title":"Benchmark edited volume 2","publisher":"Duke University Press","publisher-place":"Durham","page":"292–312","issued":{"date-parts":[[2006]]}}, +{"id":"benchmark-102","type":"chapter","title":"Benchmark chapter title 140: situated knowledge","author":[{"family":"Lyotard","given":"Robin"}],"editor":[{"family":"Saussure","given":"Robin"}],"container-title":"Benchmark edited volume 5","publisher":"Harvard University Press","publisher-place":"Durham","page":"328–348","issued":{"date-parts":[[2024]]}}, +{"id":"benchmark-103","type":"book","title":"Benchmark book title 108: a scholarly monograph","author":[{"family":"Damasio","given":"Robin"}],"publisher":"Princeton University Press","publisher-place":"Oxford","issued":{"date-parts":[[1992]]}}, +{"id":"benchmark-104","type":"thesis","title":"Benchmark thesis 159: interdisciplinary approaches to knowledge","author":[{"family":"Said","given":"Quinn"}],"publisher":"Harvard University","genre":"PhD dissertation","issued":{"date-parts":[[2008]]}}, +{"id":"benchmark-105","type":"webpage","title":"Benchmark online source 180: digital humanities perspectives","author":[{"family":"Achebe","given":"Robin"}],"container-title":"Benchmark Journal Online 4","issued":{"date-parts":[[1994]]},"accessed":{"date-parts":[[2024,1,15]]},"URL":"https://www.wiley.com/article/000180"}, +{"id":"benchmark-106","type":"thesis","title":"Benchmark thesis 158: interdisciplinary approaches to knowledge","author":[{"family":"Ricoeur","given":"Taylor"}],"publisher":"Columbia University","genre":"Master's thesis","issued":{"date-parts":[[2007]]}}, +{"id":"benchmark-107","type":"chapter","title":"Benchmark chapter title 142: situated knowledge","author":[{"family":"Massey","given":"Taylor"}],"editor":[{"family":"Senghor","given":"Taylor"}],"container-title":"Benchmark edited volume 7","publisher":"Duke University Press","publisher-place":"New York","page":"332–352","issued":{"date-parts":[[1991]]}}, +{"id":"benchmark-108","type":"chapter","title":"Benchmark chapter title 148: situated knowledge","author":[{"family":"Mouffe","given":"Robin"}],"editor":[{"family":"Tsing","given":"Robin"}],"container-title":"Benchmark edited volume 13","publisher":"Princeton University Press","publisher-place":"New York","page":"344–364","issued":{"date-parts":[[1997]]}}, +{"id":"benchmark-109","type":"article-journal","title":"Benchmark article title 43: a critical reading","author":[{"family":"Jameson","given":"Morgan"},{"family":"Massey","given":"Morgan"}],"container-title":"Cultural Studies","volume":"22","issue":"3","page":"226–229","issued":{"date-parts":[[1997]]},"DOI":"10.9999/benchmark.0043"}, +{"id":"benchmark-110","type":"article-journal","title":"Benchmark article title 42: a critical reading","author":[{"family":"Irigaray","given":"Jordan"},{"family":"Marx","given":"Jordan"}],"container-title":"American Literature","volume":"21","issue":"2","page":"223–226","issued":{"date-parts":[[1996]]},"DOI":"10.9999/benchmark.0042"}, +{"id":"benchmark-111","type":"book","title":"Benchmark book title 114: a scholarly monograph","author":[{"family":"Eagleton","given":"Jordan"}],"publisher":"Routledge","publisher-place":"Oxford","issued":{"date-parts":[[1998]]}}, +{"id":"benchmark-112","type":"thesis","title":"Benchmark thesis 160: interdisciplinary approaches to knowledge","author":[{"family":"Saussure","given":"Drew"}],"publisher":"MIT","genre":"Master's thesis","issued":{"date-parts":[[2009]]}}, +{"id":"benchmark-113","type":"chapter","title":"Benchmark chapter title 150: situated knowledge","author":[{"family":"Nussbaum","given":"Taylor"}],"editor":[{"family":"Vattimo","given":"Taylor"}],"container-title":"Benchmark edited volume 15","publisher":"Harvard University Press","publisher-place":"Oxford","page":"348–368","issued":{"date-parts":[[1999]]}}, +{"id":"benchmark-114","type":"thesis","title":"Benchmark thesis 166: interdisciplinary approaches to knowledge","author":[{"family":"Spivak","given":"Taylor"}],"publisher":"University of Chicago","genre":"Master's thesis","issued":{"date-parts":[[2015]]}}, +{"id":"benchmark-115","type":"webpage","title":"Benchmark online source 177: digital humanities perspectives","author":[{"family":"Wynter","given":"Alex"}],"container-title":"Benchmark Journal Online 1","issued":{"date-parts":[[1991]]},"accessed":{"date-parts":[[2024,1,15]]},"URL":"https://www.muse.jhu.edu/article/000177"}, +{"id":"benchmark-116","type":"chapter","title":"Benchmark chapter title 137: situated knowledge","author":[{"family":"Levi-Strauss","given":"Alex"}],"editor":[{"family":"Rawls","given":"Alex"}],"container-title":"Benchmark edited volume 2","publisher":"Oxford University Press","publisher-place":"Cambridge","page":"322–342","issued":{"date-parts":[[2021]]}}, +{"id":"benchmark-117","type":"book","title":"Benchmark book title 91: a scholarly monograph","author":[{"family":"Achebe","given":"Morgan"}],"publisher":"University of Chicago Press","publisher-place":"Chicago","issued":{"date-parts":[[2010]]}}, +{"id":"benchmark-118","type":"webpage","title":"Benchmark online source 182: digital humanities perspectives","author":[{"family":"Ahmad","given":"Taylor"}],"container-title":"Benchmark Journal Online 6","issued":{"date-parts":[[1996]]},"accessed":{"date-parts":[[2024,1,15]]},"URL":"https://www.muse.jhu.edu/article/000182"}, +{"id":"benchmark-119","type":"article-journal","title":"Benchmark article title 61: a critical reading","author":[{"family":"Nussbaum","given":"Sam"},{"family":"Saussure","given":"Sam"}],"container-title":"Journal of Comparative Literature","volume":"10","issue":"1","page":"280–283","issued":{"date-parts":[[2015]]},"DOI":"10.9999/benchmark.0061"}, +{"id":"benchmark-120","type":"webpage","title":"Benchmark online source 185: digital humanities perspectives","author":[{"family":"Azoulay","given":"Alex"}],"container-title":"Benchmark Journal Online 1","issued":{"date-parts":[[1999]]},"accessed":{"date-parts":[[2024,1,15]]},"URL":"https://www.wiley.com/article/000185"}, +{"id":"benchmark-121","type":"chapter","title":"Benchmark chapter title 135: situated knowledge","author":[{"family":"Lacan","given":"Quinn"}],"editor":[{"family":"Quijano","given":"Quinn"}],"container-title":"Benchmark edited volume 15","publisher":"Polity Press","publisher-place":"London","page":"318–338","issued":{"date-parts":[[2019]]}}, +{"id":"benchmark-122","type":"article-journal","title":"Benchmark article title 64: a critical reading","author":[{"family":"Peirce","given":"Drew"},{"family":"Sharpe","given":"Drew"}],"container-title":"Social Text","volume":"13","issue":"4","page":"289–292","issued":{"date-parts":[[2018]]},"DOI":"10.9999/benchmark.0064"}, +{"id":"benchmark-123","type":"thesis","title":"Benchmark thesis 164: interdisciplinary approaches to knowledge","author":[{"family":"Simmel","given":"Robin"}],"publisher":"Harvard University","genre":"Master's thesis","issued":{"date-parts":[[2013]]}}, +{"id":"benchmark-124","type":"article-journal","title":"Benchmark article title 6: a critical reading","author":[{"family":"Atwood","given":"Taylor"},{"family":"Chomsky","given":"Taylor"}],"container-title":"American Literature","volume":"15","issue":"2","page":"115–118","issued":{"date-parts":[[1995]]},"DOI":"10.9999/benchmark.0006"}, +{"id":"benchmark-125","type":"article-journal","title":"Benchmark article title 75: a critical reading","author":[{"family":"Simmel","given":"Morgan"},{"family":"West","given":"Morgan"}],"container-title":"New Left Review","volume":"24","issue":"3","page":"322–325","issued":{"date-parts":[[1994]]},"DOI":"10.9999/benchmark.0075"}, +{"id":"benchmark-126","type":"thesis","title":"Benchmark thesis 151: interdisciplinary approaches to knowledge","author":[{"family":"Ong","given":"Quinn"}],"publisher":"University of Chicago","genre":"PhD dissertation","issued":{"date-parts":[[2000]]}}, +{"id":"benchmark-127","type":"thesis","title":"Benchmark thesis 155: interdisciplinary approaches to knowledge","author":[{"family":"Quijano","given":"Morgan"}],"publisher":"MIT","genre":"PhD dissertation","issued":{"date-parts":[[2004]]}}, +{"id":"benchmark-128","type":"report","title":"Benchmark report 197: empirical findings and policy implications","author":[{"family":"Damasio","given":"Sam"}],"publisher":"Duke University","number":"296","issued":{"date-parts":[[2011]]},"URL":"https://www.muse.jhu.edu/article/000197"}, +{"id":"benchmark-129","type":"article-journal","title":"Benchmark article title 22: a critical reading","author":[{"family":"Derrida","given":"Taylor"},{"family":"Geertz","given":"Taylor"}],"container-title":"Postcolonial Studies","volume":"31","issue":"2","page":"163–166","issued":{"date-parts":[[2011]]},"DOI":"10.9999/benchmark.0022"}, +{"id":"benchmark-130","type":"article-journal","title":"Benchmark article title 78: a critical reading","author":[{"family":"Taylor","given":"Taylor"},{"family":"Wynter","given":"Taylor"}],"container-title":"American Literature","volume":"27","issue":"2","page":"331–334","issued":{"date-parts":[[1997]]},"DOI":"10.9999/benchmark.0078"}, +{"id":"benchmark-131","type":"article-journal","title":"Benchmark article title 53: a critical reading","author":[{"family":"Massey","given":"Sam"},{"family":"Parisi","given":"Sam"}],"container-title":"PMLA","volume":"32","issue":"1","page":"256–259","issued":{"date-parts":[[2007]]},"DOI":"10.9999/benchmark.0053"}, +{"id":"benchmark-132","type":"chapter","title":"Benchmark chapter title 134: situated knowledge","author":[{"family":"Kristeva","given":"Taylor"}],"editor":[{"family":"Polanyi","given":"Taylor"}],"container-title":"Benchmark edited volume 14","publisher":"Routledge","publisher-place":"Durham","page":"316–336","issued":{"date-parts":[[2018]]}}, +{"id":"benchmark-133","type":"article-journal","title":"Benchmark article title 13: a critical reading","author":[{"family":"Bourdieu","given":"Sam"},{"family":"Dolar","given":"Sam"}],"container-title":"Journal of Comparative Literature","volume":"22","issue":"1","page":"136–139","issued":{"date-parts":[[2002]]},"DOI":"10.9999/benchmark.0013"}, +{"id":"benchmark-134","type":"report","title":"Benchmark report 195: empirical findings and policy implications","author":[{"family":"Crenshaw","given":"Morgan"}],"publisher":"MIT","number":"294","issued":{"date-parts":[[2009]]},"URL":"https://www.wiley.com/article/000195"}, +{"id":"benchmark-135","type":"article-journal","title":"Benchmark article title 69: a critical reading","author":[{"family":"Ricoeur","given":"Sam"},{"family":"Tsing","given":"Sam"}],"container-title":"Feminist Review","volume":"18","issue":"1","page":"304–307","issued":{"date-parts":[[2023]]},"DOI":"10.9999/benchmark.0069"}, +{"id":"benchmark-136","type":"chapter","title":"Benchmark chapter title 130: situated knowledge","author":[{"family":"hooks","given":"Jordan"}],"editor":[{"family":"Nussbaum","given":"Jordan"}],"container-title":"Benchmark edited volume 10","publisher":"Harvard University Press","publisher-place":"New York","page":"308–328","issued":{"date-parts":[[2014]]}}, +{"id":"benchmark-137","type":"article-journal","title":"Benchmark article title 46: a critical reading","author":[{"family":"Lacan","given":"Taylor"},{"family":"Mignolo","given":"Taylor"}],"container-title":"Postcolonial Studies","volume":"25","issue":"2","page":"235–238","issued":{"date-parts":[[2000]]},"DOI":"10.9999/benchmark.0046"}, +{"id":"benchmark-138","type":"thesis","title":"Benchmark thesis 163: interdisciplinary approaches to knowledge","author":[{"family":"Sharpe","given":"Morgan"}],"publisher":"Columbia University","genre":"PhD dissertation","issued":{"date-parts":[[2012]]}}, +{"id":"benchmark-139","type":"article-journal","title":"Benchmark article title 3: a critical reading","author":[{"family":"Adorno","given":"Morgan"},{"family":"Bourdieu","given":"Morgan"}],"container-title":"New Left Review","volume":"12","issue":"3","page":"106–109","issued":{"date-parts":[[1992]]},"DOI":"10.9999/benchmark.0003"}, +{"id":"benchmark-140","type":"chapter","title":"Benchmark chapter title 138: situated knowledge","author":[{"family":"Lorde","given":"Jordan"}],"editor":[{"family":"Ricoeur","given":"Jordan"}],"container-title":"Benchmark edited volume 3","publisher":"Princeton University Press","publisher-place":"Oxford","page":"324–344","issued":{"date-parts":[[2022]]}}, +{"id":"benchmark-141","type":"chapter","title":"Benchmark chapter title 131: situated knowledge","author":[{"family":"Irigaray","given":"Morgan"}],"editor":[{"family":"Ong","given":"Morgan"}],"container-title":"Benchmark edited volume 11","publisher":"University of Chicago Press","publisher-place":"Cambridge","page":"310–330","issued":{"date-parts":[[2015]]}}, +{"id":"benchmark-142","type":"article-journal","title":"Benchmark article title 8: a critical reading","author":[{"family":"Barad","given":"Drew"},{"family":"Crimp","given":"Drew"}],"container-title":"Theory, Culture & Society","volume":"17","issue":"4","page":"121–124","issued":{"date-parts":[[1997]]},"DOI":"10.9999/benchmark.0008"}, +{"id":"benchmark-143","type":"webpage","title":"Benchmark online source 179: digital humanities perspectives","author":[{"family":"Abbott","given":"Morgan"}],"container-title":"Benchmark Journal Online 3","issued":{"date-parts":[[1993]]},"accessed":{"date-parts":[[2024,1,15]]},"URL":"https://www.cambridge.org/article/000179"}, +{"id":"benchmark-144","type":"book","title":"Benchmark book title 88: a scholarly monograph","author":[{"family":"Wynter","given":"Drew"}],"publisher":"Princeton University Press","publisher-place":"New York","issued":{"date-parts":[[2007]]}}, +{"id":"benchmark-145","type":"article-journal","title":"Benchmark article title 7: a critical reading","author":[{"family":"Azoulay","given":"Quinn"},{"family":"Crenshaw","given":"Quinn"}],"container-title":"Cultural Studies","volume":"16","issue":"3","page":"118–121","issued":{"date-parts":[[1996]]},"DOI":"10.9999/benchmark.0007"}, +{"id":"benchmark-146","type":"book","title":"Benchmark book title 102: a scholarly monograph","author":[{"family":"Bourdieu","given":"Taylor"}],"publisher":"Duke University Press","publisher-place":"Oxford","issued":{"date-parts":[[2021]]}}, +{"id":"benchmark-147","type":"book","title":"Benchmark book title 113: a scholarly monograph","author":[{"family":"Douglas","given":"Alex"}],"publisher":"Verso","publisher-place":"Cambridge","issued":{"date-parts":[[1997]]}}, +{"id":"benchmark-148","type":"report","title":"Benchmark report 198: empirical findings and policy implications","author":[{"family":"Dean","given":"Taylor"}],"publisher":"Columbia University","number":"297","issued":{"date-parts":[[2012]]},"URL":"https://www.tandfonline.com/article/000198"}, +{"id":"benchmark-149","type":"article-journal","title":"Benchmark article title 52: a critical reading","author":[{"family":"Marx","given":"Robin"},{"family":"Ong","given":"Robin"}],"container-title":"Social Text","volume":"31","issue":"4","page":"253–256","issued":{"date-parts":[[2006]]},"DOI":"10.9999/benchmark.0052"}, +{"id":"benchmark-150","type":"article-journal","title":"Benchmark article title 14: a critical reading","author":[{"family":"Butler","given":"Taylor"},{"family":"Douglas","given":"Taylor"}],"container-title":"Critical Inquiry","volume":"23","issue":"2","page":"139–142","issued":{"date-parts":[[2003]]},"DOI":"10.9999/benchmark.0014"}, +{"id":"benchmark-151","type":"webpage","title":"Benchmark online source 190: digital humanities perspectives","author":[{"family":"Berlant","given":"Taylor"}],"container-title":"Benchmark Journal Online 6","issued":{"date-parts":[[2004]]},"accessed":{"date-parts":[[2024,1,15]]},"URL":"https://www.wiley.com/article/000190"}, +{"id":"benchmark-152","type":"article-journal","title":"Benchmark article title 80: a critical reading","author":[{"family":"Turner","given":"Drew"},{"family":"Abbott","given":"Drew"}],"container-title":"Theory, Culture & Society","volume":"29","issue":"4","page":"337–340","issued":{"date-parts":[[1999]]},"DOI":"10.9999/benchmark.0080"}, +{"id":"benchmark-153","type":"book","title":"Benchmark book title 90: a scholarly monograph","author":[{"family":"Abbott","given":"Jordan"}],"publisher":"Harvard University Press","publisher-place":"Oxford","issued":{"date-parts":[[2009]]}}, +{"id":"benchmark-154","type":"thesis","title":"Benchmark thesis 167: interdisciplinary approaches to knowledge","author":[{"family":"Taylor","given":"Quinn"}],"publisher":"Duke University","genre":"PhD dissertation","issued":{"date-parts":[[2016]]}}, +{"id":"benchmark-155","type":"webpage","title":"Benchmark online source 172: digital humanities perspectives","author":[{"family":"Wallerstein","given":"Robin"}],"container-title":"Benchmark Journal Online 4","issued":{"date-parts":[[2021]]},"accessed":{"date-parts":[[2024,1,15]]},"URL":"https://www.muse.jhu.edu/article/000172"}, +{"id":"benchmark-156","type":"article-journal","title":"Benchmark article title 34: a critical reading","author":[{"family":"Gramsci","given":"Jordan"},{"family":"Kant","given":"Jordan"}],"container-title":"Postcolonial Studies","volume":"13","issue":"2","page":"199–202","issued":{"date-parts":[[2023]]},"DOI":"10.9999/benchmark.0034"}, +{"id":"benchmark-157","type":"chapter","title":"Benchmark chapter title 123: situated knowledge","author":[{"family":"Gramsci","given":"Morgan"}],"editor":[{"family":"Mbembe","given":"Morgan"}],"container-title":"Benchmark edited volume 3","publisher":"Verso","publisher-place":"London","page":"294–314","issued":{"date-parts":[[2007]]}}, +{"id":"benchmark-158","type":"book","title":"Benchmark book title 96: a scholarly monograph","author":[{"family":"Azoulay","given":"Drew"}],"publisher":"MIT Press","publisher-place":"Oxford","issued":{"date-parts":[[2015]]}}, +{"id":"benchmark-159","type":"book","title":"Benchmark book title 112: a scholarly monograph","author":[{"family":"Dolar","given":"Drew"}],"publisher":"Duke University Press","publisher-place":"New York","issued":{"date-parts":[[1996]]}}, +{"id":"benchmark-160","type":"article-journal","title":"Benchmark article title 56: a critical reading","author":[{"family":"Mignolo","given":"Drew"},{"family":"Quijano","given":"Drew"}],"container-title":"Theory, Culture & Society","volume":"35","issue":"4","page":"265–268","issued":{"date-parts":[[2010]]},"DOI":"10.9999/benchmark.0056"}, +{"id":"benchmark-161","type":"book","title":"Benchmark book title 106: a scholarly monograph","author":[{"family":"Crenshaw","given":"Jordan"}],"publisher":"MIT Press","publisher-place":"New York","issued":{"date-parts":[[1990]]}}, +{"id":"benchmark-162","type":"article-journal","title":"Benchmark article title 30: a critical reading","author":[{"family":"Fraser","given":"Taylor"},{"family":"Heidegger","given":"Taylor"}],"container-title":"American Literature","volume":"39","issue":"2","page":"187–190","issued":{"date-parts":[[2019]]},"DOI":"10.9999/benchmark.0030"}, +{"id":"benchmark-163","type":"chapter","title":"Benchmark chapter title 149: situated knowledge","author":[{"family":"Nancy","given":"Sam"}],"editor":[{"family":"Turner","given":"Sam"}],"container-title":"Benchmark edited volume 14","publisher":"Columbia University Press","publisher-place":"Cambridge","page":"346–366","issued":{"date-parts":[[1998]]}}, +{"id":"benchmark-164","type":"article-journal","title":"Benchmark article title 60: a critical reading","author":[{"family":"Nancy","given":"Robin"},{"family":"Said","given":"Robin"}],"container-title":"Representations","volume":"39","issue":"4","page":"277–280","issued":{"date-parts":[[2014]]},"DOI":"10.9999/benchmark.0060"}, +{"id":"benchmark-165","type":"chapter","title":"Benchmark chapter title 139: situated knowledge","author":[{"family":"Lukacs","given":"Morgan"}],"editor":[{"family":"Said","given":"Morgan"}],"container-title":"Benchmark edited volume 4","publisher":"Columbia University Press","publisher-place":"Chicago","page":"326–346","issued":{"date-parts":[[2023]]}}, +{"id":"benchmark-166","type":"thesis","title":"Benchmark thesis 170: interdisciplinary approaches to knowledge","author":[{"family":"Vattimo","given":"Jordan"}],"publisher":"MIT","genre":"Master's thesis","issued":{"date-parts":[[2019]]}}, +{"id":"benchmark-167","type":"article-journal","title":"Benchmark article title 58: a critical reading","author":[{"family":"Morrison","given":"Jordan"},{"family":"Rawls","given":"Jordan"}],"container-title":"Postcolonial Studies","volume":"37","issue":"2","page":"271–274","issued":{"date-parts":[[2012]]},"DOI":"10.9999/benchmark.0058"}, +{"id":"benchmark-168","type":"report","title":"Benchmark report 192: empirical findings and policy implications","author":[{"family":"Butler","given":"Drew"}],"publisher":"Duke University","number":"291","issued":{"date-parts":[[2006]]},"URL":"https://www.muse.jhu.edu/article/000192"}, +{"id":"benchmark-169","type":"book","title":"Benchmark book title 117: a scholarly monograph","author":[{"family":"Fanon","given":"Sam"}],"publisher":"Oxford University Press","publisher-place":"London","issued":{"date-parts":[[2001]]}}, +{"id":"benchmark-170","type":"book","title":"Benchmark book title 104: a scholarly monograph","author":[{"family":"Chakrabarty","given":"Drew"}],"publisher":"Routledge","publisher-place":"Durham","issued":{"date-parts":[[2023]]}}, +{"id":"benchmark-171","type":"article-journal","title":"Benchmark article title 55: a critical reading","author":[{"family":"Merleau-Ponty","given":"Quinn"},{"family":"Polanyi","given":"Quinn"}],"container-title":"Cultural Studies","volume":"34","issue":"3","page":"262–265","issued":{"date-parts":[[2009]]},"DOI":"10.9999/benchmark.0055"}, +{"id":"benchmark-172","type":"article-journal","title":"Benchmark article title 26: a critical reading","author":[{"family":"Elden","given":"Jordan"},{"family":"Haraway","given":"Jordan"}],"container-title":"Critical Inquiry","volume":"35","issue":"2","page":"175–178","issued":{"date-parts":[[2015]]},"DOI":"10.9999/benchmark.0026"}, +{"id":"benchmark-173","type":"article-journal","title":"Benchmark article title 44: a critical reading","author":[{"family":"Kant","given":"Robin"},{"family":"Mbembe","given":"Robin"}],"container-title":"Theory, Culture & Society","volume":"23","issue":"4","page":"229–232","issued":{"date-parts":[[1998]]},"DOI":"10.9999/benchmark.0044"}, +{"id":"benchmark-174","type":"article-journal","title":"Benchmark article title 66: a critical reading","author":[{"family":"Quijano","given":"Jordan"},{"family":"Smith","given":"Jordan"}],"container-title":"American Literature","volume":"15","issue":"2","page":"295–298","issued":{"date-parts":[[2020]]},"DOI":"10.9999/benchmark.0066"}, +{"id":"benchmark-175","type":"book","title":"Benchmark book title 103: a scholarly monograph","author":[{"family":"Butler","given":"Quinn"}],"publisher":"Verso","publisher-place":"Chicago","issued":{"date-parts":[[2022]]}}, +{"id":"benchmark-176","type":"chapter","title":"Benchmark chapter title 136: situated knowledge","author":[{"family":"Latour","given":"Drew"}],"editor":[{"family":"Ranciere","given":"Drew"}],"container-title":"Benchmark edited volume 1","publisher":"MIT Press","publisher-place":"New York","page":"320–340","issued":{"date-parts":[[2020]]}}, +{"id":"benchmark-177","type":"book","title":"Benchmark book title 83: a scholarly monograph","author":[{"family":"Wallerstein","given":"Morgan"}],"publisher":"Verso","publisher-place":"Cambridge","issued":{"date-parts":[[2002]]}}, +{"id":"benchmark-178","type":"webpage","title":"Benchmark online source 178: digital humanities perspectives","author":[{"family":"Zizek","given":"Jordan"}],"container-title":"Benchmark Journal Online 2","issued":{"date-parts":[[1992]]},"accessed":{"date-parts":[[2024,1,15]]},"URL":"https://www.tandfonline.com/article/000178"}, +{"id":"benchmark-179","type":"chapter","title":"Benchmark chapter title 144: situated knowledge","author":[{"family":"Merleau-Ponty","given":"Drew"}],"editor":[{"family":"Simmel","given":"Drew"}],"container-title":"Benchmark edited volume 9","publisher":"Routledge","publisher-place":"Oxford","page":"336–356","issued":{"date-parts":[[1993]]}}, +{"id":"benchmark-180","type":"article-journal","title":"Benchmark article title 12: a critical reading","author":[{"family":"Berlant","given":"Robin"},{"family":"Derrida","given":"Robin"}],"container-title":"Representations","volume":"21","issue":"4","page":"133–136","issued":{"date-parts":[[2001]]},"DOI":"10.9999/benchmark.0012"}, +{"id":"benchmark-181","type":"article-journal","title":"Benchmark article title 57: a critical reading","author":[{"family":"Moraga","given":"Alex"},{"family":"Ranciere","given":"Alex"}],"container-title":"Feminist Review","volume":"36","issue":"1","page":"268–271","issued":{"date-parts":[[2011]]},"DOI":"10.9999/benchmark.0057"}, +{"id":"benchmark-182","type":"article-journal","title":"Benchmark article title 4: a critical reading","author":[{"family":"Ahmad","given":"Robin"},{"family":"Butler","given":"Robin"}],"container-title":"Social Text","volume":"13","issue":"4","page":"109–112","issued":{"date-parts":[[1993]]},"DOI":"10.9999/benchmark.0004"}, +{"id":"benchmark-183","type":"book","title":"Benchmark book title 93: a scholarly monograph","author":[{"family":"Ahmad","given":"Sam"}],"publisher":"Verso","publisher-place":"London","issued":{"date-parts":[[2012]]}}, +{"id":"benchmark-184","type":"article-journal","title":"Benchmark article title 10: a critical reading","author":[{"family":"Beauvoir","given":"Jordan"},{"family":"Dean","given":"Jordan"}],"container-title":"Postcolonial Studies","volume":"19","issue":"2","page":"127–130","issued":{"date-parts":[[1999]]},"DOI":"10.9999/benchmark.0010"}, +{"id":"benchmark-185","type":"article-journal","title":"Benchmark article title 40: a critical reading","author":[{"family":"Heidegger","given":"Drew"},{"family":"Lukacs","given":"Drew"}],"container-title":"Social Text","volume":"19","issue":"4","page":"217–220","issued":{"date-parts":[[1994]]},"DOI":"10.9999/benchmark.0040"}, +{"id":"benchmark-186","type":"webpage","title":"Benchmark online source 184: digital humanities perspectives","author":[{"family":"Atwood","given":"Drew"}],"container-title":"Benchmark Journal Online 8","issued":{"date-parts":[[1998]]},"accessed":{"date-parts":[[2024,1,15]]},"URL":"https://www.cambridge.org/article/000184"}, +{"id":"benchmark-187","type":"article-journal","title":"Benchmark article title 39: a critical reading","author":[{"family":"Hegel","given":"Quinn"},{"family":"Lorde","given":"Quinn"}],"container-title":"New Left Review","volume":"18","issue":"3","page":"214–217","issued":{"date-parts":[[1993]]},"DOI":"10.9999/benchmark.0039"}, +{"id":"benchmark-188","type":"chapter","title":"Benchmark chapter title 132: situated knowledge","author":[{"family":"Jameson","given":"Robin"}],"editor":[{"family":"Parisi","given":"Robin"}],"container-title":"Benchmark edited volume 12","publisher":"Duke University Press","publisher-place":"Oxford","page":"312–332","issued":{"date-parts":[[2016]]}}, +{"id":"benchmark-189","type":"article-journal","title":"Benchmark article title 18: a critical reading","author":[{"family":"Crimp","given":"Jordan"},{"family":"Fanon","given":"Jordan"}],"container-title":"American Literature","volume":"27","issue":"2","page":"151–154","issued":{"date-parts":[[2007]]},"DOI":"10.9999/benchmark.0018"}, +{"id":"benchmark-190","type":"thesis","title":"Benchmark thesis 152: interdisciplinary approaches to knowledge","author":[{"family":"Parisi","given":"Drew"}],"publisher":"Duke University","genre":"Master's thesis","issued":{"date-parts":[[2001]]}}, +{"id":"benchmark-191","type":"chapter","title":"Benchmark chapter title 126: situated knowledge","author":[{"family":"Harvey","given":"Taylor"}],"editor":[{"family":"Moraga","given":"Taylor"}],"container-title":"Benchmark edited volume 6","publisher":"MIT Press","publisher-place":"Oxford","page":"300–320","issued":{"date-parts":[[2010]]}}, +{"id":"benchmark-192","type":"book","title":"Benchmark book title 120: a scholarly monograph","author":[{"family":"Freud","given":"Drew"}],"publisher":"Harvard University Press","publisher-place":"Oxford","issued":{"date-parts":[[2004]]}}, +{"id":"benchmark-193","type":"article-journal","title":"Benchmark article title 68: a critical reading","author":[{"family":"Rawls","given":"Robin"},{"family":"Taylor","given":"Robin"}],"container-title":"Theory, Culture & Society","volume":"17","issue":"4","page":"301–304","issued":{"date-parts":[[2022]]},"DOI":"10.9999/benchmark.0068"}, +{"id":"benchmark-194","type":"report","title":"Benchmark report 200: empirical findings and policy implications","author":[{"family":"Derrida","given":"Drew"}],"publisher":"MIT","number":"299","issued":{"date-parts":[[2014]]},"URL":"https://www.wiley.com/article/000200"}, +{"id":"benchmark-195","type":"chapter","title":"Benchmark chapter title 128: situated knowledge","author":[{"family":"Hegel","given":"Drew"}],"editor":[{"family":"Mouffe","given":"Drew"}],"container-title":"Benchmark edited volume 8","publisher":"Princeton University Press","publisher-place":"Durham","page":"304–324","issued":{"date-parts":[[2012]]}}, +{"id":"benchmark-196","type":"webpage","title":"Benchmark online source 174: digital humanities perspectives","author":[{"family":"West","given":"Taylor"}],"container-title":"Benchmark Journal Online 6","issued":{"date-parts":[[2023]]},"accessed":{"date-parts":[[2024,1,15]]},"URL":"https://www.cambridge.org/article/000174"}, +{"id":"benchmark-197","type":"webpage","title":"Benchmark online source 186: digital humanities perspectives","author":[{"family":"Barad","given":"Jordan"}],"container-title":"Benchmark Journal Online 2","issued":{"date-parts":[[2000]]},"accessed":{"date-parts":[[2024,1,15]]},"URL":"https://www.jstor.org/article/000186"}, +{"id":"benchmark-198","type":"article-journal","title":"Benchmark article title 54: a critical reading","author":[{"family":"Mbembe","given":"Taylor"},{"family":"Peirce","given":"Taylor"}],"container-title":"American Literature","volume":"33","issue":"2","page":"259–262","issued":{"date-parts":[[2008]]},"DOI":"10.9999/benchmark.0054"}, +{"id":"benchmark-199","type":"thesis","title":"Benchmark thesis 169: interdisciplinary approaches to knowledge","author":[{"family":"Turner","given":"Alex"}],"publisher":"Harvard University","genre":"PhD dissertation","issued":{"date-parts":[[2018]]}}, +{"id":"benchmark-200","type":"article-journal","title":"Benchmark article title 74: a critical reading","author":[{"family":"Sharpe","given":"Jordan"},{"family":"Weber","given":"Jordan"}],"container-title":"Critical Inquiry","volume":"23","issue":"2","page":"319–322","issued":{"date-parts":[[1993]]},"DOI":"10.9999/benchmark.0074"} +] From d8ccf4fd7b35769c2de036ffe8f953525246caca Mon Sep 17 00:00:00 2001 From: Dan Knauss Date: Wed, 17 Jun 2026 00:44:59 -0600 Subject: [PATCH 2/2] test(benchmark): extend perf suite with large-bibliography cases Adds large-size orchestration benchmark cases (style switch and mutation latency over a 200-entry bibliography) to the existing perf test, using the csl-200.json fixture. Self-skipping, consistent with the existing benchmark blocks. Salvaged from experiment/large-bibliography-benchmark. Co-Authored-By: Claude Opus 4.8 --- src/benchmarks/performance-benchmark.test.js | 295 +++++++++++++++++++ 1 file changed, 295 insertions(+) diff --git a/src/benchmarks/performance-benchmark.test.js b/src/benchmarks/performance-benchmark.test.js index 0334169..7b64d52 100644 --- a/src/benchmarks/performance-benchmark.test.js +++ b/src/benchmarks/performance-benchmark.test.js @@ -30,12 +30,35 @@ const FIXTURE_NAMES = [ const STYLE_SWITCH_SEQUENCE = ['ieee', 'vancouver', 'mla-9']; const DEFAULT_STYLE = 'chicago-notes-bibliography'; const RUNS = 5; +const LARGE_SIZES = [75, 100, 150, 200]; +// SPEC §Rate Limiting & Resource Caps budget thresholds +const BUDGET_STYLE_SWITCH_P95_MS = 250; +const BUDGET_MUTATION_P95_MS = 150; +// One style from each family: notes, author-date, numeric +const LARGE_STYLE_FAMILIES = [ + { styleKey: 'chicago-notes-bibliography', family: 'notes' }, + { styleKey: 'chicago-author-date', family: 'author-date' }, + { styleKey: 'ieee', family: 'numeric' }, +]; const BUILD_ASSET_EXTENSIONS = new Set(['.css', '.js', '.php']); function readFixture(name) { return fs.readFileSync(path.join(fixturesDir, name), 'utf8'); } +function loadCslFixture(name) { + return JSON.parse(fs.readFileSync(path.join(fixturesDir, name), 'utf8')); +} + +function cslToEntries(cslItems) { + return cslItems.map((csl, index) => ({ + id: csl.id, + csl, + formattedText: `mock:${csl.title || `Entry ${index + 1}`}`, + displayOverride: null, + })); +} + function round(value) { return Number(value.toFixed(2)); } @@ -329,6 +352,134 @@ async function benchmarkEditorMutationPaths(baseEntries) { }; } +async function benchmarkLargeSizeStyleSwitch(allCslItems) { + const results = []; + + for (const size of LARGE_SIZES) { + const entries = cslToEntries(allCslItems.slice(0, size)); + const byFamily = []; + + for (const { styleKey, family } of LARGE_STYLE_FAMILIES) { + const runs = []; + + for (let index = 0; index < RUNS; index += 1) { + clearFormattingCache(); + const { elapsedMs } = await timeAsync(() => + Promise.resolve( + formatBibliographyEntries( + entries.map((entry) => entry.csl), + styleKey + ) + ) + ); + runs.push(elapsedMs); + } + + const stats = summarize(runs); + byFamily.push({ + styleKey, + family, + ...stats, + exceedsBudget: stats.p95Ms > BUDGET_STYLE_SWITCH_P95_MS, + }); + } + + results.push({ size, byFamily }); + } + + return results; +} + +async function benchmarkLargeSizeMutations(allCslItems) { + const results = []; + const manualCsl = { + id: 'benchmark-add', + type: 'book', + title: 'Benchmark Added Citation', + author: [{ family: 'Benchmark', given: 'Ada' }], + publisher: 'Example Press', + issued: { 'date-parts': [[2026]] }, + }; + + for (const size of LARGE_SIZES) { + const base = cslToEntries(allCslItems.slice(0, size)); + const addRuns = []; + const deleteAuthorDateRuns = []; + const deleteNumericRuns = []; + + for (let index = 0; index < RUNS; index += 1) { + clearFormattingCache(); + const addMutation = await timeAsync(async () => { + const nextEntries = [ + ...base, + { + id: 'benchmark-add', + csl: manualCsl, + formattedText: null, + displayOverride: null, + }, + ]; + const formattedTexts = await formatBibliographyEntries( + nextEntries.map((entry) => entry.csl), + DEFAULT_STYLE + ); + return sortCitations( + nextEntries.map((entry, i) => ({ + ...entry, + formattedText: formattedTexts[i], + })), + DEFAULT_STYLE + ); + }); + addRuns.push(addMutation.elapsedMs); + + clearFormattingCache(); + const deleteAuthorDate = await timeAsync(async () => { + const nextEntries = base.slice(1); + const formattedTexts = await formatBibliographyEntries( + nextEntries.map((entry) => entry.csl), + 'chicago-author-date' + ); + return sortCitations( + nextEntries.map((entry, i) => ({ + ...entry, + formattedText: formattedTexts[i], + })), + 'chicago-author-date' + ); + }); + deleteAuthorDateRuns.push(deleteAuthorDate.elapsedMs); + + const deleteNumeric = await timeAsync(() => { + return Promise.resolve(sortCitations(base.slice(1), 'ieee')); + }); + deleteNumericRuns.push(deleteNumeric.elapsedMs); + } + + const addStats = summarize(addRuns); + const deleteAdStats = summarize(deleteAuthorDateRuns); + const deleteNumStats = summarize(deleteNumericRuns); + + results.push({ + size, + add: { + ...addStats, + exceedsBudget: addStats.p95Ms > BUDGET_MUTATION_P95_MS, + }, + deleteAuthorDate: { + ...deleteAdStats, + exceedsBudget: deleteAdStats.p95Ms > BUDGET_MUTATION_P95_MS, + }, + deleteNumeric: { + ...deleteNumStats, + exceedsBudget: deleteNumStats.p95Ms > BUDGET_MUTATION_P95_MS, + }, + }); + } + + return results; +} + function writeOutputs(report) { fs.mkdirSync(outputDir, { recursive: true }); const jsonPath = path.join(outputDir, 'latest.json'); @@ -390,6 +541,58 @@ function writeOutputs(report) { `| Delete from numeric bibliography | ${report.editorMutations.deleteNumericNoReformat.avgMs} | ${report.editorMutations.deleteNumericNoReformat.p50Ms} | ${report.editorMutations.deleteNumericNoReformat.p95Ms} | Safe no-reformat path; list marker provides numbering. |` ); + if (report.largeSizeStyleSwitch) { + lines.push( + '', + '## Large-size JS orchestration — style switch (mock formatter)', + '', + `Budget: p95 < ${BUDGET_STYLE_SWITCH_P95_MS} ms. Entries from csl-200.json fixture.`, + '', + '| Size | Family | Style | p50 (ms) | p95 (ms) | Budget |', + '| ---: | --- | --- | ---: | ---: | --- |' + ); + for (const row of report.largeSizeStyleSwitch) { + for (const f of row.byFamily) { + lines.push( + `| ${row.size} | ${f.family} | ${f.styleKey} | ${ + f.p50Ms + } | ${f.p95Ms} | ${f.exceedsBudget ? '⚠ over' : 'ok'} |` + ); + } + } + } + + if (report.largeSizeMutations) { + lines.push( + '', + '## Large-size JS orchestration — mutations (mock formatter)', + '', + `Budget: p95 < ${BUDGET_MUTATION_P95_MS} ms.`, + '', + '| Size | Operation | p50 (ms) | p95 (ms) | Budget |', + '| ---: | --- | ---: | ---: | --- |' + ); + for (const row of report.largeSizeMutations) { + lines.push( + `| ${row.size} | add (notes, full reformat) | ${ + row.add.p50Ms + } | ${row.add.p95Ms} | ${ + row.add.exceedsBudget ? '⚠ over' : 'ok' + } |`, + `| ${row.size} | delete — author-date (full reformat) | ${ + row.deleteAuthorDate.p50Ms + } | ${row.deleteAuthorDate.p95Ms} | ${ + row.deleteAuthorDate.exceedsBudget ? '⚠ over' : 'ok' + } |`, + `| ${row.size} | delete — numeric (no reformat) | ${ + row.deleteNumeric.p50Ms + } | ${row.deleteNumeric.p95Ms} | ${ + row.deleteNumeric.exceedsBudget ? '⚠ over' : 'ok' + } |` + ); + } + } + lines.push( '', '## Build footprint', @@ -442,6 +645,98 @@ const runBenchmark = process.env.RUN_PERF_BENCHMARK === '1'; ); }); + it('records large-size JS orchestration overhead', async () => { + const allCslItems = loadCslFixture('csl-200.json'); + + const largeSizeStyleSwitch = await benchmarkLargeSizeStyleSwitch( + allCslItems + ); + const largeSizeMutations = await benchmarkLargeSizeMutations( + allCslItems + ); + + const report = { + generatedAt: new Date().toISOString(), + formatterMode: FORMATTER_MODE, + budgets: { + styleSwitchP95Ms: BUDGET_STYLE_SWITCH_P95_MS, + mutationP95Ms: BUDGET_MUTATION_P95_MS, + }, + largeSizes: LARGE_SIZES, + largeSizeStyleSwitch, + largeSizeMutations, + }; + + fs.mkdirSync(outputDir, { recursive: true }); + const jsonPath = path.join(outputDir, 'large-size.json'); + fs.writeFileSync(jsonPath, `${JSON.stringify(report, null, 2)}\n`); + + const mdLines = [ + '# Large-size JS orchestration benchmark', + '', + `Generated: ${report.generatedAt}`, + `Formatter mode: ${FORMATTER_MODE} (apiFetch mock — JS orchestration only)`, + '', + '## Style switch', + '', + `Budget: p95 < ${BUDGET_STYLE_SWITCH_P95_MS} ms`, + '', + '| Size | Family | Style | p50 (ms) | p95 (ms) | Budget |', + '| ---: | --- | --- | ---: | ---: | --- |', + ]; + for (const row of largeSizeStyleSwitch) { + for (const f of row.byFamily) { + mdLines.push( + `| ${row.size} | ${f.family} | ${f.styleKey} | ${ + f.p50Ms + } | ${f.p95Ms} | ${f.exceedsBudget ? 'OVER' : 'ok'} |` + ); + } + } + mdLines.push( + '', + '## Mutations', + '', + `Budget: p95 < ${BUDGET_MUTATION_P95_MS} ms`, + '', + '| Size | Operation | p50 (ms) | p95 (ms) | Budget |', + '| ---: | --- | ---: | ---: | --- |' + ); + for (const row of largeSizeMutations) { + mdLines.push( + `| ${row.size} | add (notes, full reformat) | ${ + row.add.p50Ms + } | ${row.add.p95Ms} | ${ + row.add.exceedsBudget ? 'OVER' : 'ok' + } |`, + `| ${row.size} | delete — author-date (full reformat) | ${ + row.deleteAuthorDate.p50Ms + } | ${row.deleteAuthorDate.p95Ms} | ${ + row.deleteAuthorDate.exceedsBudget ? 'OVER' : 'ok' + } |`, + `| ${row.size} | delete — numeric (no reformat) | ${ + row.deleteNumeric.p50Ms + } | ${row.deleteNumeric.p95Ms} | ${ + row.deleteNumeric.exceedsBudget ? 'OVER' : 'ok' + } |` + ); + } + const mdPath = path.join(outputDir, 'large-size.md'); + fs.writeFileSync(mdPath, `${mdLines.join('\n')}\n`); + + // eslint-disable-next-line no-console + console.log(`Wrote large-size report to ${jsonPath}`); + + expect(largeSizeStyleSwitch).toHaveLength(LARGE_SIZES.length); + expect(largeSizeMutations).toHaveLength(LARGE_SIZES.length); + // Sort (no-reformat path) must always be fast regardless of list size + for (const row of largeSizeMutations) { + expect(row.deleteNumeric.p95Ms).toBeLessThan( + BUDGET_MUTATION_P95_MS + ); + } + }); + it('records repeatable local benchmark timings', async () => { const warnSpy = jest .spyOn(console, 'warn')