Files
felhom.eu/scripts/unproven.py
T
admin b03a105375
gates / gates (push) Successful in 17s
hub v0.105.0: the third name, a machine told to be quiet, and a guard for the hub's own words
Hub only. No controller change, no agent change, no wire change — nothing to bake.
demo-hp untouched: the operator is re-deploying it this evening.

R-323 — the five-word phrase is „Tulajdonosi jelmondat". It was „Visszaállító
jelszó": one word from the name retired last week, and false besides — it restores
nothing, it proves the account owns the box being bound. Five sites, all in the hub;
felhom-controller and felhom-agent carry the name nowhere, so no halt and no bake.
Both suggested names were rejected with reasons: „Fiókjelszó" would collide with the
dashboard login (a DIFFERENT real secret), and „Összekötési jelszó" would leave the
two factors on this page separated only by kód-versus-jelszó — the exact shape being
removed, since the other factor is the „Párosító kód". The chosen name differs on
both axes, stem and noun. Naming only; the acceptance pin drives the real handler.

R-324 — the hub's customer copy is under a guard for the first time. Retired names
banned across all 95 hub files; retrieval stems registered in four declared customer
surfaces. The selftest found a defect in its own instrument on the first run. One
shared vocabulary in scripts/, drift-checked into the controller gate rather than
copied (R-325 removes the scaffold).

R-321 — a machine we told to be quiet is no longer reported as dead, and it was two
doors, not one: because the state is RECORDED rather than deleted, the morning
deadline check can skip it too. A deleted state returns "", which is not "down" —
R-195's shape returning through a second door. The clock runs from the report the hub
can see, so re-enabling starts it there and emits no recovery for an outage that never
happened. Three red-proofs; the one that matters showed a genuinely dead machine
sitting at "disabled" when the suppression was made unconditional.

R-326 — "which claims are unproven" is answerable by a command now. The nine I have
been repeating was the count of claims the 9 August pass DOWNGRADED, not the count of
unproven ones. The real figures: 55 claims, 23 walked, 32 not — and only 6 of those 32
cite evidence. Its first run found a stale claim (R-327).
2026-08-13 15:50:32 +02:00

102 lines
4.1 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""unproven.py — "which claims are not proven?", as a question a machine can answer (R-326).
WHY THIS EXISTS. The operator asked on 2026-08-04 to see what is built and what is still unproven.
The picture was built (`where-felhom-stands.yaml` → `.html`) and it is good — but the QUESTION could
only be answered by a person reading it. On 2026-08-13 a session was asked for "the nine grey claims",
could not determine which nine, and declined to guess. It was right to decline, and the refusal is
the finding this closes.
WHERE "NINE" CAME FROM, since a wrong number that matches nothing is worse than no number. It is
real, and it answers a DIFFERENT question: nine claims carry `verdict: downgraded` — the count the
2026-08-09 verification pass LOWERED. The count of claims that are not walked is 32. Both are true;
only one of them is "what is unproven".
This reads the dataset only. It makes no judgement, opens no evidence and contacts no machine — a
claim's status is the capability map's business (the map changes first; the dataset follows it), and
`check_stands.py` is the gate that keeps the citations honest. This just answers the question.
Run: python3 scripts/unproven.py # every claim that is not walked
python3 scripts/unproven.py --summary # the counts only
"""
import io
import os
import re
import sys
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DATA = os.path.join(ROOT, "documentation", "architecture", "where-felhom-stands.yaml")
# The status that means "done end to end on real hardware, with evidence on file". Everything else is
# a degree of not-that, which is the whole point of the question.
PROVEN = "walked"
# Widest first, so the output reads as a ladder down from nearly-there to not-started.
ORDER = ["partial", "built", "missing"]
def field(entry, name):
m = re.search(r"^\s*%s:\s*\"?(.*?)\"?\s*$" % name, entry, re.M)
return m.group(1) if m else ""
def load():
if not os.path.exists(DATA):
sys.exit("unproven: the dataset is missing: %s" % DATA)
text = io.open(DATA, encoding="utf-8").read()
parts = re.split(r"\n - id: ", text)
header, entries = parts[0], parts[1:]
if not entries:
sys.exit("unproven: no claims parsed from %s — the file's shape changed" % DATA)
claims = []
for e in entries:
claims.append({
"id": e.split("\n", 1)[0].strip(),
"status": field(e, "status") or "(none)",
"title": field(e, "title"),
"band": field(e, "band"),
"verdict": field(e, "verdict"),
"evidence": "evidence:" in e,
})
return field(header, "verified_on"), claims
def main():
verified_on, claims = load()
not_walked = [c for c in claims if c["status"] != PROVEN]
counts = {}
for c in claims:
counts[c["status"]] = counts.get(c["status"], 0) + 1
print("where felhom stands — %d claims, verified_on %s" % (len(claims), verified_on))
print(" %-8s %d" % (PROVEN, counts.get(PROVEN, 0)))
for s in ORDER:
n = counts.get(s, 0)
with_ev = sum(1 for c in claims if c["status"] == s and c["evidence"])
print(" %-8s %d (%d cite evidence, %d prose only)" % (s, n, with_ev, n - with_ev))
for s in sorted(k for k in counts if k not in ORDER + [PROVEN]):
print(" %-8s %d ⚠ status not known to this script" % (s, counts[s]))
print(" NOT WALKED: %d of %d" % (len(not_walked), len(claims)))
if "--summary" in sys.argv:
return 0
print()
for s in ORDER + sorted(k for k in counts if k not in ORDER + [PROVEN]):
rows = [c for c in not_walked if c["status"] == s]
if not rows:
continue
print("%s (%d)" % (s.upper(), len(rows)))
for c in sorted(rows, key=lambda c: c["id"]):
ev = "evidence" if c["evidence"] else "PROSE ONLY"
vd = (" [%s]" % c["verdict"]) if c["verdict"] else ""
print(" %-40s %-10s %s%s" % (c["id"], c["band"], ev, vd))
print(" %s" % c["title"][:110])
print()
return 0
if __name__ == "__main__":
sys.exit(main())