📦 deps(thirdparty): update snapshots
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Find stale entries in .lore/.
|
||||
|
||||
Usage:
|
||||
python find_stale.py # default: 90-day threshold
|
||||
python find_stale.py --days=180
|
||||
python find_stale.py --json
|
||||
|
||||
Reports two categories:
|
||||
|
||||
Stale : entry has not been `#verified` within the threshold
|
||||
(or has no #verified at all, and was added > threshold
|
||||
days ago).
|
||||
Pending arch : entry already carries a `#stale:` tag and is waiting
|
||||
to be moved into .lore/archive/.
|
||||
|
||||
Output is plain text by default, JSON with --json.
|
||||
|
||||
Used by:
|
||||
- `audit` workflow (read-only)
|
||||
- `compress` workflow (advisory)
|
||||
- `lore mirror` (sanity check before regenerating)
|
||||
"""
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from datetime import date, datetime, timedelta
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def get_entries():
|
||||
script = Path(__file__).parent / "list_entries.py"
|
||||
r = subprocess.run(
|
||||
[sys.executable, str(script), "--json"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
if r.returncode != 0:
|
||||
print(r.stderr.strip(), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
try:
|
||||
return json.loads(r.stdout)
|
||||
except json.JSONDecodeError as exc:
|
||||
print(f"error: list_entries.py returned invalid JSON: {exc}",
|
||||
file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def parse_date(s: str):
|
||||
try:
|
||||
return datetime.strptime(s, "%Y-%m-%d").date()
|
||||
except (ValueError, TypeError):
|
||||
return None
|
||||
|
||||
|
||||
def main():
|
||||
days = 90
|
||||
json_output = "--json" in sys.argv[1:]
|
||||
|
||||
for arg in sys.argv[1:]:
|
||||
if arg.startswith("--days="):
|
||||
days = int(arg.split("=", 1)[1])
|
||||
|
||||
today = date.today()
|
||||
cutoff = today - timedelta(days=days)
|
||||
|
||||
entries = get_entries()
|
||||
stale = []
|
||||
pending_arch = []
|
||||
|
||||
for e in entries:
|
||||
# Already marked stale → pending archive
|
||||
if "stale" in e["tags"]:
|
||||
pending_arch.append(e)
|
||||
continue
|
||||
|
||||
# Determine the entry's freshness date
|
||||
last_v = parse_date(e["last_verified"])
|
||||
added = parse_date(e["tags"].get("added"))
|
||||
ref_date = last_v or added
|
||||
|
||||
if ref_date is None:
|
||||
continue # no date info, can't decide
|
||||
|
||||
if ref_date < cutoff:
|
||||
stale.append(e)
|
||||
|
||||
if json_output:
|
||||
out = {
|
||||
"threshold_days": days,
|
||||
"as_of": today.isoformat(),
|
||||
"stale": stale,
|
||||
"pending_archive": pending_arch,
|
||||
}
|
||||
print(json.dumps(out, indent=2, ensure_ascii=False))
|
||||
return
|
||||
|
||||
print(f"=== Stale (unverified > {days} days, as of {today}) ===")
|
||||
if not stale:
|
||||
print(" (none)")
|
||||
for e in stale:
|
||||
ref = e["last_verified"] or e["tags"].get("added", "unknown")
|
||||
print(f" [{e['file']}] {e['id']} {e['text']}")
|
||||
print(f" ref date: {ref}")
|
||||
|
||||
print()
|
||||
print("=== Pending archive (tagged #stale) ===")
|
||||
if not pending_arch:
|
||||
print(" (none)")
|
||||
for e in pending_arch:
|
||||
print(f" [{e['file']}] {e['id']} {e['text']}")
|
||||
print(f" marked stale: {e['tags']['stale']}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user