Skip to content

A unit is read, not assumed - #600

Merged
WaylandYang merged 4 commits into
devfrom
fix/a-unit-is-read-not-assumed
Sep 10, 2026
Merged

A unit is read, not assumed#600
WaylandYang merged 4 commits into
devfrom
fix/a-unit-is-read-not-assumed

Conversation

@WaylandYang

@WaylandYang WaylandYang commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Follow-up to #598, from four waves of end-to-end tests on an isolated base (each document pressing one rule) and two rehearsals of a Chinese enterprise corpus. Findings are recorded in 0037 under "What the test waves found".

Four defects, four fixes

A wrong currency is worse than none. Gamma Capital invested €30 million in Delta Analytics came out as amount = 30000000 $, and 腾讯以15亿元人民币投资了智谱AI as 1500000000 $: the model normalises the figure to a bare number, or writes the currency as a sibling key ("currency": "CNY"), and the write path fell back to the attribute's declared unit. Now the prompt asks for the figure as written, currency and all; the quantity scanner reads currency symbols, ISO codes, currency words and CJK magnitudes (2亿美元, 15亿元人民币, EUR 30 million, 30 million euros); a sibling currency / 币种 key becomes the unit of the numeric qualifier instead of a qualifier_unknown drop; and the declared default unit is used only when the text carries no unit token at all.

A listed attribute keeps its magnitude too. Rule 10 told the model that a number is "a plain number without unit symbols", and rule 8a told it to keep a literal "as written, units and all". For a listed attribute the model obeyed rule 10 and wrote 86 for 86亿元人民币 — the magnitude went with the unit. Rule 10 now says the same as 8a: the figure as the text writes it, the server converts. On the Chinese rehearsal 营业收入 went from 86 ¥ to 8600000000 ¥, 净利润 from 9.2 to 920000000, 注册资本 to 500000000.

A qualifier the base already defines is declared from the corpus. With nothing declared on invested_in, the model still wrote amount, stake and round — eight values into the drop report while the three attribute definitions sat in the base. When an unknown key matches an attribute of this base, the relation now declares it and the value is written, under the same auto_extend_ontology switch as the rest of the growth loop. The declaration is additive (add_relation_qualifier, ON CONFLICT DO NOTHING): documents extract in parallel and the replace-all write lost one document's declaration to another's.

A null qualifier is "not stated", not a bad value. The model writes "stake": null for a sentence with no stake; that used to be a qualifier_datatype drop, four per corpus. And a magnitude-multiplied value is rounded to a whole number: 9.2亿 is 920000000, not 919999999.9999999.

What the waves showed after the fixes

Isolated base (utopia_edges, migrated by the server), model on DeepSeek-V3:

repeatability ×3       both amounts on both edges every run; stake:"minority" refused, recorded
rules corpus, undecl.  amount,round,stake declared from the corpus; €30M kept as €; conflict recorded
Chinese, undeclared    红杉→月之暗面 2e8 $ + 8 %; 美团→理想 3e8 $; 腾讯→智谱 1.5e9 ¥; no drops
Chinese enterprise     12 documents, 21 entities, 16–18 edges carrying 25–29 attributes:
                       投资/收购/合资/代工合同/诉讼/减持/合作 each with 金额, 持股, 轮次 or 期限;
                       任职于 with 职务; ¥ and $ right; no drops; no quantity entities

Two things the waves found that this PR does not fix, both recorded in 0037: two documents describing the same edge extracted in parallel can both insert (the dedup is a read-then-write with no unique index behind it) — the "two rows plus a conflict" cut has to close that first; and the model dates "earlier this year" to a concrete day, minting a moment the text never gave.

A word on method: half a day of contradictory results turned out to be another session's server attached to the same database and job queue, processing some documents with an older binary. The waves moved to their own base after that.

Tests

  • parse_quantity / parse_leading_quantity: currencies as symbol, code and word; CJK magnitudes; rounding; strictness unchanged (3M, 1,250 people, 2025 Atlantic hurricane season).
  • Store, against a database: add_relation_qualifier is idempotent, additive, and refuses a non-attribute.
  • fmt / clippy / 232 + 32 unit tests / store test green.

🤖 Generated with Claude Code

WaylandYang and others added 4 commits September 11, 2026 00:36
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: WaylandYang <wayland0916@gmail.com>
@WaylandYang
WaylandYang merged commit 1333049 into dev Sep 10, 2026
4 checks passed
@WaylandYang
WaylandYang deleted the fix/a-unit-is-read-not-assumed branch September 10, 2026 23:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant