Skip to content

Bug: _load_narrative overwrites truncated/corrupt narratives instead of quarantining #147

@tcconnally

Description

@tcconnally

Severity: 🟡 Medium (data integrity)

_load_narrative (mneme_narrative.py:45–57) returns ({}, "") on any read/parse error. The caller (_memory_do_update) then treats this as "no narrative yet" and starts fresh, overwriting the truncated file.

If the truncation was caused by a prior crash mid-write (see related: lack of fsync in _save_narrative), this turns a recoverable situation into permanent data loss.

Suggested fix

On read error, quarantine before returning empty:

def _load_narrative(path: Path) -> tuple[dict, str]:
    if not path.exists():
        return {}, ""
    try:
        text = path.read_text(encoding="utf-8")
    except Exception as exc:
        backup = path.with_suffix(f".corrupt-{int(time.time())}.md")
        try:
            os.replace(path, backup)
            print(f"⚠ Mnēmē narrative {path} unreadable ({exc}); moved to {backup}",
                  file=sys.stderr)
        except OSError:
            pass
        return {}, ""
    fm, body = _parse_frontmatter(text)
    if not fm and not text.strip():
        return {}, ""
    if not fm:
        return {}, text
    return fm, body

Acceptance criteria

  • Test: corrupt a narrative file, call _load_narrative, assert (a) returns empty, (b) file was renamed to *.corrupt-<ts>.md.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions