library(readr)
library(dplyr)
library(tibble)
library(tidyr)
library(purrr)
library(stringr)
library(digest)
entities <- read_csv(
"data/riverton/riverton-entities.csv",
na = character(),
col_types = cols(
entity_id = col_character(),
canonical_name = col_character(),
entity_type = col_character(),
description = col_character()
)
) |>
select(entity_id, canonical_name, entity_type)
aliases <- read_csv(
"data/riverton/riverton-aliases.csv",
na = character(),
col_types = cols(
entity_id = col_character(),
alias = col_character()
)
) |>
left_join(entities, by = "entity_id")
metadata <- read_csv(
"data/riverton/riverton-reference-metadata.csv",
na = character(),
col_types = cols(
artifact = col_character(),
description = col_character(),
source = col_character(),
license = col_character(),
created_on = col_character(),
fingerprint = col_character()
)
)
entity_hash <- digest(
paste(read_lines("data/riverton/riverton-entities.csv"), collapse = "\n"),
algo = "sha256",
serialize = FALSE
)
alias_hash <- digest(
paste(read_lines("data/riverton/riverton-aliases.csv"), collapse = "\n"),
algo = "sha256",
serialize = FALSE
)Adding facts to a knowledge base
Keep provenance, conflicts, NIL records, and review decisions visible
Grace receives a week of short announcements about Riverton training programs. Some repeat each other. Two give different deadlines for the same program. Another uses the name Riverton, which could mean two different places in the reference table.
Knowledge base population reads documents, links entity mentions, and adds typed facts to a knowledge base with provenance. A knowledge base is not a truth machine. It is a structured record of claims, sources, conflicts, and review decisions.
The Riverton records in this lesson are fictional teaching examples about training programs, places, and organisations.
By the end of this lesson, you will be able to:
- distinguish entity linking from fact insertion;
- declare single-valued and list-valued slots before merging;
- keep document dates, evidence text, and offsets for every fact;
- merge duplicate facts without losing provenance;
- keep conflicting dated values instead of overwriting them; and
- route negated, hedged, ambiguous, NIL, and type-failed candidates to review.
Load the Riverton reference list
The existing knowledge base starts with entity IDs and aliases. The lesson reads the local CSV files with fixed column types, computes each file’s SHA-256 fingerprint, and compares it with the fingerprint recorded when the file was made. A mismatch stops the page before any fact is added.
| Entity ID | Canonical name | Type |
|---|---|---|
| ORG-0001 | Riverton Workforce Lab | organisation |
| ORG-0002 | Riverton Skills Centre | organisation |
| ORG-0003 | Marrow County Transit | organisation |
| LOC-0001 | Riverton | place |
| LOC-0002 | Riverton | place |
| LOC-0003 | Bellhaven | place |
| CRD-0001 | Forklift Operator Licence | credential |
| CRD-0002 | Data Support Certificate | credential |
| Artifact | Rows | Computed SHA-256 | Recorded SHA-256 | Match |
|---|---|---|---|---|
| riverton-entities.csv | 8 | df260574f1f6088b51735a4778646ef22e5338186f74db321a96802d9033fe57 | df260574f1f6088b51735a4778646ef22e5338186f74db321a96802d9033fe57 | TRUE |
| riverton-aliases.csv | 17 | 0a419b6a8a742ffab404b8c58c209eaa90b0247a0ee30dbbfc85a6e914a85c64 | 0a419b6a8a742ffab404b8c58c209eaa90b0247a0ee30dbbfc85a6e914a85c64 | TRUE |
The table prints names and types only. It does not repeat the description field for the forklift credential because this lesson is about provenance, and that description is not evidence for a job-board claim.
Declare slot rules before merging
A slot is a typed place where the knowledge base stores a value. Some slots can hold a list. Others are single-valued for a named time period, so a second dated value becomes a conflict to review.
slot_schema <- tribble(
~slot, ~subject_type, ~object_type, ~cardinality, ~merge_rule,
"offers", "organisation", "credential", "list-valued",
"One fact per subject-object pair; repeated evidence adds provenance.",
"requires", "organisation", "credential", "list-valued",
"One fact per subject-object pair; negated or hedged statements stay out of facts.",
"application_deadline", "organisation", "date literal", "single-valued",
"Keep each dated value, flag conflict, and let review decide."
)| Slot | Subject type | Object type | Cardinality | Merge rule |
|---|---|---|---|---|
| offers | organisation | credential | list-valued | One fact per subject-object pair; repeated evidence adds provenance. |
| requires | organisation | credential | list-valued | One fact per subject-object pair; negated or hedged statements stay out of facts. |
| application_deadline | organisation | date literal | single-valued | Keep each dated value, flag conflict, and let review decide. |
The slot schema tells the code what counts as a duplicate and what counts as a conflict. Without that rule, a pipeline might replace a deadline without reporting the value recorded on 4 September, or turn two offerings into an error.
Prepare dated announcements
The documents below are constructed announcements. They include one duplicate, one single-valued conflict, one negated statement, one hedged statement, an ambiguous Riverton mention, one NIL organisation, one undeclared slot, and one visible type-check failure.
extractor_version <- "riverton-kbp-rules-1.0"
documents <- tribble(
~document_id, ~document_date, ~text,
"A001", as.Date("2026-09-01"), "Riverton Skills Centre offers the Data Support Certificate.",
"A002", as.Date("2026-09-03"), "The Skills Centre offers DATA SUPPORT CERTIFICATE.",
"A003", as.Date("2026-09-04"), "Riverton Skills Centre application deadline is October 15.",
"A004", as.Date("2026-09-06"), "Riverton Skills Centre application deadline is November 1.",
"A005", as.Date("2026-09-07"), "Marrow County Transit does not require the Forklift Operator Licence.",
"A006", as.Date("2026-09-08"), "Riverton will host the Data Support Certificate.",
"A007", as.Date("2026-09-09"), "Riverton Transit offers forklift certification.",
"A008", as.Date("2026-09-10"), "Bellhaven offers the Data Support Certificate.",
"A009", as.Date("2026-09-11"), "Riverton Skills Centre may offer the Forklift Operator Licence.",
"A010", as.Date("2026-09-12"), "Riverton Skills Centre promotes the Data Support Certificate."
)
candidate_plan <- tribble(
~candidate_id, ~document_id, ~slot, ~subject_mention, ~object_mention, ~status, ~expected_action,
"CAND-001", "A001", "offers", "Riverton Skills Centre", "Data Support Certificate", "asserted", "add fact",
"CAND-002", "A002", "offers", "Skills Centre", "DATA SUPPORT CERTIFICATE", "asserted", "merge duplicate",
"CAND-003", "A003", "application_deadline", "Riverton Skills Centre", "October 15", "asserted", "add fact",
"CAND-004", "A004", "application_deadline", "Riverton Skills Centre", "November 1", "asserted", "flag conflict",
"CAND-005", "A005", "requires", "Marrow County Transit", "Forklift Operator Licence", "negated", "reject negated",
"CAND-006", "A006", "offers", "Riverton", "Data Support Certificate", "asserted", "hold ambiguous",
"CAND-007", "A007", "offers", "Riverton Transit", "forklift certification", "asserted", "hold NIL",
"CAND-008", "A008", "offers", "Bellhaven", "Data Support Certificate", "asserted", "reject type",
"CAND-009", "A009", "offers", "Riverton Skills Centre", "Forklift Operator Licence", "hedged", "hold hedged",
"CAND-010", "A010", "promotes", "Riverton Skills Centre", "Data Support Certificate", "asserted", "reject undeclared slot"
)| Document ID | Document date | Evidence text |
|---|---|---|
| A001 | 2026-09-01 | Riverton Skills Centre offers the Data Support Certificate. |
| A002 | 2026-09-03 | The Skills Centre offers DATA SUPPORT CERTIFICATE. |
| A003 | 2026-09-04 | Riverton Skills Centre application deadline is October 15. |
| A004 | 2026-09-06 | Riverton Skills Centre application deadline is November 1. |
| A005 | 2026-09-07 | Marrow County Transit does not require the Forklift Operator Licence. |
| A006 | 2026-09-08 | Riverton will host the Data Support Certificate. |
| A007 | 2026-09-09 | Riverton Transit offers forklift certification. |
| A008 | 2026-09-10 | Bellhaven offers the Data Support Certificate. |
| A009 | 2026-09-11 | Riverton Skills Centre may offer the Forklift Operator Licence. |
| A010 | 2026-09-12 | Riverton Skills Centre promotes the Data Support Certificate. |
| Candidate ID | Document ID | Slot | Subject mention | Object mention | Status | Expected action |
|---|---|---|---|---|---|---|
| CAND-001 | A001 | offers | Riverton Skills Centre | Data Support Certificate | asserted | add fact |
| CAND-002 | A002 | offers | Skills Centre | DATA SUPPORT CERTIFICATE | asserted | merge duplicate |
| CAND-003 | A003 | application_deadline | Riverton Skills Centre | October 15 | asserted | add fact |
| CAND-004 | A004 | application_deadline | Riverton Skills Centre | November 1 | asserted | flag conflict |
| CAND-005 | A005 | requires | Marrow County Transit | Forklift Operator Licence | negated | reject negated |
| CAND-006 | A006 | offers | Riverton | Data Support Certificate | asserted | hold ambiguous |
| CAND-007 | A007 | offers | Riverton Transit | forklift certification | asserted | hold NIL |
| CAND-008 | A008 | offers | Bellhaven | Data Support Certificate | asserted | reject type |
| CAND-009 | A009 | offers | Riverton Skills Centre | Forklift Operator Licence | hedged | hold hedged |
| CAND-010 | A010 | promotes | Riverton Skills Centre | Data Support Certificate | asserted | reject undeclared slot |
These expected actions are not a benchmark. They are a checklist for a teaching pipeline written by the same author as the examples. They are hand-supplied candidates, standing in for an extractor such as lesson 69’s relation extractor. The code below links their mentions, checks types and status, and applies population rules.
Link mentions and keep offsets
The linker below accepts an alias only when it has one candidate. If the mention is absent from the alias table, the code creates a provisional NIL ID for a subject mention; a candidate whose object is not in the table is held for review. If the alias has several candidates, the candidate goes to review instead of choosing a nearby name.
Show the mention-linking code
normalize_text <- function(value) {
str_to_lower(value, locale = "en")
}
alias_lookup <- aliases |>
mutate(normalized_alias = normalize_text(alias)) |>
distinct(normalized_alias, entity_id, canonical_name, entity_type)
link_mention <- function(mention) {
rows <- alias_lookup |>
filter(normalized_alias == normalize_text(mention))
if (nrow(rows) == 0L) {
return(tibble(
linked_id = NA_character_,
linked_type = NA_character_,
link_status = "NIL"
))
}
if (n_distinct(rows$entity_id) > 1L) {
return(tibble(
linked_id = paste(sort(unique(rows$entity_id)), collapse = "; "),
linked_type = paste(sort(unique(rows$entity_type)), collapse = "; "),
link_status = "ambiguous"
))
}
tibble(
linked_id = rows$entity_id[[1]],
linked_type = rows$entity_type[[1]],
link_status = "linked"
)
}
locate_mention <- function(text, mention) {
location <- str_locate(
text,
regex(escape_regex(mention), ignore_case = TRUE)
)
tibble(
start = as.integer(location[1, 1]),
end = as.integer(location[1, 2])
)
}
escape_regex <- function(value) {
str_replace_all(value, "([.\\\\|()\\[\\]{}^$*+?])", "\\\\\\1")
}
nil_mentions <- candidate_plan |>
distinct(subject_mention) |>
mutate(link = map(subject_mention, link_mention)) |>
unnest(link) |>
filter(link_status == "NIL") |>
mutate(provisional_id = sprintf("NIL-%04d", row_number()))
candidates <- candidate_plan |>
left_join(documents, by = "document_id") |>
mutate(
subject_link = map(subject_mention, link_mention),
object_link = map2(
slot,
object_mention,
\(current_slot, current_mention) {
if (current_slot == "application_deadline") {
tibble(
linked_id = current_mention,
linked_type = "date literal",
link_status = "literal value (not linked)"
)
} else {
link_mention(current_mention)
}
}
),
subject_offsets = map2(text, subject_mention, locate_mention),
object_offsets = map2(text, object_mention, locate_mention)
) |>
unnest(subject_link) |>
rename(
subject_id = linked_id,
subject_type = linked_type,
subject_link_status = link_status
) |>
unnest(object_link) |>
rename(
object_id = linked_id,
object_type = linked_type,
object_link_status = link_status
) |>
unnest(subject_offsets) |>
rename(subject_start = start, subject_end = end) |>
unnest(object_offsets) |>
rename(object_start = start, object_end = end) |>
left_join(
nil_mentions |>
select(subject_mention, provisional_id),
by = "subject_mention"
) |>
mutate(
subject_id = if_else(subject_link_status == "NIL", provisional_id, subject_id),
subject_type = if_else(subject_link_status == "NIL", "organisation", subject_type),
object_value = case_when(
slot == "application_deadline" ~ object_mention,
TRUE ~ object_id
)
)
link_table <- candidates |>
select(
candidate_id,
subject_mention,
subject_id,
subject_type,
subject_link_status,
object_mention,
object_id,
object_type,
object_link_status
)| Candidate ID | Subject mention | Subject ID | Subject type | Subject link status | Object mention | Object ID | Object type | Object link status |
|---|---|---|---|---|---|---|---|---|
| CAND-001 | Riverton Skills Centre | ORG-0002 | organisation | linked | Data Support Certificate | CRD-0002 | credential | linked |
| CAND-002 | Skills Centre | ORG-0002 | organisation | linked | DATA SUPPORT CERTIFICATE | CRD-0002 | credential | linked |
| CAND-003 | Riverton Skills Centre | ORG-0002 | organisation | linked | October 15 | October 15 | date literal | literal value (not linked) |
| CAND-004 | Riverton Skills Centre | ORG-0002 | organisation | linked | November 1 | November 1 | date literal | literal value (not linked) |
| CAND-005 | Marrow County Transit | ORG-0003 | organisation | linked | Forklift Operator Licence | CRD-0001 | credential | linked |
| CAND-006 | Riverton | LOC-0001; LOC-0002 | place | ambiguous | Data Support Certificate | CRD-0002 | credential | linked |
| CAND-007 | Riverton Transit | NIL-0001 | organisation | NIL | forklift certification | CRD-0001 | credential | linked |
| CAND-008 | Bellhaven | LOC-0003 | place | linked | Data Support Certificate | CRD-0002 | credential | linked |
| CAND-009 | Riverton Skills Centre | ORG-0002 | organisation | linked | Forklift Operator Licence | CRD-0001 | credential | linked |
| CAND-010 | Riverton Skills Centre | ORG-0002 | organisation | linked | Data Support Certificate | CRD-0002 | credential | linked |
The Riverton row keeps both candidate IDs in the review record. It is not auto-linked to either place. The Riverton Transit row gets a provisional NIL ID and is not merged into Marrow County Transit.
Apply slot, status, and type decisions
The action table is the evaluation for this lesson. It shows whether the pipeline made the expected decision for each candidate. It is not precision and recall.
Show the slot and type checks
schema_checks <- candidates |>
left_join(slot_schema, by = "slot") |>
mutate(
declared_slot = !is.na(subject_type.y),
subject_type_ok = declared_slot & subject_type.x == subject_type.y,
object_type_ok = case_when(
!declared_slot ~ FALSE,
object_type.y == "date literal" ~ str_detect(object_mention, "^[A-Z][a-z]+ [0-9]+$"),
TRUE ~ object_type.x == object_type.y
),
type_check = subject_type_ok & object_type_ok,
fact_key = paste(slot, subject_id, object_value, sep = "|")
)
first_seen <- schema_checks |>
filter(status == "asserted", subject_link_status == "linked", type_check) |>
arrange(document_date, candidate_id) |>
distinct(fact_key, .keep_all = TRUE) |>
transmute(first_candidate_id = candidate_id, fact_key)
single_value_seen <- schema_checks |>
filter(status == "asserted", subject_link_status == "linked", type_check) |>
filter(cardinality == "single-valued") |>
count(slot, subject_id, name = "single_value_count")
first_single_seen <- schema_checks |>
filter(status == "asserted", subject_link_status == "linked", type_check) |>
filter(cardinality == "single-valued") |>
arrange(document_date, candidate_id) |>
group_by(slot, subject_id) |>
slice_head(n = 1) |>
ungroup() |>
transmute(slot, subject_id, first_single_candidate_id = candidate_id)
candidate_actions <- schema_checks |>
left_join(first_seen, by = "fact_key") |>
left_join(single_value_seen, by = c("slot", "subject_id")) |>
left_join(first_single_seen, by = c("slot", "subject_id")) |>
mutate(
single_value_count = coalesce(single_value_count, 0L),
actual_action = case_when(
status == "negated" ~ "reject negated",
status == "hedged" ~ "hold hedged",
subject_link_status == "ambiguous" ~ "hold ambiguous",
subject_link_status == "NIL" ~ "hold NIL",
!declared_slot ~ "reject undeclared slot",
object_link_status == "NIL" | is.na(type_check) ~ "hold NIL",
!type_check ~ "reject type",
candidate_id != first_candidate_id ~ "merge duplicate",
cardinality == "single-valued" &
single_value_count > 1L &
candidate_id != first_single_candidate_id ~ "flag conflict",
TRUE ~ "add fact"
),
action_matches = actual_action == expected_action,
action_reason = case_when(
status == "negated" ~ "negated statements never become facts",
status == "hedged" ~ "hedged statements wait for review",
subject_link_status == "ambiguous" ~ "alias maps to more than one ID",
subject_link_status == "NIL" ~ "new name receives a provisional ID for review",
!declared_slot ~ "slot is not declared in the schema",
object_link_status == "NIL" | is.na(type_check) ~ "object mention is not linked",
!type_check ~ "slot type check failed",
candidate_id != first_candidate_id ~ "same fact already exists; keep provenance",
cardinality == "single-valued" &
single_value_count > 1L &
candidate_id != first_single_candidate_id ~ "single-valued slot has dated conflict",
TRUE ~ "asserted, linked, and type-compatible"
)
)| Candidate ID | Expected action | Pipeline action | Match | Reason |
|---|---|---|---|---|
| CAND-001 | add fact | add fact | TRUE | asserted, linked, and type-compatible |
| CAND-002 | merge duplicate | merge duplicate | TRUE | same fact already exists; keep provenance |
| CAND-003 | add fact | add fact | TRUE | asserted, linked, and type-compatible |
| CAND-004 | flag conflict | flag conflict | TRUE | single-valued slot has dated conflict |
| CAND-005 | reject negated | reject negated | TRUE | negated statements never become facts |
| CAND-006 | hold ambiguous | hold ambiguous | TRUE | alias maps to more than one ID |
| CAND-007 | hold NIL | hold NIL | TRUE | new name receives a provisional ID for review |
| CAND-008 | reject type | reject type | TRUE | slot type check failed |
| CAND-009 | hold hedged | hold hedged | TRUE | hedged statements wait for review |
| CAND-010 | reject undeclared slot | reject undeclared slot | TRUE | slot is not declared in the schema |
The type failure is visible: Bellhaven is a place ID, not an organisation. The negated requirement row is rejected rather than stored as a negative fact or used to delete anything.
Build facts and provenance
The final fact table keeps one fact for the duplicate offer and two dated deadline values for the conflict. Provenance stays in a separate table so one fact can point to several source records.
accepted_candidates <- candidate_actions |>
filter(actual_action %in% c("add fact", "merge duplicate", "flag conflict"))
fact_keys <- accepted_candidates |>
distinct(slot, subject_id, object_value, fact_key) |>
arrange(slot, subject_id, object_value) |>
mutate(fact_id = sprintf("FACT-%03d", row_number()))
populated_facts <- accepted_candidates |>
inner_join(fact_keys, by = c("slot", "subject_id", "object_value", "fact_key")) |>
group_by(fact_id, slot, subject_id, object_value) |>
summarise(
provenance_records = n(),
conflict_flag = first(cardinality) == "single-valued" &
n_distinct(candidate_actions$object_value[
candidate_actions$slot == first(slot) &
candidate_actions$subject_id == first(subject_id) &
candidate_actions$actual_action %in% c("add fact", "flag conflict")
]) > 1L,
.groups = "drop"
) |>
arrange(fact_id)
fact_provenance <- accepted_candidates |>
inner_join(fact_keys, by = c("slot", "subject_id", "object_value", "fact_key")) |>
transmute(
fact_id,
candidate_id,
document_id,
document_date,
evidence_text = text,
subject_start,
subject_end,
object_start,
object_end,
candidate_source = "hand-supplied candidate",
pipeline_rules_version = extractor_version
) |>
arrange(fact_id, document_id)
review_queue <- candidate_actions |>
filter(!actual_action %in% c("add fact", "merge duplicate", "flag conflict")) |>
transmute(
candidate_id,
document_id,
subject_mention,
object_mention,
provisional_or_candidate_id = subject_id,
review_reason = action_reason
)| Fact ID | Slot | Subject ID | Object value | Provenance records | Conflict flagged |
|---|---|---|---|---|---|
| FACT-001 | application_deadline | ORG-0002 | November 1 | 1 | TRUE |
| FACT-002 | application_deadline | ORG-0002 | October 15 | 1 | TRUE |
| FACT-003 | offers | ORG-0002 | CRD-0002 | 2 | FALSE |
| Fact ID | Candidate ID | Document ID | Document date | Evidence text | Subject start | Subject end | Object start | Object end | Candidate source | Pipeline rules version |
|---|---|---|---|---|---|---|---|---|---|---|
| FACT-001 | CAND-004 | A004 | 2026-09-06 | Riverton Skills Centre application deadline is November 1. | 1 | 22 | 48 | 57 | hand-supplied candidate | riverton-kbp-rules-1.0 |
| FACT-002 | CAND-003 | A003 | 2026-09-04 | Riverton Skills Centre application deadline is October 15. | 1 | 22 | 48 | 57 | hand-supplied candidate | riverton-kbp-rules-1.0 |
| FACT-003 | CAND-001 | A001 | 2026-09-01 | Riverton Skills Centre offers the Data Support Certificate. | 1 | 22 | 35 | 58 | hand-supplied candidate | riverton-kbp-rules-1.0 |
| FACT-003 | CAND-002 | A002 | 2026-09-03 | The Skills Centre offers DATA SUPPORT CERTIFICATE. | 5 | 17 | 26 | 49 | hand-supplied candidate | riverton-kbp-rules-1.0 |
| Candidate ID | Document ID | Subject mention | Object mention | Provisional or candidate ID | Review reason |
|---|---|---|---|---|---|
| CAND-005 | A005 | Marrow County Transit | Forklift Operator Licence | ORG-0003 | negated statements never become facts |
| CAND-006 | A006 | Riverton | Data Support Certificate | LOC-0001; LOC-0002 | alias maps to more than one ID |
| CAND-007 | A007 | Riverton Transit | forklift certification | NIL-0001 | new name receives a provisional ID for review |
| CAND-008 | A008 | Bellhaven | Data Support Certificate | LOC-0003 | slot type check failed |
| CAND-009 | A009 | Riverton Skills Centre | Forklift Operator Licence | ORG-0002 | hedged statements wait for review |
| CAND-010 | A010 | Riverton Skills Centre | Data Support Certificate | ORG-0002 | slot is not declared in the schema |
One offer fact has two provenance records. The two deadline facts both remain, and both are flagged because a later document might be an update, an error, or a different session. The candidate set adds 3 populated facts after the review rules run. The table records the conflict; it does not resolve it. The FACT- values here are display IDs minted during this render; a real knowledge base keeps issued fact IDs stable once it publishes them.
Prepare the graph facts used in the visualization lesson
Lesson 81 redraws a small graph from the same IDs. The table below is a compact edge view of the populated facts. The two Riverton place IDs stay separate because entity IDs, not labels, are the keys.
graph_facts <- populated_facts |>
left_join(
fact_provenance |>
group_by(fact_id) |>
summarise(document_ids = paste(document_id, collapse = "; "), .groups = "drop"),
by = "fact_id"
) |>
transmute(
subject_id,
relation = slot,
object_value,
document_ids,
source = "populated fact"
)| Subject ID | Relation | Object value | Document IDs | Source |
|---|---|---|---|---|
| ORG-0002 | application_deadline | November 1 | A004 | populated fact |
| ORG-0002 | application_deadline | October 15 | A003 | populated fact |
| ORG-0002 | offers | CRD-0002 | A001; A002 | populated fact |
These graph edges are still KB records, not proof about the real world. The source column says they came from the constructed population step, and the document IDs point back to the provenance table above. The two Riverton place IDs remain in the entity table, but their shared label is a naming note for the visualization lesson rather than a factual relation.
What the knowledge base does not know
A missing edge is not evidence that a relation is false. This is the open-world caveat: the KB records what it has seen and accepted under its current policy. It may be incomplete, stale, or contradicted by a later document. Provenance helps a reviewer inspect a claim; it does not certify the claim as true.
What to remember
- Knowledge base population combines linking and slot filling.
- Slot cardinality must be declared before merging facts.
- Duplicate facts can share one fact ID with several provenance records.
- Single-valued conflicts keep both dated values until review.
- Negated and hedged statements do not become facts.
Rivertonstays ambiguous, and a NIL organisation receives a provisional ID.
Grace ends with fewer automatic facts than candidate statements. That is the point: a useful KBP step records what it added, what it held, and why.