Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion .claude/settings.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,21 @@
"allow": [
"Bash(wc:*)",
"Bash(git:*)",
"Bash(gh pr:*)"
"Bash(gh pr:*)",
"Bash(python3 -c \"import yaml; print\\(yaml.__version__\\)\")",
"Bash(pip3 show *)",
"Bash(pip3 install *)",
"Bash(python3 -c \"from ruamel.yaml import YAML; print\\('ok'\\)\")",
"Bash(mkdir -p /private/tmp/claude-501/-Users-rdm-oss-forrtproject-github-io/d40a3858-03b0-4abe-8e07-eb52ecb3b04b/scratchpad/pubtest/data /private/tmp/claude-501/-Users-rdm-oss-forrtproject-github-io/d40a3858-03b0-4abe-8e07-eb52ecb3b04b/scratchpad/pubtest/scripts)",
"Bash(cp /private/tmp/claude-501/-Users-rdm-oss-forrtproject-github-io/d40a3858-03b0-4abe-8e07-eb52ecb3b04b/scratchpad/publications_test.yaml /private/tmp/claude-501/-Users-rdm-oss-forrtproject-github-io/d40a3858-03b0-4abe-8e07-eb52ecb3b04b/scratchpad/pubtest/data/publications.yaml)",
"Bash(cp /Users/rdm/oss/forrtproject.github.io/scripts/build_publications.py /private/tmp/claude-501/-Users-rdm-oss-forrtproject-github-io/d40a3858-03b0-4abe-8e07-eb52ecb3b04b/scratchpad/pubtest/scripts/)",
"Bash(python3 scripts/build_publications.py)",
"Bash(mkdir -p /private/tmp/claude-501/-Users-rdm-oss-forrtproject-github-io/d40a3858-03b0-4abe-8e07-eb52ecb3b04b/scratchpad/pubtest2/data /private/tmp/claude-501/-Users-rdm-oss-forrtproject-github-io/d40a3858-03b0-4abe-8e07-eb52ecb3b04b/scratchpad/pubtest2/scripts)",
"Bash(cp /Users/rdm/oss/forrtproject.github.io/scripts/build_publications.py /private/tmp/claude-501/-Users-rdm-oss-forrtproject-github-io/d40a3858-03b0-4abe-8e07-eb52ecb3b04b/scratchpad/pubtest2/scripts/)",
"Bash(cat)",
"Bash(mkdir -p /private/tmp/claude-501/-Users-rdm-oss-forrtproject-github-io/d40a3858-03b0-4abe-8e07-eb52ecb3b04b/scratchpad/pubtest3/data /private/tmp/claude-501/-Users-rdm-oss-forrtproject-github-io/d40a3858-03b0-4abe-8e07-eb52ecb3b04b/scratchpad/pubtest3/scripts)",
"Bash(cp /Users/rdm/oss/forrtproject.github.io/scripts/build_publications.py /private/tmp/claude-501/-Users-rdm-oss-forrtproject-github-io/d40a3858-03b0-4abe-8e07-eb52ecb3b04b/scratchpad/pubtest3/scripts/)",
"Bash(python3 scripts/build_publications.py --dry-run)"
]
}
}
15 changes: 15 additions & 0 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,21 @@ Processes:

Triggers `deploy.yaml` after successful processing via `repository_dispatch`.

### [update_publications.yml](workflows/update_publications.yml)
**Hydrates DOI-stub entries in `data/publications.yaml`**

| Trigger | Schedule |
|---------|----------|
| Push to `main` touching `data/publications.yaml` | On push |
| Weekly | Monday 03:30 UTC |
| Manual dispatch | Manual (`force` option to bypass the DOI cache) |

Runs `scripts/build_publications.py`, which fetches title/authors/journal/year/
abstract/citation for any entry with a top-level `doi:` key from Crossref/DataCite
(via doi.org content negotiation). Never commits to `main` directly — opens a PR
for review when metadata changes, same pattern as the glossary-update PR in
`data-processing.yml`. See `content/publications/README` for the entry format.

## Quality Checks

### [spell-check.yaml](workflows/spell-check.yaml)
Expand Down
90 changes: 90 additions & 0 deletions .github/workflows/update_publications.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
name: Update publications

# =====================================================================
# Hydrates DOI-stub entries in data/publications.yaml (see
# scripts/build_publications.py) by fetching title/authors/journal/year/
# abstract/citation from the DOI's registration agency (Crossref/DataCite).
#
# Never commits to main directly: if hydration produces a diff, it's pushed
# to a new branch and opened as a PR for human review before it goes live.
#
# Triggers:
# - push to main touching data/publications.yaml (hydrate a newly added
# DOI stub right away)
# - weekly schedule (catch metadata drift: preprint -> published,
# volume/page assignment, etc.)
# - workflow_dispatch (manual run, optionally ignoring the DOI cache)
# =====================================================================

on:
push:
branches: [main]
paths:
- 'data/publications.yaml'
schedule:
- cron: '30 3 * * 1' # weekly, Monday 03:30 UTC
workflow_dispatch:
inputs:
force:
description: 'Ignore the DOI lookup cache and refetch everything'
required: false
type: boolean
default: false

concurrency:
group: update-publications
cancel-in-progress: false

jobs:
hydrate:
name: Hydrate publication DOIs
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v6

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

- name: Install dependencies
run: pip install ruamel.yaml

