fix(skills): abort blob GC on a non-dict ledger row instead of raising
After json.loads() succeeds, gc_blobs() called row.get(...) unconditionally (tools/skill_ledger.py:353). A syntactically valid but non-object line such as `[]` or `"x"` raised AttributeError out of gc_blobs() and up through `hermes curator ledger --compact`. list_entries() already tolerates such rows with an isinstance(row, dict) check (~L414); mirror it here and abort the sweep with the same "malformed ledger line; blob GC skipped" warning — a row we cannot interpret may still hold blob references, so nothing may be deleted. Test: `non-dict-row` param on the kept invariant test (ledger + b"[]\n"). RED with the guard removed (AttributeError: 'list' object has no attribute 'get'), GREEN at head.
This commit is contained in:
@@ -94,7 +94,7 @@ def test_gc_blobs_removes_only_unreferenced(ledger_home):
|
||||
assert skill_ledger.gc_blobs() == (0, 0)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("failure", ["unreadable", "missing", "invalid-encoding", "malformed-json"])
|
||||
@pytest.mark.parametrize("failure", ["unreadable", "missing", "invalid-encoding", "malformed-json", "non-dict-row"])
|
||||
def test_gc_keeps_rollback_blobs_when_the_ledger_cannot_be_read(ledger_home, monkeypatch, caplog, failure):
|
||||
from tools import skill_ledger
|
||||
|
||||
@@ -121,6 +121,8 @@ def test_gc_keeps_rollback_blobs_when_the_ledger_cannot_be_read(ledger_home, mon
|
||||
ledger.unlink()
|
||||
elif failure == "malformed-json":
|
||||
ledger.write_bytes(saved + b"{broken\n")
|
||||
elif failure == "non-dict-row":
|
||||
ledger.write_bytes(saved + b"[]\n")
|
||||
else:
|
||||
ledger.write_bytes(b"\xff")
|
||||
assert skill_ledger.gc_blobs() == (0, 0)
|
||||
|
||||
@@ -351,6 +351,9 @@ def gc_blobs() -> Tuple[int, int]:
|
||||
except json.JSONDecodeError:
|
||||
logger.warning("skill_ledger: malformed ledger line; blob GC skipped")
|
||||
return 0, 0
|
||||
if not isinstance(row, dict):
|
||||
logger.warning("skill_ledger: malformed ledger line; blob GC skipped")
|
||||
return 0, 0
|
||||
for item in (row.get("before") or []) + (row.get("after") or []):
|
||||
referenced.add(str(item.get("sha256", "")))
|
||||
deleted = freed = 0
|
||||
|
||||
Reference in New Issue
Block a user