mirror of
https://github.com/affaan-m/ECC.git
synced 2026-10-31 12:55:21 +00:00
fix: preserve escaped instinct strings through serialization
RED: multiline/control serialization and newline decoding failed; C1/NEL cases exposed malformed or folded YAML. GREEN: 40 targeted tests and 126 complete Linux tests pass; quote/parser coverage 100%/97.4%. Unicode, Windows paths and legacy escapes survive round trips; Pi/catalog checks pass.
(cherry picked from commit 1b1119f409)
This commit is contained in:
1 parent
21e0ab5271
commit
7b7ec11b2a
2 files changed
+37
-5
No files matched your search
@@ -238,11 +238,10 @@ def _fetch_import_url(source: str, *, max_bytes: int = 2 * 1024 * 1024) -> str:
|
||||
def _yaml_quote(value: str) -> str:
|
||||
"""Quote a string for safe YAML frontmatter serialization.
|
||||
|
||||
Uses double quotes and escapes embedded double-quote characters to
|
||||
prevent malformed YAML when the value contains quotes.
|
||||
JSON double-quoted strings are valid YAML and keep control characters
|
||||
escaped on one line, preserving instinct frontmatter boundaries.
|
||||
"""
|
||||
escaped = value.replace('\\', '\\\\').replace('"', '\\"')
|
||||
return f'"{escaped}"'
|
||||
return json.dumps(value)
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
@@ -546,7 +545,10 @@ def parse_instinct_file(content: str) -> list[dict]:
|
||||
value = value.strip()
|
||||
# Unescape quoted YAML strings
|
||||
if value.startswith('"') and value.endswith('"'):
|
||||
value = value[1:-1].replace('\\"', '"').replace('\\\\', '\\')
|
||||
try:
|
||||
value = json.loads(value)
|
||||
except json.JSONDecodeError:
|
||||
value = value[1:-1].replace('\\"', '"').replace('\\\\', '\\')
|
||||
elif value.startswith("'") and value.endswith("'"):
|
||||
value = value[1:-1].replace("''", "'")
|
||||
if key == 'confidence':
|
||||
|
||||
@@ -281,6 +281,36 @@ def test_parse_confidence_preserves_valid_range(confidence):
|
||||
assert parse_instinct_file(content)[0]["confidence"] == confidence
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [
|
||||
"line one\nline two", "tab\tvalue", "carriage\rreturn",
|
||||
'when writing "quoted" text', r"C:\Users\name", "caf\u00e9",
|
||||
r"literal\ntext", "line\n---\nid: other\n---", "control\x01value",
|
||||
])
|
||||
def test_quoted_instinct_strings_roundtrip(value: str) -> None:
|
||||
quoted = _mod._yaml_quote(value)
|
||||
assert json.loads(quoted) == value
|
||||
instincts = parse_instinct_file(f"---\nid: roundtrip\ntrigger: {quoted}\n---\nBody")
|
||||
assert len(instincts) == 1
|
||||
assert instincts[0]["trigger"] == value
|
||||
|
||||
|
||||
def test_parse_quoted_instinct_decodes_newline_escape() -> None:
|
||||
content = '---\nid: newline\ntrigger: "line one\\nline two"\n---\nBody'
|
||||
assert parse_instinct_file(content)[0]["trigger"] == "line one\nline two"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", ["line\u0085value", "line\u0090value"])
|
||||
def test_unicode_controls_are_escaped_for_yaml(value: str) -> None:
|
||||
quoted = _mod._yaml_quote(value)
|
||||
assert quoted.isascii()
|
||||
assert json.loads(quoted) == value
|
||||
|
||||
|
||||
def test_parse_quoted_instinct_preserves_legacy_escape() -> None:
|
||||
content = '---\nid: legacy\ntrigger: "C:\\projects"\n---\nBody'
|
||||
assert parse_instinct_file(content)[0]["trigger"] == r"C:\projects"
|
||||
|
||||
|
||||
def test_parse_trigger_strips_quotes():
|
||||
content = """\
|
||||
---
|
||||
|
||||
Reference in new issue
Block a user