- name: Restore DOI metadata cache
uses: actions/cache@v4
with:
path: scripts/publications_doi_cache.json
key: publications-doi-cache-${{ github.run_id }}
restore-keys: |
publications-doi-cache-

- name: Run hydration script
run: |
python3 scripts/build_publications.py ${{ inputs.force && '--force' || '' }}

- name: Create PR with hydrated metadata
env:
GITHUB_TOKEN: ${{ secrets.FORRT_PAT }}
run: |
if [ -z "$(git status --porcelain -- data/publications.yaml)" ]; then
echo "ℹ️ No publication metadata changes detected"
exit 0
fi

BRANCH_NAME="publications-update-$(date +%Y%m%d-%H%M%S)"
git checkout -b "$BRANCH_NAME"

git add data/publications.yaml
git commit -m "Update hydrated publication metadata - $(date -u +'%Y-%m-%d %H:%M:%S UTC')"

git push -u origin "$BRANCH_NAME"

gh pr create \
--title "📚 Publications metadata update - $(date '+%Y-%m-%d')" \
--body "Automated DOI metadata hydration generated on $(date -u +'%Y-%m-%d %H:%M:%S UTC') by scripts/build_publications.py. Please review the hydrated title/authors/abstract/citation fields before merging." \
--base main \
--head "$BRANCH_NAME"
echo "✅ PR created for publications update"
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -277,3 +277,6 @@ bibtex_to_apa/node_modules/

# DOI lookup cache for cluster parsing script
scripts/doi_cache.json

# DOI metadata cache for publications hydration script
scripts/publications_doi_cache.json
55 changes: 53 additions & 2 deletions content/publications/README
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,60 @@

This folder contains PDF files and other publication-related assets. The actual publication data is stored in `/data/publications.yaml` (NOT in this folder).

## Adding a New Publication
## Adding a New Publication (DOI, recommended)

Publications are managed in the **`/data/publications.yaml`** file. This file contains all publication metadata that is displayed on the website.
If the publication has a DOI, you only need to add a minimal stub — a script
fetches the rest. Add an entry with a top-level `doi:` key:

```yaml
- doi: "10.1016/j.socec.2025.102502"
type: "journal" # journal, preprint, media, policy, affiliated, wip
focus_area: "Meta-Research & Scientific Reform"
```

Commit that stub to `data/publications.yaml` and push (or open a PR). The
[update_publications.yml](/.github/workflows/update_publications.yml) workflow
runs `scripts/build_publications.py`, which resolves the DOI via Crossref/DataCite
and fills in `title`, `authors`, `journal_name`, `year`, `status`, `abstract`,
`citation`, `links.doi`, and `altmetric_doi`. It opens a PR with the hydrated
result for review — nothing is pushed straight to `main`.

**On every run, all of the auto-filled fields above are recomputed from the DOI
and will overwrite hand edits.** To pin a field permanently (a custom abstract
blurb, an extra `postprint`/`pdf`/`project` link, a manually-chosen `status`),
add it under `overrides:` instead of editing the auto field directly:

```yaml
- doi: "10.1016/j.socec.2025.102502"
type: "journal"
focus_area: "Meta-Research & Scientific Reform"
overrides:
abstract: "Custom short blurb instead of the paper's full abstract"
status: "In Press"
links:
postprint: "https://osf.io/preprints/..."
pdf: "./pdf/local-copy.pdf"
```

`type` and `focus_area` are never touched by the script — always set those by
hand. If a DOI fails to resolve (bad DOI, API outage), the script leaves that
entry's existing fields untouched and logs a warning rather than blanking them.

Citations are built as
`{authors} ({year}). <strong>{title}.</strong> <em>{journal_name}</em>, {volume}({issue}), {page}. https://doi.org/{doi}`
— good for typical journal articles and preprints, but book chapters and other
unusual venues often need a hand-written `overrides.citation`. Check the PR
diff before merging.

**Note:** Existing publications that predate this pipeline are still fully
hand-written (no top-level `doi:` key) and are left alone by the script —
migrating them to the DOI-stub format is a separate, deliberate task, not
something that happens automatically.

## Adding a New Publication (manual, no DOI)

For publications without a DOI (op-eds, policy briefs, work-in-progress, etc.),
write the full entry by hand as before.

### Steps to Add a Publication

Expand Down
17 changes: 17 additions & 0 deletions content/publications/template.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
# Below is a template for adding a new publication to the publications.yaml file. in data/publications.yaml
# Remove or add the fields as needed following the layout of the existing entries.

# --- Preferred: DOI stub (auto-hydrated by scripts/build_publications.py) ---
# Only `doi`, `type`, and `focus_area` are hand-written; the rest is fetched
# from Crossref/DataCite and refreshed on every run. Pin a field permanently by
# adding it under `overrides:` instead. See content/publications/README.

- doi: "10.xxxx/xxxxx"
type: "journal" # journal, preprint, media, policy, affiliated, wip
focus_area: "Meta-Research & Scientific Reform"
# overrides:
# abstract: "Custom short blurb instead of the paper's full abstract"
# status: "In Press"
# links:
# postprint: "https://osf.io/preprints/..."
# pdf: "./pdf/local-copy.pdf"

# --- Fallback: full manual entry (no DOI, e.g. op-eds, policy briefs, WIP) ---

- title: ""
type: ""
year: ""
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ gspread
python-dotenv
matplotlib
pypinyin
ruamel.yaml
Loading
Loading