0030cbd1de
gates / gates (push) Successful in 26s
The records the catalog's ladder entries cite (apps/<app>/bench and apps/<app>/verdict.json), the drill tools, the spike, R-626's run, R-612/R-613 red-proofs, the chaos schedule (seed 20260923) drawn BEFORE round 1. Docs and register follow at the end of the night. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
61 lines
3.5 KiB
Python
61 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Part B spike — does the controller tolerate a top-level `update_ladder:` key in .felhom.yml?
|
|
|
|
The drill catalog's navidrome carries the block (drill commit given as argv[1]). The app must sync,
|
|
deploy, probe and badge exactly as without it. Positive observables: the sync reaches the drill commit,
|
|
the metadata the page needs is read (display_name, deploy_fields), the deploy reaches `running`, the
|
|
controller's own health-probe line for navidrome appears, the badge renders in both languages."""
|
|
import sys, time, json, re
|
|
sys.path.insert(0, ".")
|
|
import walk as w
|
|
want = sys.argv[1]
|
|
tag = sys.argv[2] if len(sys.argv) > 2 else "v?"
|
|
w.login()
|
|
w.say(f"SPIKE on controller {tag}, drill commit {want}")
|
|
w.sync_rescan()
|
|
time.sleep(3)
|
|
head = w.guest("cat /var/lib/docker/volumes/felhom-controller-data/_data/catalog-cache/.git/HEAD 2>/dev/null; git -C /var/lib/docker/volumes/felhom-controller-data/_data/catalog-cache rev-parse --short=12 HEAD 2>/dev/null; ls /var/lib/docker/volumes/felhom-controller-data/_data/ | head -30")
|
|
w.say("catalog cache: " + head.replace("\n", " | "))
|
|
has = w.guest("grep -c '^update_ladder:' /opt/docker/stacks/navidrome/.felhom.yml")
|
|
w.say(f"update_ladder lines in the box's navidrome/.felhom.yml: {has.strip()}")
|
|
c, d = w.ctl("GET", "/api/stacks/navidrome/deploy-fields")
|
|
meta = ((d.get("data") or {}).get("metadata") or {})
|
|
w.say(f"deploy-fields -> {c}; display_name={meta.get('display_name')!r} fields={[f.get('env_var') for f in meta.get('deploy_fields') or []]}")
|
|
ok = w.deploy("navidrome", "navidrome")
|
|
w.wait_app("navidrome", "/")
|
|
probe = []
|
|
for _ in range(40):
|
|
c2, d2 = w.ctl("GET", "/api/debug/logs?level=DEBUG&lines=3000")
|
|
ents = ((d2.get("data") or {}).get("entries") or []) if isinstance(d2, dict) else []
|
|
probe = [e.get("timestamp", "") + " " + e.get("message", "") for e in ents
|
|
if "navidrome" in e.get("message", "") and "probe" in e.get("message", "").lower()]
|
|
if any("healthy=true" in p or "-> 200" in p or "→ 200" in p or " ok" in p for p in probe):
|
|
break
|
|
time.sleep(10)
|
|
w.say("probe lines for navidrome:\n " + "\n ".join(probe[-6:]))
|
|
st = w.stack("navidrome")
|
|
w.say(f"state={st.get('state')} deployed={st.get('deployed')} health={st.get('health')}")
|
|
import re as _re
|
|
b = {}
|
|
for i in range(12):
|
|
for lang, suf in (("hu", ""), ("en", "?lang=en")):
|
|
h = w.page(f"/apps/navidrome{suf}")
|
|
b[lang] = _re.findall(r'<span class="tag tag-[a-z]+" title="[^"]*">([^<]*)<', h)[:4]
|
|
if b["hu"] and b["en"]:
|
|
w.say(f"badge present after {i} rescan round(s)")
|
|
break
|
|
w.ctl("POST", "/api/stacks/rescan")
|
|
time.sleep(5)
|
|
w.say("badges: " + json.dumps(b, ensure_ascii=False))
|
|
logs = w.guest("docker logs --since 10m felhom-controller 2>&1 | grep -iE 'navidrome' | grep -iE 'probe|yaml|felhom.yml|error|WARN' | tail -15")
|
|
w.say("controller log lines for navidrome:\n" + logs)
|
|
errs = w.guest("docker logs --since 10m felhom-controller 2>&1 | grep -iE 'yaml: |unmarshal|cannot parse' | tail -5")
|
|
w.say("yaml/unmarshal errors in the controller log (want none): " + (errs.strip() or "(none)"))
|
|
w.remove("navidrome")
|
|
out = {"controller": tag, "drill_commit": want, "ladder_on_box": has.strip(), "deploy_fields_http": c,
|
|
"display_name": meta.get("display_name"), "deployed": ok, "state": st.get("state"),
|
|
"badges": b, "probe_lines": probe[-6:],
|
|
"yaml_errors": errs.strip()}
|
|
json.dump(out, open(f"B1-spike-{tag}.json", "w"), indent=2, ensure_ascii=False)
|
|
open(f"B1-spike-{tag}.log", "w").write("\n".join(w.LOG) + "\n")
|