File size: 5,571 Bytes
7c6808b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# ResearchBee v1.4 β€” verified-sources release

## What changed, in one line

Policy facts now come from databases, not from the language model. Where no
source could be reached, the system says so instead of filling the gap.

---

## 1. HuggingFace Space β€” `researchbee-hf/`

| File | Status |
|---|---|
| `app.py` | **modified** β€” DOI-first `/api/check-license`, registry-backed `/api/find-repository`, fixed publisher matcher, Khazna startup + 23:30 refresh, new `/api/health` |
| `prompts.py` | **modified** β€” "ResearchPilot" β†’ "ResearchBee" everywhere; `LICENSE_SYSTEM_PROMPT` can no longer state policy facts; new `ADVISORY_NOTE_PROMPT`; `REPO_SYSTEM_PROMPT` constrained to registry selection |
| `oaworks.py` | **new** β€” OA.Works Permissions client, schema-confirmed against T&F / Elsevier / Springer |
| `doi_utils.py` | **new** β€” DOI extraction from URLs and text; ISSN mod-11 validation |
| `repositories.py` | **new** β€” 25-entry curated repository registry |
| `khazna_loader.py` | **new** β€” loads the harvested Khazna index from an HF Dataset |
| `requirements.txt` | **modified** β€” added `huggingface_hub`, `apscheduler` |

Upload all seven. `ku_knowledge.py`, `openalex.py`, `scimago_index.py`,
`utils.py`, `Dockerfile`, and the SCImago CSV are unchanged β€” leave them.

### Before you deploy

1. **Set `KU_ROR` in `oaworks.py`.** Find it at https://ror.org (search
   "Khalifa University"). This matters more than it looks: Elsevier publishes a
   12-month embargo for UK institutions and 24 months for everyone else, and
   the ROR lets OA.Works pick the right one.
2. Optionally set `KHAZNA_DATASET` and `HF_TOKEN` in Space secrets.
3. Check `GET /api/health` after deploy β€” it reports every source's status.

Khazna lookups return `checked: false` until the harvest has run. That is
correct behaviour, not a failure.

---

## 2. GitHub Pages β€” `researchbee-github/`

| File | Status |
|---|---|
| `index.html` | **modified** β€” DOI/URL field added as the primary input |
| `js/license.js` | **modified** β€” sends the DOI, renders provenance, Khazna status, deposit statement |
| `js/render_license.js` | **new** β€” the new render helpers |
| `css/style.css` | **modified** β€” styles appended at the end |
| `khazna_oai.py` | **new** β€” the OAI-PMH harvester (runs in Actions, not in the Space) |
| `.github/workflows/harvest-khazna.yml` | **new** β€” nightly 23:00 Dubai harvest |
| `test_publishers.py` | **new** β€” validation harness |

Other JS files are untouched.

---

## 3. Khazna harvest β€” first run

```bash
# See the deposit gap before automating anything
python khazna_oai.py gap

# Verify the parser against real records
python khazna_oai.py inspect --set publications:withFiles --format mods -n 2 --raw
python khazna_oai.py inspect --set openaire --format oai_dc -n 2 --raw
```

Then:
1. Create an HF **Dataset** repo (default: `nikeshn/researchbee-data`)
2. Add `HF_TOKEN` as a GitHub repository secret
3. Actions β†’ "Harvest Khazna" β†’ **Run workflow** (first full run)
4. Nightly thereafter: Sunday full, Mon–Sat incremental

Sunday is full because Khazna's OAI reports `deletedRecord: no` β€” incrementals
can never learn that a record was withdrawn.

---

## 4. How to tell it is working

**With a DOI** β€” green "Verified Β· OA.Works Permissions" badge, per-version
rights, the publisher's required deposit statement with a copy button, a source
panel with evidence links, and Khazna status.

**Without a DOI** β€” amber "Unverified Β· journal-level estimate", all version
blocks "Unclear", a prompt to enter a DOI. The backend forcibly downgrades any
`policy_status: "Confirmed"` the model returns, so this cannot be bypassed.

**Khazna unavailable** β€” "Khazna status not checked", explicitly distinguished
from "Not yet in Khazna".

Test DOIs from this build:

```
10.1080/19322909.2023.2221477   T&F      β€” no embargo stated
10.1016/j.jclepro.2023.136775   Elsevier β€” 24 months (not 12; see below)
10.1007/s11192-023-04812-4      Springer β€” preprint immediate, AAM 12 months
```

---

## 5. Things worth knowing

**The Elsevier embargo trap.** OA.Works returns two permissions with identical
`score: 1100` β€” 12 months (UK) and 24 months (everyone else). Ranking by score
alone silently picks 12. `_permission_rank()` in `oaworks.py` breaks the tie by
the *longer* embargo. Do not "optimise" that away.

**Absent is not zero.** T&F records carry no embargo field. The system reports
"Not stated in the permission record" rather than "no embargo", because T&F's
published policy is normally 12 months and a wrong permissive answer costs the
library a takedown notice.

**Publisher matcher.** Now covers imprints whose SCImago string never says the
parent publisher β€” W.B. Saunders, Academic Press, Cell Press, BioMed Central,
Palgrave, Blackwell, Informa, Dove Medical. Q1 APC badge coverage went from
45.8% to 51.1% (+497 journals). `AMBIGUOUS_ALIASES` prevents "Maximum Academic
Press" from being mistaken for Elsevier.

**Repository registry.** The model selects entries by `id` and writes the
`fit_reason`; every factual field is overwritten from `repositories.py`.
Unknown ids are dropped. Entries you have not personally verified are left
blank rather than guessed β€” please fill them in and bump `verified`.

---

## 6. Still open

- `KU_ROR` is empty
- Repository registry has blank fields awaiting your verification
- Wiley, IEEE and ACS not yet validated against OA.Works (`test_publishers.py`)
- Worth telling OA.Works about the UK/non-UK tie: `help@openaccessbutton.org`