fix(okf-normalize): so tratar bloco --- como frontmatter se for mapa YAML valido
Bug: parse_frontmatter aceitava qualquer bloco ---...--- inicial como frontmatter. Ficheiros que comecam com --- como regua/separador (ex: MEMORY.md seguido de ## heading) tinham o corpo tratado como frontmatter, e o ramo 'tem frontmatter' injectava campos OKF la dentro -> YAML partido (5 casos no run do Cloud). Fix: _looks_like_yaml_mapping() valida via PyYAML (isinstance dict) com fallback heuristico (1a linha = chave, sem heading markdown no topo). Tambem: report_path passou a escrever no dir do script (era path Hub hardcoded inexistente). Validado: caso-bug + regressao (com/sem frontmatter) -> 0 erros, YAML valido. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -81,14 +81,46 @@ def get_git_timestamp(filepath: Path, hub: Path) -> str:
|
|||||||
return datetime.fromtimestamp(mtime, tz=timezone.utc).isoformat()
|
return datetime.fromtimestamp(mtime, tz=timezone.utc).isoformat()
|
||||||
|
|
||||||
|
|
||||||
|
def _looks_like_yaml_mapping(fm: str) -> bool:
|
||||||
|
"""True só se o bloco for um mapa YAML válido (evita tratar régua '---' + corpo
|
||||||
|
como frontmatter — causa de corrupção em MEMORY.md e afins)."""
|
||||||
|
if not fm.strip():
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
import yaml # type: ignore
|
||||||
|
data = yaml.safe_load(fm)
|
||||||
|
return isinstance(data, dict)
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
# Fallback sem PyYAML: a 1ª linha não-vazia tem de ser uma chave `nome:`;
|
||||||
|
# nenhuma linha de topo (não-indentada, não-vazia) pode ser heading markdown.
|
||||||
|
first = None
|
||||||
|
for ln in fm.split("\n"):
|
||||||
|
if not ln.strip():
|
||||||
|
continue
|
||||||
|
if first is None:
|
||||||
|
first = ln
|
||||||
|
if ln[:1] == "#": # heading markdown ao nível de topo
|
||||||
|
return False
|
||||||
|
if first is None:
|
||||||
|
return False
|
||||||
|
return bool(re.match(r"^[A-Za-z_][\w\-]*:", first))
|
||||||
|
|
||||||
|
|
||||||
def parse_frontmatter(content: str):
|
def parse_frontmatter(content: str):
|
||||||
"""Retorna (frontmatter_str, body_str, has_fm) ou (None, content, False)."""
|
"""Retorna (frontmatter_str, body_str, has_fm) ou (None, content, False).
|
||||||
|
|
||||||
|
Só considera frontmatter um bloco `---…---` inicial que seja um MAPA YAML válido.
|
||||||
|
Um `---` inicial usado como régua/separador (seguido de corpo) NÃO é frontmatter."""
|
||||||
if content.startswith("---\n"):
|
if content.startswith("---\n"):
|
||||||
end = content.find("\n---\n", 4)
|
end = content.find("\n---\n", 4)
|
||||||
if end != -1:
|
if end != -1:
|
||||||
fm = content[4:end]
|
fm = content[4:end]
|
||||||
body = content[end + 5:]
|
if _looks_like_yaml_mapping(fm):
|
||||||
return fm, body, True
|
body = content[end + 5:]
|
||||||
|
return fm, body, True
|
||||||
return None, content, False
|
return None, content, False
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user