test(fixtures): replace sector-specific example material with generic, fictitious examples — green
Every fixture, test document, tool example and document now uses an invented kitchen-and-baking handbook series, written in this repository. The package's behaviour is unchanged; src/ changes are comments and help text only. - Generated fixtures are regenerated from their generators. Their structural counts are identical before and after: elements, images, rows, cells, headings, bookmarks and the witness inventory's per-document totals. The image-inbox and accounting documents are renamed kapittel-84-*. - tools/okf_accounting_gate.py: the two options that named one real corpus each are replaced by a generic, repeatable --corpus PATH with no default. Row 5 compares the PDF pair alone. Gate verdict unchanged: RED rows 2, 3, 6. - tools/okf_witness.py: the STS JSON reader for one publisher's delivery is removed, along with its three twins and five tests. The mutation harness loses W09. - docs/: 13 dated reports that documented runs on a retired reference corpus are removed, and 40 are neutralized. Dead links are removed, and no new dangling path is introduced. - The synthetic MCP-gate corpus and the residual probe words are neutral. Valgt: keep the `okf quality --fasit` bar value (the measured fraction, one corpus) and rewrite only its provenance, because the verdict stays unchanged and the number names nothing. Term check with the local list: 0 of 411 tracked files, 0 file names, 0 of 27 binary fixtures. Suite after git add: 2457 passed, 1 skipped. The base tree had 2460 passed and 2 skipped; five tests went with the JSON reader and four were added by the term check. ruff, ruff format and mypy --strict src/ are clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
1e7345a401
commit
9d1f4b14ed
174 changed files with 1889 additions and 6512 deletions
|
|
@ -33,20 +33,20 @@ def derive(text: str, source_file: str = "note.md") -> DocumentStructure:
|
|||
|
||||
|
||||
def test_title_from_frontmatter_is_declared() -> None:
|
||||
doc = derive("---\ntitle: Vegbygging\n---\n\nbody\n", "n500-vegbygging.md")
|
||||
assert doc.title == "Vegbygging"
|
||||
doc = derive("---\ntitle: Surdeigsbaking\n---\n\nbody\n", "q500-surdeigsbaking.md")
|
||||
assert doc.title == "Surdeigsbaking"
|
||||
assert "title" not in doc.derived
|
||||
|
||||
|
||||
def test_title_from_leading_heading_is_derived() -> None:
|
||||
doc = derive("# Vegbygging\n\nbody\n", "n500-vegbygging.md")
|
||||
assert doc.title == "Vegbygging"
|
||||
doc = derive("# Surdeigsbaking\n\nbody\n", "q500-surdeigsbaking.md")
|
||||
assert doc.title == "Surdeigsbaking"
|
||||
assert "title" in doc.derived
|
||||
|
||||
|
||||
def test_title_falls_back_to_the_filename_stem_and_is_derived() -> None:
|
||||
doc = derive("body with no heading\n", "n500-vegbygging.md")
|
||||
assert doc.title == "n500-vegbygging"
|
||||
doc = derive("body with no heading\n", "q500-surdeigsbaking.md")
|
||||
assert doc.title == "q500-surdeigsbaking"
|
||||
assert "title" in doc.derived
|
||||
|
||||
|
||||
|
|
@ -78,11 +78,11 @@ def test_title_is_nfc_normalised() -> None:
|
|||
@pytest.mark.parametrize(
|
||||
("source_file", "expected"),
|
||||
[
|
||||
("n500-vegbygging.md", "N500"),
|
||||
("N500 Vegbygging.md", "N500"),
|
||||
("v720-something.md", "V720"),
|
||||
("q500-surdeigsbaking.md", "Q500"),
|
||||
("Q500 Surdeigsbaking.md", "Q500"),
|
||||
("w720-something.md", "W720"),
|
||||
("4.2.1-details.md", "4.2.1"),
|
||||
("R610.4 note.md", "R610.4"),
|
||||
("P610.4 note.md", "P610.4"),
|
||||
],
|
||||
)
|
||||
def test_number_is_read_off_the_filename_and_marked_derived(
|
||||
|
|
@ -94,14 +94,14 @@ def test_number_is_read_off_the_filename_and_marked_derived(
|
|||
|
||||
|
||||
def test_a_declared_number_wins_and_is_not_marked_derived() -> None:
|
||||
doc = derive("---\nnumber: N200\n---\n\nbody\n", "n500-vegbygging.md")
|
||||
assert doc.number == "N200"
|
||||
doc = derive("---\nnumber: Q200\n---\n\nbody\n", "q500-surdeigsbaking.md")
|
||||
assert doc.number == "Q200"
|
||||
assert "number" not in doc.derived
|
||||
|
||||
|
||||
def test_number_falls_back_to_the_title_when_the_filename_has_none() -> None:
|
||||
doc = derive("# N500 Vegbygging\n", "dropped-file.md")
|
||||
assert doc.number == "N500"
|
||||
doc = derive("# Q500 Surdeigsbaking\n", "dropped-file.md")
|
||||
assert doc.number == "Q500"
|
||||
assert "number" in doc.derived
|
||||
|
||||
|
||||
|
|
@ -126,8 +126,8 @@ def test_no_number_anywhere_is_none_not_an_invention() -> None:
|
|||
("number_source", "expected_parent"),
|
||||
[
|
||||
("4.2.1-x.md", "4.2"),
|
||||
("R610.4 x.md", "R610"),
|
||||
("n500-x.md", None),
|
||||
("P610.4 x.md", "P610"),
|
||||
("q500-x.md", None),
|
||||
# `4.2` would drop to `4`, and a BARE integer is not a document number
|
||||
# under this module's own grammar. A pointer nothing could ever satisfy
|
||||
# is not a pointer: it would sit in the unresolved list forever, and an
|
||||
|
|
@ -157,38 +157,38 @@ def test_parent_is_structural_and_carries_the_numbers_confidence() -> None:
|
|||
|
||||
|
||||
def test_number_mentions_in_the_body_are_references() -> None:
|
||||
doc = derive("See N200 and jf. N300 kap. 4 for details.\n", "n500-x.md")
|
||||
assert doc.references == ("N200", "N300")
|
||||
doc = derive("See Q200 and jf. Q300 kap. 4 for details.\n", "q500-x.md")
|
||||
assert doc.references == ("Q200", "Q300")
|
||||
assert "references" in doc.derived
|
||||
|
||||
|
||||
def test_a_document_never_references_itself() -> None:
|
||||
doc = derive("N500 says that N500 applies, see N200.\n", "n500-x.md")
|
||||
assert doc.references == ("N200",)
|
||||
doc = derive("Q500 says that Q500 applies, see Q200.\n", "q500-x.md")
|
||||
assert doc.references == ("Q200",)
|
||||
|
||||
|
||||
def test_references_are_deduplicated_and_ordered_by_first_appearance() -> None:
|
||||
# Each mention carries a cue, because a number without one is no longer a
|
||||
# reference at all. What this test pins is the ordering and the dedup.
|
||||
doc = derive("se N300 then se N200 then se N300 again.\n", "n500-x.md")
|
||||
assert doc.references == ("N300", "N200")
|
||||
doc = derive("se Q300 then se Q200 then se Q300 again.\n", "q500-x.md")
|
||||
assert doc.references == ("Q300", "Q200")
|
||||
|
||||
|
||||
def test_markdown_link_targets_are_references_too() -> None:
|
||||
doc = derive("See [the other](other-doc.md) and [again](other-doc.md).\n", "n500-x.md")
|
||||
doc = derive("See [the other](other-doc.md) and [again](other-doc.md).\n", "q500-x.md")
|
||||
assert "other-doc.md" in doc.references
|
||||
|
||||
|
||||
def test_external_links_are_not_references() -> None:
|
||||
# A cross-reference is inside the bundle. An http link is somebody else's
|
||||
# document and resolving it is not this library's job.
|
||||
doc = derive("See [upstream](https://example.test/a.md).\n", "n500-x.md")
|
||||
doc = derive("See [upstream](https://example.test/a.md).\n", "q500-x.md")
|
||||
assert doc.references == ()
|
||||
|
||||
|
||||
def test_declared_references_are_not_marked_derived() -> None:
|
||||
doc = derive("---\nreferences: [N200, N300]\n---\n\nbody mentioning N400\n", "n500-x.md")
|
||||
assert doc.references == ("N200", "N300")
|
||||
doc = derive("---\nreferences: [Q200, Q300]\n---\n\nbody mentioning Q400\n", "q500-x.md")
|
||||
assert doc.references == ("Q200", "Q300")
|
||||
assert "references" not in doc.derived
|
||||
|
||||
|
||||
|
|
@ -196,8 +196,8 @@ def test_declared_references_are_not_marked_derived() -> None:
|
|||
|
||||
|
||||
def test_supersedes_is_declared_only_never_inferred_per_document() -> None:
|
||||
doc = derive("---\nsupersedes: [n500-2018]\n---\n\nbody\n", "n500-2021.md")
|
||||
assert doc.supersedes == ("n500-2018",)
|
||||
doc = derive("---\nsupersedes: [q500-2018]\n---\n\nbody\n", "q500-2021.md")
|
||||
assert doc.supersedes == ("q500-2018",)
|
||||
assert "supersedes" not in doc.derived
|
||||
|
||||
|
||||
|
|
@ -205,13 +205,13 @@ def test_no_declared_supersedes_means_none_at_document_level() -> None:
|
|||
# Whether one document supersedes another is a fact about a PAIR, so a
|
||||
# single document cannot answer it. The bundle-level resolver may propose
|
||||
# it; this function must not.
|
||||
doc = derive("This replaces the 2018 edition.\n", "n500-2021.md")
|
||||
doc = derive("This replaces the 2018 edition.\n", "q500-2021.md")
|
||||
assert doc.supersedes == ()
|
||||
|
||||
|
||||
def test_version_is_declared_only() -> None:
|
||||
assert derive("---\nversion: '2021'\n---\n\nbody\n", "x.md").version == "2021"
|
||||
assert derive("body\n", "n500-2021.md").version is None
|
||||
assert derive("body\n", "q500-2021.md").version is None
|
||||
|
||||
|
||||
# --- pass-through of the producer's own keys ------------------------------
|
||||
|
|
@ -231,8 +231,8 @@ def test_a_document_with_no_frontmatter_declares_nothing() -> None:
|
|||
|
||||
|
||||
def test_derivation_is_deterministic() -> None:
|
||||
text = "---\nstatus: gjeldende\n---\n\n# N500 Vegbygging\n\nSee N200.\n"
|
||||
assert derive(text, "n500-vegbygging.md") == derive(text, "n500-vegbygging.md")
|
||||
text = "---\nstatus: gjeldende\n---\n\n# Q500 Surdeigsbaking\n\nSee Q200.\n"
|
||||
assert derive(text, "q500-surdeigsbaking.md") == derive(text, "q500-surdeigsbaking.md")
|
||||
|
||||
|
||||
# --- bundle-level resolution ----------------------------------------------
|
||||
|
|
@ -258,10 +258,10 @@ def edges_of(bundle: BundleStructure, kind: str) -> list[tuple[str, str, str | N
|
|||
|
||||
def test_a_reference_resolves_to_the_document_carrying_that_number() -> None:
|
||||
bundle = resolve(
|
||||
doc("inbox-n500", "See N200 for details.\n", "n500-vegbygging.md"),
|
||||
doc("inbox-n200", "body\n", "n200-grunnlag.md"),
|
||||
doc("inbox-q500", "See Q200 for details.\n", "q500-surdeigsbaking.md"),
|
||||
doc("inbox-q200", "body\n", "q200-grunnlag.md"),
|
||||
)
|
||||
assert edges_of(bundle, "references") == [("inbox-n500", "N200", "inbox-n200")]
|
||||
assert edges_of(bundle, "references") == [("inbox-q500", "Q200", "inbox-q200")]
|
||||
assert bundle.unresolved == ()
|
||||
|
||||
|
||||
|
|
@ -269,17 +269,17 @@ def test_a_reference_to_a_document_not_yet_dropped_is_UNRESOLVED_not_dropped() -
|
|||
# Normal state while a bundle is still being built up. It must be visible
|
||||
# as unfulfilled: an absence that does not scream is the most dangerous
|
||||
# state this repo knows.
|
||||
bundle = resolve(doc("inbox-n500", "See N200.\n", "n500-x.md"))
|
||||
assert edges_of(bundle, "references") == [("inbox-n500", "N200", None)]
|
||||
assert [e.subject for e in bundle.unresolved] == ["N200"]
|
||||
bundle = resolve(doc("inbox-q500", "See Q200.\n", "q500-x.md"))
|
||||
assert edges_of(bundle, "references") == [("inbox-q500", "Q200", None)]
|
||||
assert [e.subject for e in bundle.unresolved] == ["Q200"]
|
||||
|
||||
|
||||
def test_a_reference_resolves_once_its_target_arrives_in_a_later_round() -> None:
|
||||
first = doc("inbox-n500", "See N200.\n", "n500-x.md")
|
||||
first = doc("inbox-q500", "See Q200.\n", "q500-x.md")
|
||||
assert resolve(first).unresolved != ()
|
||||
later = resolve(first, doc("inbox-n200", "body\n", "n200-y.md"))
|
||||
later = resolve(first, doc("inbox-q200", "body\n", "q200-y.md"))
|
||||
assert later.unresolved == ()
|
||||
assert edges_of(later, "references") == [("inbox-n500", "N200", "inbox-n200")]
|
||||
assert edges_of(later, "references") == [("inbox-q500", "Q200", "inbox-q200")]
|
||||
|
||||
|
||||
def test_a_link_target_resolves_against_the_source_filename() -> None:
|
||||
|
|
@ -287,10 +287,10 @@ def test_a_link_target_resolves_against_the_source_filename() -> None:
|
|||
# the file arrived as, never at the concept name. Resolving only concept
|
||||
# names would report every intra-bundle link as dangling.
|
||||
bundle = resolve(
|
||||
doc("inbox-a", "See [other](n200-grunnlag.md).\n", "a.md"),
|
||||
doc("inbox-n200", "body\n", "n200-grunnlag.md"),
|
||||
doc("inbox-a", "See [other](q200-grunnlag.md).\n", "a.md"),
|
||||
doc("inbox-q200", "body\n", "q200-grunnlag.md"),
|
||||
)
|
||||
assert edges_of(bundle, "references") == [("inbox-a", "n200-grunnlag.md", "inbox-n200")]
|
||||
assert edges_of(bundle, "references") == [("inbox-a", "q200-grunnlag.md", "inbox-q200")]
|
||||
|
||||
|
||||
def test_parent_resolves_to_the_document_carrying_the_parent_number() -> None:
|
||||
|
|
@ -308,19 +308,19 @@ def test_a_missing_parent_is_unresolved_rather_than_absent() -> None:
|
|||
|
||||
def test_declared_supersedes_resolves_and_is_not_derived() -> None:
|
||||
bundle = resolve(
|
||||
doc("inbox-new", "---\nsupersedes: [n500-2018]\n---\nbody\n", "n500-2021.md"),
|
||||
doc("inbox-old", "body\n", "n500-2018.md"),
|
||||
doc("inbox-new", "---\nsupersedes: [q500-2018]\n---\nbody\n", "q500-2021.md"),
|
||||
doc("inbox-old", "body\n", "q500-2018.md"),
|
||||
)
|
||||
assert edges_of(bundle, "supersedes") == [("inbox-new", "n500-2018", "inbox-old")]
|
||||
assert edges_of(bundle, "supersedes") == [("inbox-new", "q500-2018", "inbox-old")]
|
||||
assert [e.derived for e in bundle.edges if e.kind == "supersedes"] == [False]
|
||||
|
||||
|
||||
def test_same_number_with_ordered_versions_yields_a_DERIVED_supersedes_chain() -> None:
|
||||
# The one pair-level heuristic in the module, and it is marked as such.
|
||||
bundle = resolve(
|
||||
doc("inbox-a", "---\nnumber: N500\nversion: '2018'\n---\nbody\n", "a.md"),
|
||||
doc("inbox-b", "---\nnumber: N500\nversion: '2021'\n---\nbody\n", "b.md"),
|
||||
doc("inbox-c", "---\nnumber: N500\nversion: '2026'\n---\nbody\n", "c.md"),
|
||||
doc("inbox-a", "---\nnumber: Q500\nversion: '2018'\n---\nbody\n", "a.md"),
|
||||
doc("inbox-b", "---\nnumber: Q500\nversion: '2021'\n---\nbody\n", "b.md"),
|
||||
doc("inbox-c", "---\nnumber: Q500\nversion: '2026'\n---\nbody\n", "c.md"),
|
||||
)
|
||||
chain = [(e.source, e.target) for e in bundle.edges if e.kind == "supersedes"]
|
||||
assert chain == [("inbox-b", "inbox-a"), ("inbox-c", "inbox-b")]
|
||||
|
|
@ -331,16 +331,16 @@ def test_same_number_without_versions_proposes_nothing() -> None:
|
|||
# Two documents sharing a number and no way to order them is exactly the
|
||||
# case where a guess would be indistinguishable from a fact.
|
||||
bundle = resolve(
|
||||
doc("inbox-a", "---\nnumber: N500\n---\nbody\n", "a.md"),
|
||||
doc("inbox-b", "---\nnumber: N500\n---\nbody\n", "b.md"),
|
||||
doc("inbox-a", "---\nnumber: Q500\n---\nbody\n", "a.md"),
|
||||
doc("inbox-b", "---\nnumber: Q500\n---\nbody\n", "b.md"),
|
||||
)
|
||||
assert edges_of(bundle, "supersedes") == []
|
||||
|
||||
|
||||
def test_version_ordering_is_numeric_not_lexicographic() -> None:
|
||||
bundle = resolve(
|
||||
doc("inbox-a", "---\nnumber: N500\nversion: '9'\n---\nbody\n", "a.md"),
|
||||
doc("inbox-b", "---\nnumber: N500\nversion: '10'\n---\nbody\n", "b.md"),
|
||||
doc("inbox-a", "---\nnumber: Q500\nversion: '9'\n---\nbody\n", "a.md"),
|
||||
doc("inbox-b", "---\nnumber: Q500\nversion: '10'\n---\nbody\n", "b.md"),
|
||||
)
|
||||
assert [(e.source, e.target) for e in bundle.edges if e.kind == "supersedes"] == [
|
||||
("inbox-b", "inbox-a")
|
||||
|
|
@ -351,14 +351,14 @@ def test_version_ordering_is_numeric_not_lexicographic() -> None:
|
|||
|
||||
|
||||
def test_resolution_does_not_depend_on_the_order_documents_were_added() -> None:
|
||||
a = doc("inbox-a", "See N200.\n", "n500-x.md")
|
||||
b = doc("inbox-n200", "See N500.\n", "n200-y.md")
|
||||
a = doc("inbox-a", "See Q200.\n", "q500-x.md")
|
||||
b = doc("inbox-q200", "See Q500.\n", "q200-y.md")
|
||||
assert resolve(a, b) == resolve(b, a)
|
||||
|
||||
|
||||
def test_resolving_the_same_document_twice_yields_one_edge_not_two() -> None:
|
||||
a = doc("inbox-a", "See N200.\n", "n500-x.md")
|
||||
b = doc("inbox-n200", "body\n", "n200-y.md")
|
||||
a = doc("inbox-a", "See Q200.\n", "q500-x.md")
|
||||
b = doc("inbox-q200", "body\n", "q200-y.md")
|
||||
once = resolve(a, b)
|
||||
# A mapping cannot hold the same key twice, which is the point: identity is
|
||||
# the concept name, so re-dropping a file replaces rather than accumulates.
|
||||
|
|
@ -368,8 +368,8 @@ def test_resolving_the_same_document_twice_yields_one_edge_not_two() -> None:
|
|||
|
||||
def test_edges_are_deterministically_ordered() -> None:
|
||||
bundle = resolve(
|
||||
doc("inbox-b", "See N100 and N300.\n", "n200-b.md"),
|
||||
doc("inbox-a", "See N300.\n", "n100-a.md"),
|
||||
doc("inbox-b", "See Q100 and Q300.\n", "q200-b.md"),
|
||||
doc("inbox-a", "See Q300.\n", "q100-a.md"),
|
||||
)
|
||||
assert list(bundle.edges) == sorted(bundle.edges, key=lambda e: (e.source, e.kind, e.subject))
|
||||
|
||||
|
|
@ -390,46 +390,46 @@ def test_edges_are_deterministically_ordered() -> None:
|
|||
# `1.6`), a hash algorithm name (`SHA256`), and tokens lifted out
|
||||
# of escape sequences in quoted source (`\n60` -> `N60`).
|
||||
#
|
||||
# The version class cannot be excluded structurally: corpus A proves `V221` and
|
||||
# `V240` are genuine document numbers and corpus B proves `V0.3.0` is a
|
||||
# The version class cannot be excluded structurally: corpus A proves `W221` and
|
||||
# `W240` are genuine document numbers and corpus B proves `V0.3.0` is a
|
||||
# software version, and they are the same token shape. So no blacklist can
|
||||
# work, and a positive cue is the only rule that can be defended against data.
|
||||
# A missing reference is visible to the reader; a false one is not.
|
||||
|
||||
|
||||
def test_a_package_version_is_not_a_reference() -> None:
|
||||
doc = derive("Built on pdfplumber 0.11.10 and Python 3.14.0, licence AGPL-3.0.\n", "n500-x.md")
|
||||
doc = derive("Built on pdfplumber 0.11.10 and Python 3.14.0, licence AGPL-3.0.\n", "q500-x.md")
|
||||
assert doc.references == ()
|
||||
|
||||
|
||||
def test_a_v_prefixed_version_is_not_a_reference() -> None:
|
||||
# The reported failure class: a version string carried in a title, read as
|
||||
# a document number. `V221` in corpus A is a real document; `v0.5.0` here
|
||||
# a document number. `W221` in corpus A is a real document; `v0.5.0` here
|
||||
# is not, and only the cue in front of it can tell them apart.
|
||||
doc = derive("The classifier lags v0.3.0 and the gap is wider now (v0.5.0a2).\n", "n500-x.md")
|
||||
doc = derive("The classifier lags v0.3.0 and the gap is wider now (v0.5.0a2).\n", "q500-x.md")
|
||||
assert doc.references == ()
|
||||
|
||||
|
||||
def test_a_number_inside_markup_is_not_a_reference() -> None:
|
||||
doc = derive('<math id="id-647a093b-a70f-4e38-d277-b139040226a4">x</math>\n', "n500-x.md")
|
||||
doc = derive('<math id="id-647a093b-a70f-4e38-d277-b139040226a4">x</math>\n', "q500-x.md")
|
||||
assert doc.references == ()
|
||||
|
||||
|
||||
def test_a_measurement_is_not_a_reference() -> None:
|
||||
doc = derive("Compressive strength at least 500 kN/m2, used only below 2.5 m.\n", "n500-x.md")
|
||||
doc = derive("Compressive strength at least 500 kN/m2, used only below 2.5 m.\n", "q500-x.md")
|
||||
assert doc.references == ()
|
||||
|
||||
|
||||
def test_a_cue_word_makes_a_number_a_reference() -> None:
|
||||
# KNOWN-POSITIVE. Without it the two tests above pass for the wrong reason:
|
||||
# a rule that finds nothing at all also finds nothing false.
|
||||
doc = derive("Laid to depth as se kapittel 2.6.2.2 and tabell 4.8.4-3 give.\n", "n500-x.md")
|
||||
doc = derive("Laid to depth as se kapittel 2.6.2.2 and tabell 4.8.4-3 give.\n", "q500-x.md")
|
||||
assert doc.references == ("2.6.2.2", "4.8.4")
|
||||
assert "references" in doc.derived
|
||||
|
||||
|
||||
def test_a_section_sign_is_a_cue() -> None:
|
||||
doc = derive("Emitted as one block, in §10.2's own listing order.\n", "n500-x.md")
|
||||
doc = derive("Emitted as one block, in §10.2's own listing order.\n", "q500-x.md")
|
||||
assert doc.references == ("10.2",)
|
||||
|
||||
|
||||
|
|
@ -437,14 +437,14 @@ def test_a_cue_only_counts_at_a_word_boundary() -> None:
|
|||
# A Norwegian compound ending in `-klasse` ends in the cue `se`. Matching
|
||||
# an unanchored cue admitted 86 such class designations on corpus A, none
|
||||
# of which name a document.
|
||||
doc = derive("Se også R210; lysklasse C5 gjelder.\n", "n500-x.md")
|
||||
assert doc.references == ("R210",)
|
||||
doc = derive("Se også P210; ovnsklasse C5 gjelder.\n", "q500-x.md")
|
||||
assert doc.references == ("P210",)
|
||||
|
||||
|
||||
def test_a_fragment_only_link_target_is_not_a_reference() -> None:
|
||||
# An anchor points inside THIS document. It can never resolve to another
|
||||
# concept, so emitting it states a relation that cannot exist.
|
||||
doc = derive("See [table pairing](#table-pairing).\n", "n500-x.md")
|
||||
doc = derive("See [table pairing](#table-pairing).\n", "q500-x.md")
|
||||
assert doc.references == ()
|
||||
|
||||
|
||||
|
|
@ -453,5 +453,5 @@ def test_a_template_placeholder_link_target_is_not_a_reference() -> None:
|
|||
# occur in a concept name (`reduce_to_id_grammar` emits lowercase
|
||||
# alphanumerics and hyphens), so such a target can never resolve — and an
|
||||
# edge that can never resolve is a claim, not a pending pointer.
|
||||
doc = derive("Managed lines read `- [title](ingest-{id}.md)`.\n", "n500-x.md")
|
||||
doc = derive("Managed lines read `- [title](ingest-{id}.md)`.\n", "q500-x.md")
|
||||
assert doc.references == ()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue