Skip to content
Open
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
23 changes: 21 additions & 2 deletions crates/utopia-extract/src/open.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,10 @@ the passage does not. Each is null when the passage gives none.\n\
slot of an \"s\" entry, the last slot of an \"n\" entry.\n\
7. \"n\" lists other names, one entry each: [name as listed, other name, quote] — a short form, \
a former name, a spelling in another script that this passage uses for a thing in \"e\" or a \
thing already recorded. Only names actually written in the passage; never a pronoun or a \
description.\n\
thing already recorded. Only a proper name or a fixed term may become another name; a role or \
generic phrase whose referent the passage decides is never another name, even when it refers to \
a thing in \"e\" or a thing already recorded; it stays the description or the qualifier words. \
Only names actually written in the passage; never a pronoun or a description.\n\
8. State nothing the passage does not state, and state each thing once: with a value or with \
an object, not both. The Document line, the opening of the document and the list of things \
already recorded only say where the passage comes from; write nothing about them. If the \
Expand Down Expand Up @@ -732,6 +734,23 @@ mod tests {
assert!(!x.truncated);
}

/// `named = 0` only matters if that decision follows the thing into `n`: an
/// anaphoric role can pass both server checks because its words and referent
/// really are in the passage.
#[test]
fn a_passage_resolved_phrase_is_not_another_name() {
let msgs = build_open_messages("filing.txt", &[], None, "text");
let system = &msgs[0].content;
assert!(system.contains("Only a proper name or a fixed term may become another name"));
assert!(system.contains(
"a role or generic phrase whose referent the passage decides is never another name"
));
assert!(
system.contains("even when it refers to a thing in \"e\" or a thing already recorded")
);
assert!(system.contains("it stays the description or the qualifier words"));
}

fn known(handle: &str, name: &str, type_key: &str) -> KnownEntity {
KnownEntity {
handle: handle.into(),
Expand Down
16 changes: 16 additions & 0 deletions crates/utopia-store/src/names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ pub struct NameSource<'a> {
///
/// 同一个实体同一个名字只有一行(`insert_value_fact` 按主语、谓词、值去重),
/// 再被提到只是多一条证据、证据日期往早挪。
///
/// 被描述的东西一个别名也不收(#770):`description` 是它的身份,名字事实是召回
/// 的桥;模型违反契约把描述写进 `n` 时,这里是最后一道结构闸门。
pub async fn record(
pool: &PgPool,
kb_id: Uuid,
Expand All @@ -87,6 +90,19 @@ pub async fn record(
if name.is_empty() {
return Ok(None);
}
let described: bool = sqlx::query_scalar(
"SELECT EXISTS (
SELECT 1 FROM entities
WHERE id = $1 AND kb_id = $2 AND description IS NOT NULL
)",
)
.bind(entity_id)
.bind(kb_id)
.fetch_one(pool)
.await?;
if described {
return Ok(None);
}
let attr = ensure_known_as(pool, kb_id).await?;
let (fact_id, _) = insert_value_fact(
pool,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ async fn a_described_thing_has_a_description_and_no_name() -> anyhow::Result<()>
assert!(type_id.is_none(), "文档的类别词不是本体的类");
assert_eq!(specific.as_deref(), Some("subsidiary"));

// 一条迟到的别名也不能把描述变成召回桥:record 得拒绝它,而不是照单全收
assert_eq!(
names::record(&pool, f.kb, id, "the Shanghai buyer", None, None).await?,
None
);

// 没有一条以它为主语的事实——尤其没有 known_as
let facts: i64 = sqlx::query_scalar("SELECT count(*) FROM facts WHERE subject_id = $1")
.bind(id)
Expand Down
5 changes: 4 additions & 1 deletion docs/design/extraction.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ are extraction's rules [0039].
description, the document's kind word, and whether it is named or described. `s`: statements, each
opening with its own verbatim quote and then naming its subject and object in words, the relation
phrase as written, an object name or a literal value, qualifiers keyed by the document's role
words, and `when` / `ended` time words. `n`: other names the document gives a thing. Statements name their sides in words
words, and `when` / `ended` time words. `n`: other names the document gives a thing, and only a
proper name or fixed term may become one. A role or generic phrase whose referent the passage
decides stays description or qualifier words even when it points at a listed or already recorded
thing [#770]. Statements name their sides in words
and carry their own quote because a numbered contract mixed the ids up on dense passages (misworded
10 to 14% with ids, 2 to 7% with names) [#731]. Parsing is per item: a malformed item is counted and
a truncated reply is repaired to its last complete item.
Expand Down
Loading