Seed PDF Fixtures for the Ready for Annotation Project¶
The seeded Ready for Annotation project owns two systematic searches, and they exist for two different jobs:
| Search | ID | Studies | PDFs uploaded? | What it is for |
|---|---|---|---|---|
| Included Studies | …-000000000202 |
20 (17 with a PDF URL) | Packaged with the environment's web build | Testing the PDF viewer, region marking, graph assignment |
| Bulk PDF Upload Test Set | …-000000000205 |
12 (all with a PDF path) | No — deliberately | Testing the bulk PDF upload feature end to end |
Both are created by DatabaseSeeder in a fresh, explicitly seeded non-production database.
Seeding requires matching non-production RuntimeEnvironment and ActiveEnvironment values,
plus the existing seed-mode/enabled flag. Production, missing and conflicting environment
signals are refused before database access. Existing databases are not overwritten or
reset: they retain their studies, uploads and annotations. The paths live in SeedDataConstants
(ReadyForAnnotationPdfPaths and ReadyForAnnotationBulkPdfPaths) and are index-aligned with
their study ID arrays.
Ready-linked viewer fixtures¶
The 17 viewer PDFs are small synthetic documents committed under
src/services/web/src/assets/seed-pdf-fixtures/seed/. They contain selectable text and a bar
chart for region marking, and explicitly say they are not published research. They contain
no real participant data and require no external-host upload or third-party licence.
The seeder stores these absolute URLs in PdfRelativePath; the existing PdfLinkBuilder.Build
absolute-URL behavior returns them unchanged. No product URL-building behavior changes. The
preview seed job already supplies its own web URL. The supported local process-compose stack
supplies http://localhost:${PORT_ANGULAR}. Missing or invalid web configuration fails before
creating records. Deploy the matching web build before accepting these links as working.
After deployment, verify the actual URL (substitute the chosen preview or staging origin):
curl --fail --head "https://staging.syrf.org.uk/assets/seed-pdf-fixtures/seed/01-mcao-transient-neuroprotection.pdf"
Expect 200, Content-Type: application/pdf, and a rendered page in the signed-in annotation
workflow. HTTP availability alone is not signed-in acceptance. These same-origin fixtures
exercise the viewer; managed-upstream proxy acceptance remains a separate check in #3283/#3284.
The earlier CC BY bundle attribution file is retained for historical bundles; it does not
describe these generated synthetic fixtures. No fixture has been published to the shared
legacy ecrf1 host by this change.
Constraint: seed PDF paths must be portable ASCII¶
PdfLinkBuilder.BuildLegacy concatenates the relative path into the URL without
percent-encoding it. That is deliberate — byte-identical output is what keeps existing production
links working — but it means a seed path containing a space or a non-ASCII character would depend
on the browser to repair the URL.
So every fixture-relative path is lowercase ASCII, hyphen-separated, and free of spaces. Tests and the bundle generator enforce portability. The seeder validates the exact expected set: absolute web-asset URLs for the viewer search, relative paths for the upload search.
Generate or download the bundles¶
Once this web build is deployed, reviewers can download:
<web-origin>/assets/seed-pdf-fixtures/syrf-seed-pdfs-bulk-test.zip— the 12 upload files.<web-origin>/assets/seed-pdf-fixtures/syrf-seed-pdfs-hosted.zip— the 17 viewer files.<web-origin>/assets/seed-pdf-fixtures/SHA256SUMS— deterministic bundle checksums.
Or regenerate locally from the worktree root, with Python 3 and no external dependencies:
Output is .local/seed-pdf-fixtures/. Generation does not contact a server, seed a database,
or publish files. Repeated generation preserves identical bytes; it refuses to overwrite
different existing output. Choose a new --output directory for intentionally changed fixtures.
The generator reads the C# path arrays directly, so the ZIP entries cannot silently drift.
To regenerate the packaged web assets, use
--output src/services/web/src/assets/seed-pdf-fixtures and review the resulting diff.
Included Studies paths¶
The 17 studies that pass screening, in study order. The three studies excluded at screening deliberately carry no path, so the "study has no PDF" state stays representable.
| # | Asset path below /assets/seed-pdf-fixtures/ |
|---|---|
| 1 | seed/01-mcao-transient-neuroprotection.pdf |
| 2 | seed/02-mcao-permanent-infarct-volume.pdf |
| 3 | seed/03-mcao-hypothermia-outcome.pdf |
| 4 | seed/04-intracerebral-haemorrhage-oedema.pdf |
| 5 | seed/05-subarachnoid-haemorrhage-vasospasm.pdf |
| 6 | seed/06-spinal-cord-injury-locomotor-recovery.pdf |
| 7 | seed/07-spinal-cord-injury-graft-survival.pdf |
| 8 | seed/08-traumatic-brain-injury-cognition.pdf |
| 9 | seed/09-traumatic-brain-injury-biomarkers.pdf |
| 10 | seed/10-autoimmune-encephalomyelitis-clinical-score.pdf |
| 11 | seed/11-autoimmune-encephalomyelitis-remyelination.pdf |
| 12 | seed/12-parkinsonian-lesion-rotational-behaviour.pdf |
| 13 | seed/13-alzheimer-model-spatial-memory.pdf |
| 14 | seed/14-neuropathic-pain-mechanical-allodynia.pdf |
| 15 | seed/15-global-ischaemia-hippocampal-cell-loss.pdf |
| 16 | seed/16-stroke-thrombolysis-adjunct-therapy.pdf |
| 17 | seed/17-stroke-stem-cell-therapy.pdf |
Testing bulk PDF upload¶
The Bulk PDF Upload Test Set exists so the feature has real seeded studies to match against.
No individual PDF is hosted for it, and ValidateSeedData asserts that none of its studies has a delivered
path — a delivered file would quietly retire the fixture.
"Undelivered" means BulkPdfDeliveredPath is null, not that linkToPdf is necessarily null:
legacy relative-path behavior can still produce a URL to a missing file. The fixture deliberately
preserves that existing behavior; confirm the real delivery state and successful rendering after upload.
Bulk matching keys on the whole relative path within the folder you pick, not on the file name. The fixture therefore spans three depths on purpose: four files at the root, four one level down, and four two levels down. Lay out a local folder exactly like this and pick that folder:
<your-folder>/
├── bulk-01-mcao-dose-response.pdf
├── bulk-02-mcao-sex-differences.pdf
├── bulk-03-spinal-cord-injury-rehabilitation.pdf
├── bulk-04-traumatic-brain-injury-blast.pdf
├── batch-a/
│ ├── bulk-05-autoimmune-encephalomyelitis-diet.pdf
│ ├── bulk-06-parkinson-neuroinflammation.pdf
│ ├── bulk-07-alzheimer-tau-burden.pdf
│ └── bulk-08-neuropathic-pain-microglia.pdf
└── batch-b/
└── nested/
├── bulk-09-ischaemic-preconditioning.pdf
├── bulk-10-haemorrhage-iron-chelation.pdf
├── bulk-11-neonatal-hypoxia-model.pdf
└── bulk-12-retinal-ischaemia-outcome.pdf
Extract syrf-seed-pdfs-bulk-test.zip into a fresh folder and select that folder, not its parent.
The archive contains exactly 12 synthetic PDFs in this layout, with no extra enclosing directory.
With that folder the match preview should report 12 matched, 0 unmatched, 0 missing. Useful variations to prove the preview is telling the truth:
- Missing studies: delete
batch-a/bulk-07-alzheimer-tau-burden.pdf→ 11 matched, 1 missing. - Unmatched files: add any other PDF → it appears as an unmatched file, and nothing is linked to it.
- Path, not filename: move
bulk-01-mcao-dose-response.pdfintobatch-a/→ it stops matching, because its key changes.
All 12 studies are dual-screened as included, so after a successful upload you can open one in the annotation stage and confirm its PDF now renders — the same viewer path the Included Studies search exercises, but reached through the upload pipeline.
Bulk PDF upload is behind the bulkPdfUpload feature flag, which also requires deletionLifecycle
to be on; see Manage Feature Flags.
Changing the fixtures¶
- Adding a study with a PDF to the Included Studies search: append its ID to
ReadyForAnnotationStudyIds, append the path toReadyForAnnotationPdfPathsat the same index, regenerate the assets and update the explicit count contract/tests. The arrays are index-aligned and the seeder throws if there are more paths than studies. - Renaming a viewer file: preserve already-seeded URLs; coordinate migration rather than silently removing an asset still referenced by an existing database.
- Never upload files for the Bulk PDF Upload Test Set to the static host. That fixture is only useful while it is undelivered.
Reset and repeat safely¶
Regenerating or re-extracting the ZIP resets local files only. Rerunning the seeder against an
existing database preserves completed uploads and annotations; it does not reset the fixture.
For a clean end-to-end run, use a fresh disposable mock-data PR preview, or the established
/reseed-db procedure only after confirming that preview is disposable and obtaining reset
authorization. Never reseed shared staging merely to repeat this test. Existing staging seed
records are not migrated by this change. A legacy seed dataset therefore needs a separately
authorized reset or targeted migration before it can use the new fixture URLs.