Heratio Help Center article. Category: AI & Automation.
Authority Resolution - Park Queue
The park queue is the engine's "I cannot decide yet" outlet. Mentions that are parked stay alive, get re-scanned for new candidates, and re-surface when the upstream authority store changes. This article covers when to park, how to find parked items, what "new candidate available" means, and the re-review flow.
Lifecycle
mention pending
|
+--- archivist clicks Park ---> ahg_mention_park row, state = parked
|
(cron: auth-res:scan-parked)
|
v
candidate set changed?
/ \
yes no
/ \
new_candidate_available = 1 (no change, just update
| new_candidate_check_at)
v
archivist sees flag, clicks Unpark
|
v
ParkQueueService::unparkAndRereview()
|
v
mention pending (with fresh candidates)
park is the only non-terminal decision in the five-outcome tree. All other outcomes (link, link_different, create_new, reject) are terminal.
When to park
- The mention is real but the right authority record does not exist yet, and an import is pending.
- The mention is real but the document context is ambiguous and needs off-line research.
- The mention is real but the candidate scoring is unsafe (close ties at the top, or the wrong card is highest).
- The mention may be a NER false positive but you are not sure enough to reject. Rejection writes NER training data, so you want it to be confident; if you cannot be confident, park.
The park screen
/admin/authority-resolution/park
Top-line tiles
- Total parked - count of active
ahg_mention_parkrows. - New candidate available - count of rows where the background scan saw the candidate set change.
- Archivists involved - count of distinct
parked_by_user_id.
Filters
- Parked by - dropdown of users who have parked anything. Defaults to "Mine" (the logged-in user).
- Entity type - PERSON / ORG / GPE / PLACE / LOC.
- New candidate only - boolean, shows only rows the scan job has flagged.
- Parked at - date range.
- Reason - text search (
LIKE) inside the park reason. - Sort -
parked_at_desc(default),parked_at_asc,entity_type,new_candidateflag.
Per-row actions
Each row shows the mention value, entity type, parked-by user, parked-at timestamp, the reason, and an NEW CANDIDATE badge when the background scan has flagged it.
| Action | What it does |
|---|---|
| Unpark + review | Calls ParkQueueService::unparkAndRereview(), regenerates candidates, re-scores evidence, redirects to the review screen with state = pending. |
| Show context | Expands the surrounding text and the original ahg_ner_entity row inline. |
| Discard | Permanent reject. Writes decision_type = reject and removes the park row in one transaction. |
What "new candidate available" means
The background scan auth-res:scan-parked walks every parked row and computes a fingerprint of the current candidate set: a sorted CSV of source|authority_id|fuseki_uri|display_name tuples. If the fingerprint has changed since the last scan, the job sets new_candidate_available = 1 and records new_candidate_check_at = NOW(). If it has not changed, the flag stays at 0 and only the check timestamp is updated.
Triggers that typically change the fingerprint:
- A new external adapter went live (VIAF, Wikidata, GeoNames, ...).
- A MARC or EAD import added authority records to the local store.
- A previously stub Fuseki adapter started returning rows.
The scan is cheap (one candidate-generator pass per parked mention) and idempotent. Suggested cron: hourly.
0 * * * * www-data /usr/bin/php /usr/share/nginx/heratio/artisan auth-res:scan-parked >/dev/null 2>&1
Re-review flow
POST /admin/authority-resolution/park/{mention}/unpark runs ParkQueueService::unparkAndRereview($mentionId, $userId):
DELETE FROM ahg_mention_park WHERE mention_id = ?.UPDATE ahg_mention SET state = 'pending'for that mention.CandidateGeneratorService::generate($mentionId)re-queries every adapter.EvidenceScorer::scoreAllForMention($mentionId)re-scores the new set.- Redirects to
/admin/authority-resolution/review/{id}.
The candidate list may be empty after re-review. The review screen handles this by surfacing the "Create new" path as the obvious next step.
Bulk re-review
When you know a wave of parked mentions can now be decided (an import landed, a new adapter shipped), use the artisan command:
$ sudo -u www-data php artisan auth-res:reprocess-parked --since=2026-05-01
Re-reviewing 1 parked mention(s) (parked >= 2026-05-01)...
mention 24: unparked, 2 candidates, 2 scored.
Done. 1 re-reviewed, 0 failed, 1 now have at least one candidate.
Options:
--since=YYYY-MM-DD- re-review every mention parked on or after the given date.--limit=0- cap (0 = no cap).--user-id=0- archivist user id to attribute the unpark. 0 means "system".
The command does the same thing as the per-row "Unpark + review" button, but in bulk. It does not make decisions for you - it just moves the mentions back to pending so they re-surface on the review queue.
Data model
ahg_mention_park:
| Column | Purpose |
|---|---|
mention_id |
UNIQUE - one active park row per mention |
parked_by_user_id |
For the "My parked" filter and per-archivist counts |
parked_at |
Timestamp; sort key and --since filter |
reason |
Free text, LIKE-searchable |
new_candidate_available |
0 / 1, set by scan-parked |
new_candidate_check_at |
Timestamp of last scan |
Dashboard widget
ParkQueueService::countsByArchivist() returns [archivist_user_id => count]. The partial auth-res::_park-dashboard-widget renders this as a sortable list, with "Mine" wired to the logged-in user. The widget is reusable from any admin dashboard.
A JSON endpoint at GET /admin/authority-resolution/park/dashboard.json exposes the same counts without rendering the screen:
{
"total_parked": 1,
"total_new_candidate": 0,
"by_archivist": [{"user_id": 900148, "name": null, "count": 1}]
}
Edge cases
- Unpark with no candidates -
unparkAndRereview()always returns. The candidate list may be empty; the review screen handles this with a "create new" prompt. - Re-parking - parking an already-parked mention is a no-op. The UNIQUE constraint on
mention_idprevents duplicates; the existing row'sreasonis updated. - Park then reject - rejecting from the review screen deletes the park row in the same transaction; you do not need to "unpark to reject".
- Park then create-new - same: terminal decisions sweep the park row away.
Related
- "AHG Authority Resolution - User Guide" - the mental model and the five outcomes.
- "Authority Resolution - Review Screen Reference" - the screen the unpark flow lands on.
- "Authority Resolution - CLI Commands" -
auth-res:scan-parkedandauth-res:reprocess-parkedin detail.