fix(okf): a flow sequence admits '#' and ':' where YAML reads them as text
1.4.0 refused a flow-sequence scalar element carrying '#' or ':' anywhere. okf writes `references: [...]` as a flow sequence of doc links, and an entry may carry a #fragment or a scheme://. claude-code-llm-wiki measured parse_frontmatter raising on 2 038 of 5 467 concepts of a bundle okf produced (2026-09-17); reproduced here on the same bundle, 2 038 / 5 467 before and 0 / 5 467 after (0 / 4 466 and 0 / 5 530 on the two other builds). The two characters are now refused by position, where PyYAML 6.0.3 gives them a meaning: '#' opening the element or following whitespace (a comment), ':' opening or ending the element or preceding whitespace (a mapping). Elsewhere they are scalar characters. The rest of the refused set, the indicator rule and the no-mixing rule are unchanged. Chosen over admitting the characters wholesale because `[a: b]` is a mapping and `[a #b]` a comment to YAML; admitting those would hand the consumer a value YAML does not read. The position checks are substring tests, no regex: CPU time stays linear in element count and length (100k -> 800k), about 10 % over 1.4.0, inside the existing 2 s bound. Pinned upstream corpus unmoved at 6 / 53. 910 passed (+17), coverage exit 0, redos-sweep exit 0, 45 LIMITATIONS entries.
This commit is contained in:
parent
79285e1265
commit
639da03f8c
4 changed files with 119 additions and 6 deletions
|
|
@ -1143,6 +1143,52 @@ def test_a_flow_sequence_scalar_element_must_be_a_plain_scalar(cid, fm):
|
|||
parse_frontmatter(f"---\ntype: table\n{fm}---\n\nbody\n")
|
||||
|
||||
|
||||
# --- 1.4.1: `#` and `:` are refused where YAML gives them a meaning, not anywhere
|
||||
# 1.4.0 refused both characters anywhere in an element. A consumer measured what
|
||||
# that costs (claude-code-llm-wiki, 2026-09-17, reproduced here 2026-09-23 on
|
||||
# the same bundle): okf writes `references: [...]` as a flow sequence of doc
|
||||
# links, an entry may carry a `#fragment` or a `scheme://`, and 2 038 of 5 467
|
||||
# concepts raised on it. YAML itself reads those as plain scalars. The boundary
|
||||
# is where YAML puts it, ground-truthed against PyYAML 6.0.3 on each row below:
|
||||
# `#` opens a comment only at the start of an element or after whitespace, and
|
||||
# `:` opens a mapping only at the start of an element, at its end, or before
|
||||
# whitespace. Everywhere else both are ordinary characters of the scalar.
|
||||
|
||||
@pytest.mark.parametrize("cid,fm,expected", [
|
||||
("okf's own references line",
|
||||
"references: [/docs/en/claude-platform-on-aws, /docs/en/amazon-bedrock#3-configure-claude-code]\n",
|
||||
["/docs/en/claude-platform-on-aws", "/docs/en/amazon-bedrock#3-configure-claude-code"]),
|
||||
("fragment mid-element", "tags: [a#b]\n", ["a#b"]),
|
||||
("fragment at the end", "tags: [a#]\n", ["a#"]),
|
||||
("custom URL scheme", "references: [claude-cli://open]\n", ["claude-cli://open"]),
|
||||
("scheme then a second element", "references: [vscode://ext/x, y]\n", ["vscode://ext/x", "y"]),
|
||||
("host and port", "references: [https://e.com:8443/a]\n", ["https://e.com:8443/a"]),
|
||||
("colon between two characters", "tags: [a:b]\n", ["a:b"]),
|
||||
("space before the colon, none after", "tags: [a :b]\n", ["a :b"]),
|
||||
("scheme and fragment together", "references: [x://y#z]\n", ["x://y#z"]),
|
||||
])
|
||||
def test_a_flow_sequence_scalar_admits_hash_and_colon_where_yaml_does(cid, fm, expected):
|
||||
key = fm.split(":", 1)[0]
|
||||
assert parse_frontmatter(f"---\ntype: table\n{fm}---\n\nbody\n")[0][key] == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cid,fm", [
|
||||
# Each of these is a ParserError or a mapping in PyYAML 6.0.3, so each stays
|
||||
# refused: admitting it would hand back a value YAML does not read.
|
||||
("hash opening an element", "tags: [#b]\n"),
|
||||
("hash opening a second element", "tags: [a, #b]\n"),
|
||||
("hash after a space", "tags: [a # b, c]\n"),
|
||||
("hash after a tab", "tags: [a\t#b]\n"),
|
||||
("colon ending an element", "tags: [a:]\n"),
|
||||
("colon before the separator", "tags: [a:, b]\n"),
|
||||
("colon opening an element", "tags: [:a]\n"),
|
||||
("colon before a tab", "tags: [a:\tb]\n"),
|
||||
])
|
||||
def test_a_flow_sequence_scalar_still_refuses_hash_and_colon_where_yaml_reads_them(cid, fm):
|
||||
with pytest.raises(OKFFrontmatterError):
|
||||
parse_frontmatter(f"---\ntype: table\n{fm}---\n\nbody\n")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("cid,fm", [
|
||||
("scalar then mapping", "tags: [a, {b: c}]\n"),
|
||||
("mapping then scalar", "sources: [{ id: a }, plain]\n"),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue