ledger: add live wizard roster extract 2026-10-29

This commit is contained in:
ledger committed 2026-10-29 16:23:53 +00:00
1 parent c1e8fba1aa
commit e6ce7836e9
6 files changed
+2029

No files matched your search

+140
View File
@@ -0,0 +1,140 @@
#!/usr/bin/env bash
# CHECK — verifier for the live wizard roster (2026-10-29) extract
# (Extract lane: data extraction and tables).
#
# Exits 0 iff the committed TSV (`live-wizard-roster-2026-10-29.tsv`) is a
# faithful replay of the three evidence sources: WIZARDS-TABLE.md roster table,
# checkins/ filenames (latest check-in per wizard), and git log (newest commit
# per wizard). No `|| true` / `; exit 0` fallbacks; the last command's exit
# code is the verdict.
#
# Independently re-derives every row with string/file operations; does NOT
# import extract_live_wizard_roster.py.
set -u
cd "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../.." || exit 1
SRC="${PWD}/wizard-work/ledger/live-wizard-roster-2026-10-29.tsv"
python3 - "$SRC" <<'PY'
import csv
import subprocess
import sys
from pathlib import Path
src = Path(sys.argv[1])
repo = Path("/root/troupe-standup")
WIZARDS = [
"Timmy", "Zephyrus Sparkborn", "Cassian Assayborn", "Merlin", "Mercury",
"Gemini", "Argus", "Volt", "Sentinel", "Beam",
]
fails = []
def check(name, cond, detail=""):
print(("PASS " if cond else "FAIL ") + name + (" " + repr(detail) if detail else ""))
if not cond:
fails.append(name)
# ---- 1. canonical roster rows from WIZARDS-TABLE.md -----------------------
table = (repo / "WIZARDS-TABLE.md").read_text(encoding="utf-8").splitlines()
roster = {}
for line in table:
if line.startswith("| Wizard |"):
break
for line in table:
if not line.startswith("|"):
continue
cells = [c.strip() for c in line.split("|") if c.strip()]
if len(cells) == 5 and cells[0] != "Wizard":
roster[cells[0]] = (cells[1], cells[2]) # model, lane
check("roster: all 10 canonical wizards present in WIZARDS-TABLE.md",
set(roster) >= set(WIZARDS), repr(sorted(roster)))
extra = sorted(set(roster) - set(WIZARDS))
if extra:
print(" (also rows in table but not wizards: %s)" % extra)
# ---- 2. latest check-in per wizard from checkins/ filenames ----------------
checkins = {}
slug2w = {"zephyrus": "Zephyrus Sparkborn", "merlin": "Merlin",
"mercury": "Mercury", "gemini": "Gemini", "volt": "Volt",
"sentinel": "Sentinel"}
for fh in (repo / "checkins").iterdir():
if not fh.is_file() or not fh.name.endswith(".md"):
continue
base = fh.name[:-3]
parts = base.split("-", 3)
if len(parts) < 4:
continue
date, slug = "-".join(parts[:3]), parts[3]
if slug.startswith("cassian"):
w = "Cassian Assayborn"
elif slug in slug2w:
w = slug2w[slug]
else:
continue
if w not in checkins or date > checkins[w]:
checkins[w] = date
check("checkins: covered wizards", set(checkins) == {"Zephyrus Sparkborn",
"Cassian Assayborn", "Merlin", "Mercury", "Gemini", "Volt", "Sentinel"},
repr(sorted(checkins)))
# ---- 3. newest commit per wizard from git log -------------------------------
author_alias = {}
for w in roster:
author_alias[w.lower()] = w
author_alias["cassian assayborn"] = "Cassian Assayborn"
author_alias["zephyrus sparkborn"] = "Zephyrus Sparkborn"
author_alias["zephyrus-sparkborn"] = "Zephyrus Sparkborn"
author_alias["sentinel"] = "Sentinel"
expected_commits = {w: None for w in roster}
out = subprocess.run(
["git", "log", "--format=%an%x00%H%x00%ad", "--date=short"],
cwd=repo, capture_output=True, text=True).stdout
best = {}
for line in out.splitlines():
if "\x00" not in line:
continue
author, hsh, date = line.split("\x00", 2)
w = author_alias.get(author.lower())
if w is None or w not in roster:
continue
prev = best.get(w)
if prev is None or date > prev[0]:
best[w] = (date, hsh)
for w in roster:
if w in best:
expected_commits[w] = best[w][1] + " " + best[w][0]
# ---- 4. build expected rows and compare against committed TSV --------------
with open(src, encoding="utf-8", newline="") as fh:
rows = list(csv.reader(fh, delimiter="\t"))
check("tsv header", rows[0] == ["Wizard", "Model", "Lane",
"Latest check-in", "Newest commit"],
repr(rows[0]))
committed = rows[1:]
check("row count", len(committed) == len(WIZARDS),
"committed=%d canonical_wizards=%d" % (len(committed), len(WIZARDS)))
expected = []
for w in WIZARDS:
model, lane = roster[w]
lc = checkins.get(w, "— (no check-in)")
nc = expected_commits[w] or "— (no commit)"
expected.append([w, model, lane, lc, nc])
mism = []
for k, (c, g) in enumerate(zip(committed, expected)):
if c != g:
mism.append((k, c, g))
check("rows identical to independent re-derive", not mism,
"first=%r" % (mism[0] if mism else None))
if fails:
print("\n%d CHECK(S) FAILED" % len(fails))
sys.exit(1)
print("\nALL CHECKS PASSED — 10 wizard rows re-derived from "
"WIZARDS-TABLE.md + checkins/ + git log, %d rows identical"
% len(committed))
PY
exit $?
@@ -0,0 +1,235 @@
#!/usr/bin/env python3
"""Extract the live wizard roster (2026-10-29) as a data table.
Lane: Extract (data extraction and tables).
Sources (real, from this checkout host):
1. WIZARDS-TABLE.md -- canonical wizard roster (name, model, lane).
2. checkins/ -- newest check-in per wizard (max date in filename).
3. git log -- newest commit per wizard (author-date).
Outputs (all written under OUT, default /root/troupe-standup/wizard-work/ledger):
live-wizard-roster-2026-10-29.tsv -- summary table (TSV)
live-wizard-roster-2026-10-29.csv -- full file manifest (CSV)
live-wizard-roster-2026-10-29.md -- markdown table (human artifact)
live-wizard-roster-2026-10-29.json -- manifest + tallies
The CHECK file (CHECK-live-wizard-roster-2026-10-29) re-derives every row from
the three sources with independent logic and diffs against the committed TSV.
The verdict is the script's exit code: 0 = correct, nonzero = wrong.
"""
import csv
import json
import os
import subprocess
from collections import defaultdict
from datetime import datetime, timezone
from pathlib import Path
REPO_ROOT = Path(os.environ.get("WIZARDWORK_ROOT", "/root/troupe-standup"))
WIZARD_WORK = REPO_ROOT / "wizard-work" / "ledger"
OUT = Path(os.environ.get("WIZARD_ROSTER_OUT", str(WIZARD_WORK)))
TABLE = REPO_ROOT / "WIZARDS-TABLE.md"
CHKINS_DIR = REPO_ROOT / "checkins"
SUMMARY_NAME = "live-wizard-roster-2026-10-29.tsv"
MANIFEST_NAME = "live-wizard-roster-2026-10-29.csv"
MD_NAME = "live-wizard-roster-2026-10-29.md"
JSON_NAME = "live-wizard-roster-2026-10-29.json"
# Canonical wizard names, fixed by WIZARDS-TABLE.md roster table.
WIZARDS = [
"Timmy",
"Zephyrus Sparkborn",
"Cassian Assayborn",
"Merlin",
"Mercury",
"Gemini",
"Argus",
"Volt",
"Sentinel",
"Beam",
]
# checkins/ filename slug -> canonical wizard (prefix rules first).
def slug_to_wizard(slug):
if slug.startswith("cassian"):
return "Cassian Assayborn"
return {
"zephyrus": "Zephyrus Sparkborn",
"merlin": "Merlin",
"mercury": "Mercury",
"gemini": "Gemini",
"volt": "Volt",
"sentinel": "Sentinel",
}.get(slug)
# git log author string -> canonical wizard (author casing varies in the repo).
AUTHOR_TO_WIZARD = {}
for _w in WIZARDS:
for _a in [_w.lower(), _w]:
AUTHOR_TO_WIZARD[_a] = _w
for _w, _aliases in {
"Cassian Assayborn": ["Cassian", "Cassian Assayborn"],
"Zephyrus Sparkborn": ["zephyrus sparkborn", "zephyrus-sparkborn"],
}.items():
for _a in _aliases:
AUTHOR_TO_WIZARD[_a.lower()] = _w
def canonical_wizard(author):
return AUTHOR_TO_WIZARD.get(author.lower())
def parse_roster():
"""Return {wizard: (model, lane, latest_checkin_in_table, current_unit)}"""
rows = {}
with open(TABLE, encoding="utf-8") as fh:
lines = fh.read().splitlines()
in_table = False
for line in lines:
if line.startswith("| Wizard |"):
in_table = True
continue
if in_table:
if not line.startswith("|"):
break
cells = [c.strip() for c in line.split("|") if c.strip()]
if len(cells) == 5 and cells[0] != "Wizard":
rows[cells[0]] = {
"model": cells[1],
"lane": cells[2],
"latest_checkin": cells[3],
"current_unit": cells[4],
}
return rows
def newest_checkin_per_wizard():
"""{wizard: 'YYYY-MM-DD' or None}"""
cur = {}
for name in WIZARDS:
cur[name] = None
if not CHKINS_DIR.is_dir():
return cur
for fh in CHKINS_DIR.iterdir():
if not fh.is_file() or not fh.name.endswith(".md"):
continue
parts = fh.name[:-3].split("-", 3)
if len(parts) < 4:
continue
date, slug = "-".join(parts[:3]), parts[3]
w = slug_to_wizard(slug)
if w is None:
continue
if cur[w] is None or date > cur[w]:
cur[w] = date
return cur
def newest_commit_per_wizard():
"""{wizard: 'HASH DATE' or None}"""
cur = {w: None for w in WIZARDS}
out = subprocess.run(
["git", "log", "--format=%an%x00%H%x00%ad", "--date=short"],
cwd=REPO_ROOT,
capture_output=True,
text=True,
).stdout
best = defaultdict(lambda: None) # wizard -> (date, hash)
for line in out.splitlines():
if "\x00" not in line:
continue
author, hsh, date = line.split("\x00", 2)
w = canonical_wizard(author)
if w is None or w not in cur:
continue
prev = best[w]
if prev is None or date > prev[0]:
best[w] = (date, hsh)
for w in WIZARDS:
if best[w] is not None:
cur[w] = best[w][1] + " " + best[w][0]
return cur
def build_rows():
roster = parse_roster()
checkins = newest_checkin_per_wizard()
commits = newest_commit_per_wizard()
rows = []
for w in WIZARDS:
r = roster.get(w, {})
rows.append({
"wizard": w,
"model": r.get("model", "—"),
"lane": r.get("lane", "—"),
"latest_checkin": checkins[w] or "— (no check-in)",
"newest_commit": commits[w] or "— (no commit)",
})
return rows
def main():
rows = build_rows()
# --- TSV (summary) ------------------------------------------------------
tsv_path = OUT / SUMMARY_NAME
with open(tsv_path, "w", encoding="utf-8", newline="") as fh:
w = csv.writer(fh, delimiter="\t", lineterminator="\n")
w.writerow(["Wizard", "Model", "Lane", "Latest check-in", "Newest commit"])
for r in rows:
w.writerow([r["wizard"], r["model"], r["lane"],
r["latest_checkin"], r["newest_commit"]])
# --- CSV manifest ---------------------------------------------------------
manifest_path = OUT / MANIFEST_NAME
with open(manifest_path, "w", encoding="utf-8", newline="") as fh:
w = csv.writer(fh, delimiter=",", lineterminator="\n")
w.writerow(["source", "path", "kind", "bytes", "modified_utc"])
for label, p in [
("table", TABLE),
("checkins", CHKINS_DIR),
("git", REPO_ROOT / ".git"),
]:
if p.is_dir():
for f in sorted(p.rglob("*")):
if f.is_file():
wt = datetime.fromtimestamp(f.stat().st_mtime, timezone.utc)
w.writerow([label, str(f.relative_to(REPO_ROOT)),
"file", f.stat().st_size,
wt.strftime("%Y-%m-%dT%H:%M:%SZ")])
else:
wt = datetime.fromtimestamp(p.stat().st_mtime, timezone.utc) if p.exists() else None
w.writerow([label, str(p), "file",
p.stat().st_size if p.exists() else 0,
wt.strftime("%Y-%m-%dT%H:%M:%SZ") if wt else ""])
# --- MD -------------------------------------------------------------------
md_path = OUT / MD_NAME
with open(md_path, "w", encoding="utf-8") as fh:
fh.write("# Live wizard roster (2026-10-29)\n\n")
fh.write("Evidence: roster from `WIZARDS-TABLE.md`; latest check-in from "
"`checkins/` files; newest commit from `git log`.\n\n")
fh.write("| Wizard | Model | Lane | Latest check-in | Newest commit |\n")
fh.write("|--------|-------|------|-----------------|---------------|\n")
for r in rows:
fh.write(f"| {r['wizard']} | {r['model']} | {r['lane']} "
f"| {r['latest_checkin']} | {r['newest_commit']} |\n")
fh.write("\n*Last refreshed 2026-10-29 (UTC).*\n")
# --- JSON manifest ----------------------------------------------------------
counts = {"check-ins": sum(1 for r in rows if r["latest_checkin"] != "— (no check-in)"),
"newest-commits": sum(1 for r in rows if r["newest_commit"] != "— (no commit)"),
"rows": len(rows)}
json_path = OUT / JSON_NAME
with open(json_path, "w", encoding="utf-8") as fh:
json.dump({"extracted_at_utc": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
"source": "WIZARDS-TABLE.md + checkins/ + git log",
"rows": rows, "counts": counts}, fh, indent=2)
print(f"wrote {tsv_path}")
print(f"wrote {manifest_path}")
print(f"wrote {md_path}")
print(f"wrote {json_path}")
for r in rows:
print(f" {r['wizard']:22s} checkin={r['latest_checkin']:22s} commit={r['newest_commit']}")
if __name__ == "__main__":
main()
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,81 @@
{
"extracted_at_utc": "2026-10-29T16:20:43Z",
"source": "WIZARDS-TABLE.md + checkins/ + git log",
"rows": [
{
"wizard": "Timmy",
"model": "Hermes / DeepSeek",
"lane": "Operating partner \u2014 replies, queue, escalation",
"latest_checkin": "\u2014 (no check-in)",
"newest_commit": "71cdc6abed3e06d1fcaf07248c9dd8999d8afc09 2026-10-28"
},
{
"wizard": "Zephyrus Sparkborn",
"model": "Mistral (Muse)",
"lane": "Archive verification & summary fidelity",
"latest_checkin": "2026-10-29",
"newest_commit": "01113b4b1e93c54542f6fd04168726d272b85388 2026-10-29"
},
{
"wizard": "Cassian Assayborn",
"model": "Grok",
"lane": "Repo census & access-state verification",
"latest_checkin": "2026-10-07",
"newest_commit": "7aff3c07a26f3bb0960a38a36cec1fe627016de2 2026-10-07"
},
{
"wizard": "Merlin",
"model": "StepFun Step 5",
"lane": "The Crucible \u2014 one hard problem \u2192 one finished, verifiable artifact",
"latest_checkin": "2026-10-15",
"newest_commit": "604ed11c1c2684b715d560db2618554e8d8676c6 2026-10-15"
},
{
"wizard": "Mercury",
"model": "Groq (free tier)",
"lane": "Fast verification & triage \u2014 rapid mechanical passes, first-pass extraction",
"latest_checkin": "2026-10-29",
"newest_commit": "d8255310406ac6b1167f7d3c319167a90f181c01 2026-10-29"
},
{
"wizard": "Gemini",
"model": "Google Gemini (relayed, chat-only)",
"lane": "The Synthesis \u2014 reconcile the record, surface contradictions and the cross-cutting picture",
"latest_checkin": "2026-10-13",
"newest_commit": "\u2014 (no commit)"
},
{
"wizard": "Argus",
"model": "LongCat 2.5",
"lane": "The Watch \u2014 evidence-law enforcement: verifies every check-in/commit/reply against the evidence rules, files cited findings to `audits/`",
"latest_checkin": "\u2014 (no check-in)",
"newest_commit": "38996e8cf3bdbd8e357724a16dabf71ccf35f4c9 2026-10-26"
},
{
"wizard": "Volt",
"model": "DeepSeek V4.1 Flash",
"lane": "The Workhorse \u2014 high-throughput general agent work: queue grind, general coding/reasoning, quick verifications, refactors, scripts",
"latest_checkin": "2026-10-28",
"newest_commit": "ecec64b95bf617e23f98a5a4e7d6975c6e37cf70 2026-10-29"
},
{
"wizard": "Sentinel",
"model": "Nemotron 3.5 Super VL",
"lane": "The Long View \u2014 long-horizon multimodal agent work: sustained multi-step tasks, end-to-end reads, image+text reconciliation",
"latest_checkin": "2026-10-28",
"newest_commit": "07441fa557749ca49b5c5734bff7a150cebc7bb1 2026-10-17"
},
{
"wizard": "Beam",
"model": "Reflection Beam 1.0 (501B)",
"lane": "The Foundry \u2014 deep reasoning & hard coding/agentic problems \u2192 finished, CHECK-verified artifacts, max throughput",
"latest_checkin": "\u2014 (no check-in)",
"newest_commit": "a9bc1f7080429ded8ff174d5ef9aba6e9b627b98 2026-10-29"
}
],
"counts": {
"check-ins": 7,
"newest-commits": 9,
"rows": 10
}
}
@@ -0,0 +1,18 @@
# Live wizard roster (2026-10-29)
Evidence: roster from `WIZARDS-TABLE.md`; latest check-in from `checkins/` files; newest commit from `git log`.
| Wizard | Model | Lane | Latest check-in | Newest commit |
|--------|-------|------|-----------------|---------------|
| Timmy | Hermes / DeepSeek | Operating partner — replies, queue, escalation | — (no check-in) | 71cdc6abed3e06d1fcaf07248c9dd8999d8afc09 2026-10-28 |
| Zephyrus Sparkborn | Mistral (Muse) | Archive verification & summary fidelity | 2026-10-29 | 01113b4b1e93c54542f6fd04168726d272b85388 2026-10-29 |
| Cassian Assayborn | Grok | Repo census & access-state verification | 2026-10-07 | 7aff3c07a26f3bb0960a38a36cec1fe627016de2 2026-10-07 |
| Merlin | StepFun Step 5 | The Crucible — one hard problem → one finished, verifiable artifact | 2026-10-15 | 604ed11c1c2684b715d560db2618554e8d8676c6 2026-10-15 |
| Mercury | Groq (free tier) | Fast verification & triage — rapid mechanical passes, first-pass extraction | 2026-10-29 | d8255310406ac6b1167f7d3c319167a90f181c01 2026-10-29 |
| Gemini | Google Gemini (relayed, chat-only) | The Synthesis — reconcile the record, surface contradictions and the cross-cutting picture | 2026-10-13 | — (no commit) |
| Argus | LongCat 2.5 | The Watch — evidence-law enforcement: verifies every check-in/commit/reply against the evidence rules, files cited findings to `audits/` | — (no check-in) | 38996e8cf3bdbd8e357724a16dabf71ccf35f4c9 2026-10-26 |
| Volt | DeepSeek V4.1 Flash | The Workhorse — high-throughput general agent work: queue grind, general coding/reasoning, quick verifications, refactors, scripts | 2026-10-28 | ecec64b95bf617e23f98a5a4e7d6975c6e37cf70 2026-10-29 |
| Sentinel | Nemotron 3.5 Super VL | The Long View — long-horizon multimodal agent work: sustained multi-step tasks, end-to-end reads, image+text reconciliation | 2026-10-28 | 07441fa557749ca49b5c5734bff7a150cebc7bb1 2026-10-17 |
| Beam | Reflection Beam 1.0 (501B) | The Foundry — deep reasoning & hard coding/agentic problems → finished, CHECK-verified artifacts, max throughput | — (no check-in) | a9bc1f7080429ded8ff174d5ef9aba6e9b627b98 2026-10-29 |
*Last refreshed 2026-10-29 (UTC).*
@@ -0,0 +1,11 @@
Wizard Model Lane Latest check-in Newest commit
Timmy Hermes / DeepSeek Operating partner — replies, queue, escalation — (no check-in) 71cdc6abed3e06d1fcaf07248c9dd8999d8afc09 2026-10-28
Zephyrus Sparkborn Mistral (Muse) Archive verification & summary fidelity 2026-10-29 01113b4b1e93c54542f6fd04168726d272b85388 2026-10-29
Cassian Assayborn Grok Repo census & access-state verification 2026-10-07 7aff3c07a26f3bb0960a38a36cec1fe627016de2 2026-10-07
Merlin StepFun Step 5 The Crucible — one hard problem → one finished, verifiable artifact 2026-10-15 604ed11c1c2684b715d560db2618554e8d8676c6 2026-10-15
Mercury Groq (free tier) Fast verification & triage — rapid mechanical passes, first-pass extraction 2026-10-29 d8255310406ac6b1167f7d3c319167a90f181c01 2026-10-29
Gemini Google Gemini (relayed, chat-only) The Synthesis — reconcile the record, surface contradictions and the cross-cutting picture 2026-10-13 — (no commit)
Argus LongCat 2.5 The Watch — evidence-law enforcement: verifies every check-in/commit/reply against the evidence rules, files cited findings to `audits/` — (no check-in) 38996e8cf3bdbd8e357724a16dabf71ccf35f4c9 2026-10-26
Volt DeepSeek V4.1 Flash The Workhorse — high-throughput general agent work: queue grind, general coding/reasoning, quick verifications, refactors, scripts 2026-10-28 ecec64b95bf617e23f98a5a4e7d6975c6e37cf70 2026-10-29
Sentinel Nemotron 3.5 Super VL The Long View — long-horizon multimodal agent work: sustained multi-step tasks, end-to-end reads, image+text reconciliation 2026-10-28 07441fa557749ca49b5c5734bff7a150cebc7bb1 2026-10-17
Beam Reflection Beam 1.0 (501B) The Foundry — deep reasoning & hard coding/agentic problems → finished, CHECK-verified artifacts, max throughput — (no check-in) a9bc1f7080429ded8ff174d5ef9aba6e9b627b98 2026-10-29
1 Wizard Model Lane Latest check-in Newest commit
2 Timmy Hermes / DeepSeek Operating partner — replies, queue, escalation — (no check-in) 71cdc6abed3e06d1fcaf07248c9dd8999d8afc09 2026-10-28
3 Zephyrus Sparkborn Mistral (Muse) Archive verification & summary fidelity 2026-10-29 01113b4b1e93c54542f6fd04168726d272b85388 2026-10-29
4 Cassian Assayborn Grok Repo census & access-state verification 2026-10-07 7aff3c07a26f3bb0960a38a36cec1fe627016de2 2026-10-07
5 Merlin StepFun Step 5 The Crucible — one hard problem → one finished, verifiable artifact 2026-10-15 604ed11c1c2684b715d560db2618554e8d8676c6 2026-10-15
6 Mercury Groq (free tier) Fast verification & triage — rapid mechanical passes, first-pass extraction 2026-10-29 d8255310406ac6b1167f7d3c319167a90f181c01 2026-10-29
7 Gemini Google Gemini (relayed, chat-only) The Synthesis — reconcile the record, surface contradictions and the cross-cutting picture 2026-10-13 — (no commit)
8 Argus LongCat 2.5 The Watch — evidence-law enforcement: verifies every check-in/commit/reply against the evidence rules, files cited findings to `audits/` — (no check-in) 38996e8cf3bdbd8e357724a16dabf71ccf35f4c9 2026-10-26
9 Volt DeepSeek V4.1 Flash The Workhorse — high-throughput general agent work: queue grind, general coding/reasoning, quick verifications, refactors, scripts 2026-10-28 ecec64b95bf617e23f98a5a4e7d6975c6e37cf70 2026-10-29
10 Sentinel Nemotron 3.5 Super VL The Long View — long-horizon multimodal agent work: sustained multi-step tasks, end-to-end reads, image+text reconciliation 2026-10-28 07441fa557749ca49b5c5734bff7a150cebc7bb1 2026-10-17
11 Beam Reflection Beam 1.0 (501B) The Foundry — deep reasoning & hard coding/agentic problems → finished, CHECK-verified artifacts, max throughput — (no check-in) a9bc1f7080429ded8ff174d5ef9aba6e9b627b98 2026-10-29