hub v0.105.0: the third name, a machine told to be quiet, and a guard for the hub's own words
gates / gates (push) Successful in 17s

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).
This commit is contained in:
2026-08-13 15:50:32 +02:00
parent 955a4f07b7
commit b03a105375
14 changed files with 995 additions and 16 deletions
+7 -2
View File
@@ -621,5 +621,10 @@ class (an image `VOLUME` at an unmounted path) is still live — `immich-server`
| **R-318** | **No honest marker exists that says Felhom installed dnsmasq on a machine already in the field, and none can be invented.** Established from source and on the box: the Felhom `/etc/dnsmasq.d/felhom-*.conf` snippets are deleted by the uninstall's own loop (`:1162`) BEFORE the ownership decision and do not survive it; the install state file that carries the record is deleted at `:1268`; nothing under `/etc/felhom*` remains. `/var/log/dpkg.log` does record the install — and is a **timestamp**, which the standing rule refuses as a heuristic dressed as a fact. **So for every box installed before v1.27.0 the answer is the preflight message, and that is a mechanism rather than a rule:** it names the finding, keeps its two routes and its promise not to touch DNS on a host we do not own, and adds *"THIS LOOKS LIKE OURS … systemctl disable --now dnsmasq"*. **Judged as a customer would:** it is honest, it hedges correctly (*looks like*), and it names one exact command — the one thing that gets that person moving. Its weakness is that it asks them to answer *"did this host have dnsmasq before Felhom?"*, which is precisely the question we can no longer answer for them | **CLOSED — established, no action possible for existing boxes** | R-300, R-316 | — | CC |
| **R-319** | **The guest-network watchdog finally has a reader — the first of R-264's twenty-one, and it is the repair COUNT that matters, not the state.** The agent has reported `guest_net` on every heartbeat since **v0.92.0** (R-54, 2026-07-21) and the string `guest_net` occurred **nowhere** in `felhom.eu/hub/` — stored as raw text inside `report_json`, read by nothing. **Established before anything was built:** the facts DO arrive and ARE persisted — `demo-felhom-8363b5`'s newest row carries `guest_net.checked_at` plus per-guest `vmid/state/mode/ip/has_route/dhclient_alive/checked_at/message`, and the agent's wire type (`felhom-agent/internal/hub/report.go:139-160`) additionally carries `healed`, `heal_succeeded`, `last_heal_at`, `heals_last_hour`, `damped`, absent from the live rows only because they are `omitempty` on a box that has never needed a repair. **So this was hub-only: no wire change, no agent change, no controller change, nothing to bake.** **What was built** (`hub/internal/web/hosts.go` `parseGuestNet`/`guestNet` + the host-detail *Guest network* card): the hub MODELS the stanza instead of storing it as text, renders it where a person looks at a machine, and **surfaces `heals_last_hour` beside the state rather than behind it** — because a guest the watchdog keeps repairing is healthy at every instant anyone looks and is nevertheless failing, which is the exact shape of the failed-disk-drawn-as-a-healthy-empty-disk defect. `heal_succeeded` is decoded too, and deliberately: **R-260 is this project's warning that a decoder short of three fields dropped the one that decided the question**, and six FAILED repairs is a guest that is down while six successful ones is a nuisance. **An unknown is never drawn as healthy**, following the August companion-flag convention — three absences kept apart with three different sentences (agent older than 0.92.0; a capable agent that sent nothing; a guest whose own `state` the watchdog did not assert), and a malformed stanza degrades to unknown without a 500. **ALARM JUDGEMENT: no email, deliberately.** The incident behind this (`INCIDENT-guest-dhclient-killed-2026-07-20.md`, a killed `dhclient` that took a tunnel down for 1 h 15 m) was about nobody being able to SEE the condition, not about nobody being paged; and a new alarm on a fleet of two demo machines is untested noise on a dispatcher whose severity contract is exact-match. **Revisit when a third machine exists or when a repair count is seen climbing on real hardware** — the visible count is what will supply that evidence. **Red-proofs, mutations asserted applied by grep before each run:** (1) the unknown branches replaced by the healthy badge → **both** C sub-cases go red, a silent machine seen rendering as healthy; (2) `RepairCount: 0` in the decoder → B goes red on *"a guest repaired 6 times in an hour is reported as fine"*; (3) `Degraded()` forced true → A goes red on *"a machine that is fine is being alarmed on"*, proving the guard is reachable in both directions. **Positive control that the wiring is real, not just written: the wire-contract gate's checked-tag count rose 182 → 190 and its skipped count fell 88 → 80** as the eight `guest_net` allowlist entries were REMOVED — an allowlisted tag is skipped, so leaving them would have meant the new fields were never checked at all | **CLOSED — shipped hub-side 2026-08-13** | R-54, R-260, R-264 | — | CC |
| **R-320** | **Evidence has been destroyed twice in three days, in the same place, by the same act.** 2026-08-12, the retained-key drill: the Phase A logs lived on `drill-r50`'s disk and were destroyed by the revert to `virgin` between Phase A and Phase B (`audits/DRILL-retained-key-2026-08-12.md` §11.5). 2026-08-13, R-316: the Part 1 logs, same disk, same revert, between Part 1 and Part 2 (`audits/REPORT-r316-installer-v1.28.0-2026-08-13.md` §9 — *"the same mistake as Tuesday, in the same place"*). **That report was copied into `audits/` by this session on purpose:** it lived in `REPORT.md`, which every session overwrites — so writing tonights report would have destroyed the record of a destroyed record. **Both times the conclusions survived on luck** — the quotations had been read live, and an independent reproduction happened to exist. **Both times the golden-bake runbook's existing "scp the log OUT first" was applied to the FINAL teardown and not the intermediate one**, which is the whole finding: the middle revert is the one that gets forgotten. **The rule, now standing rule 5 in `workspace-CLAUDE.md` (so it loads in every session) and repeated where a session actually meets it — `runbooks/target-selection.md`, `RUNBOOK-rehearsal-v3.md`, and the `PROMPT-TEMPLATE.md` report section: evidence is copied off the machine at the end of the phase that produced it, before any revert, snapshot restore or teardown — not at the end of the session.** **A rule without a mechanism is a wish, so the mechanism is named: the pull is the LAST ACT OF THE PHASE**, not a step to remember later. **And the already-gone case is documented rather than improvised: say so plainly in the report and reproduce the finding independently** — which is what both sessions did, and it should be the expectation rather than a good instinct under pressure | **CLOSED — rule written, four homes** | — | — | CC |
| **R-321** | **A box on which reporting is deliberately switched off still alarms as stale, then down.** Found while deciding `reporting_disabled` on its own merits (R-264). **The product supports the state:** with hub reporting off the controller sends ONE minimal report carrying `reporting_disabled: true` and `health.status: "disabled"` (`felhom-controller/controller/cmd/controller/main.go:1246-1260`) and then goes quiet by design. **The state IS visible**`health_status` is decoded and stored, and `hub/internal/web/rollup.go:25` renders that customer as `disabled`, which is why the `reporting_disabled` FLAG itself is reclassified *redundant* rather than owed a reader: it is a second spelling of a fact already read. **But the alarm does not consult it.** `StalenessChecker.Check` (`hub/internal/monitor/staleness.go:88+`) computes its verdict from report AGE alone; the only skip is `IsCustomerBlocked`. So a deliberately-silent box goes `node_stale` at 30 minutes and `node_down` at 60, and the operator is paged about a machine that is fine — **the classic false alarm that teaches people to ignore the channel**, and a sibling of R-195, where the guard that should have covered a customer was keyed off the wrong fact. **NOT FIXED HERE, deliberately: adding a decoder for the flag would have felt like progress and left the alarm firing.** The fix belongs in the checker, which already holds the health status it needs. **Bounded honestly: no machine is in this state today** (all three known hosts report normally), so this is a latent defect found by reading, not an observed outage | **READY (S) — NEW 2026-08-13, RANK 3** | R-195, R-264 | Skip (or downgrade) the staleness verdict for a customer whose last report declared `health.status = "disabled"`, and **log the deferral with its own counter** — the v0.73.0 precedent: a quiet check must not look like a check that did not run. Fail OPEN on an unreadable status: an unreadable state must never SUPPRESS a real alarm | CC |
| **R-322** | **The claim guard has never scanned the hub, and the hub sends the customer's first sentence.** `retrieval_promise_gate.py` lives in `felhom-controller/controller/scripts/` and its declared surfaces are that repo's `internal/web/templates` plus ONE Go handler file — extended to Go strings only on 2026-08-12 (R-311), on the ground that *"the highest-stakes customer copy in the product… none of it had ever been scanned"*. **The same sentence is true one repo over.** The hub composes and sends every customer-facing e-mail (`internal/notify/templates.go`) and renders the self-bind pages, i.e. the copy a customer reads BEFORE they ever see a box screen, and no gate in either repo looks at it. **Scanned by hand while shipping R-295's hub half: `felhom.eu/hub/` returns ZERO occurrences of all four stems** (`visszaállíthat`, `visszaszerezhet`, `visszahozhat`, `visszanyit`) across every non-test `.go` and `.html` under `internal/`. **So nothing was hiding, and this is a SCOPE gap rather than a live defect** — which is exactly the moment to record it, before the first hub-side retrieval promise is written by someone who assumes the guard has them covered. **Recommended shape, and the reason it is not one line:** the gate is invoked by `controller_gates.py`, so pointing it at a sibling repo makes a controller gate fail on a felhom.eu edit — the cross-repo lesson from G-1 (a gate needing a sibling passes locally and exits INCONCLUSIVE in CI, and must never SKIP when the sibling is absent). The cheaper honest option is a hub-side sibling registered in `repo_gates.py` that shares the stem list, with ONE list rather than two drifting copies | **READY (S) — NEW 2026-08-13, RANK 3** | R-294, R-299, R-302, R-311 | Scan the hub's customer-facing surfaces with the same stems, from `repo_gates.py`. **Share the stem list — two copies of a word list is how the plural got past the singular (R-299).** Do NOT make a controller gate depend on a felhom.eu clone | CC |
| **R-321** | **A box on which reporting is deliberately switched off still alarms as stale, then down.** Found while deciding `reporting_disabled` on its own merits (R-264). **The product supports the state:** with hub reporting off the controller sends ONE minimal report carrying `reporting_disabled: true` and `health.status: "disabled"` (`felhom-controller/controller/cmd/controller/main.go:1246-1260`) and then goes quiet by design. **The state IS visible**`health_status` is decoded and stored, and `hub/internal/web/rollup.go:25` renders that customer as `disabled`, which is why the `reporting_disabled` FLAG itself is reclassified *redundant* rather than owed a reader: it is a second spelling of a fact already read. **But the alarm does not consult it.** `StalenessChecker.Check` (`hub/internal/monitor/staleness.go:88+`) computes its verdict from report AGE alone; the only skip is `IsCustomerBlocked`. So a deliberately-silent box goes `node_stale` at 30 minutes and `node_down` at 60, and the operator is paged about a machine that is fine — **the classic false alarm that teaches people to ignore the channel**, and a sibling of R-195, where the guard that should have covered a customer was keyed off the wrong fact. **NOT FIXED HERE, deliberately: adding a decoder for the flag would have felt like progress and left the alarm firing.** The fix belongs in the checker, which already holds the health status it needs. **Bounded honestly: no machine is in this state today** (all three known hosts report normally), so this is a latent defect found by reading, not an observed outage. **FIXED 2026-08-13, hub v0.105.0 — and it turned out to be TWO doors, not one.** **(1) `StalenessChecker.Check`** skips the age transition for a customer whose last report declared `health.status = "disabled"`. The discriminator is the box's OWN last word, not an inference — which is what makes this a suppression rather than a guess, and the §5 halt condition (*"suppressing an alarm on a guess is worse than the false alarm it removes"*) therefore did not fire. **The state is RECORDED (`StateDisabled`), not deleted** — and that choice is load-bearing rather than cosmetic. The `blocked` precedent deletes, but a deleted state returns `""` from `GetState`, and `""` is not `"down"`, so **(2) `CheckBackupDeadlines` would have gone on e-mailing `expected_backup_missed` every morning about the same machine.** That is R-195's shape returning through a second door, which is why both are closed together. Recording it also satisfies the visibility requirement: quiet-on-purpose and quiet-by-accident no longer look identical. `downtimeStart` is cleared **on entry**, so a later genuine outage cannot compute its duration from a clock that started before we asked for the silence — the `blocked` branch does not do this, which is filed as an observation rather than changed under this row. **THE RE-ENABLEMENT CLOCK, stated because it was a judgement:** it runs from the report the hub can actually see, so for a box that reports on re-enabling the clock starts at re-enablement. Timing from the last report BEFORE the switch-off would fire an instant stale/down for a quiet period we requested — a false alarm produced by fixing false alarms. Leaving `disabled` re-enters the same branch as a NEW customer: a first observation, never a `node_recovered` for an outage that did not happen. **LIMIT, stated rather than hidden:** if reporting is re-enabled and the box then fails to report at all, the hub still sees only that final `disabled` report and keeps suppressing. The hub cannot distinguish that from *still switched off* — its view changes only when a report arrives. This is precisely why the state is made visible: an operator who re-enabled a box and still sees `disabled` is being told it has not come back. **Four scenarios and three red-proofs, every mutation asserted applied by grep before its run.** The one that matters: making the suppression unconditional was seen leaving a genuinely dead machine at `"disabled"` instead of `"down"`**a real alarm demonstrably cannot be swallowed unnoticed.** Removing the suppression reproduced today's behaviour, `node_down` and all. Making the state STICKY (remembered instead of re-read from the box) produced the permanent silence — a once-disabled machine never alarming again. **A weakness in the tests themselves was found by a red-proof and fixed:** scenario A originally seeded the customer already-disabled, so the checker's new-customer branch swallowed the first observation and the test passed on its state assertion alone even with the suppression deleted. It now observes the machine HEALTHY first, and the same red-proof then fails on the EVENT — `emitted [node_down]`, the actual false alarm, reproduced | **CLOSED — shipped hub v0.105.0, both doors** | R-195, R-264 | — | CC |
| **R-322** | **The claim guard has never scanned the hub, and the hub sends the customer's first sentence.** `retrieval_promise_gate.py` lives in `felhom-controller/controller/scripts/` and its declared surfaces are that repo's `internal/web/templates` plus ONE Go handler file — extended to Go strings only on 2026-08-12 (R-311), on the ground that *"the highest-stakes customer copy in the product… none of it had ever been scanned"*. **The same sentence is true one repo over.** The hub composes and sends every customer-facing e-mail (`internal/notify/templates.go`) and renders the self-bind pages, i.e. the copy a customer reads BEFORE they ever see a box screen, and no gate in either repo looks at it. **Scanned by hand while shipping R-295's hub half: `felhom.eu/hub/` returns ZERO occurrences of all four stems** (`visszaállíthat`, `visszaszerezhet`, `visszahozhat`, `visszanyit`) across every non-test `.go` and `.html` under `internal/`. **So nothing was hiding, and this is a SCOPE gap rather than a live defect** — which is exactly the moment to record it, before the first hub-side retrieval promise is written by someone who assumes the guard has them covered. **Recommended shape, and the reason it is not one line:** the gate is invoked by `controller_gates.py`, so pointing it at a sibling repo makes a controller gate fail on a felhom.eu edit — the cross-repo lesson from G-1 (a gate needing a sibling passes locally and exits INCONCLUSIVE in CI, and must never SKIP when the sibling is absent). The cheaper honest option is a hub-side sibling registered in `repo_gates.py` that shares the stem list, with ONE list rather than two drifting copies | **CLOSED 2026-08-13 by R-324**`scripts/hub_copy_gate.py`, registered in `repo_gates.py`, scanning 95 hub files for retired names and four declared customer surfaces for retrieval stems, with a plant→convict→remove→pass selftest that caught a defect in its own instrument on the first run. The stem list IS shared (`scripts/customer_copy_vocab.py`) and no controller gate was made to depend on a felhom.eu clone; the controller gate's adoption of the shared list is R-325, and until it happens the two are drift-checked rather than left to diverge | R-294, R-299, R-302, R-311, R-324 | — | CC |
| **R-323** | **The third near-homograph — the five-word phrase is „Tulajdonosi jelmondat” now.** Found and deliberately LEFT ALONE while shipping R-295's hub half (it was reported as an observation rather than swept in, which was right — it is a different secret and a different decision), then **RULED by the operator 2026-08-13: rename it on the same reasoning.** **Enumeration first, at `file:line`, and it is small: FIVE customer-facing sites, all in the hub**`web/selfbind.go:255` (lead), `:256` (failure banner), `:261` (field label), `:263` (hint), and `notify/templates.go:331` (the self-bind mail's item 2). **NOTHING in `felhom-controller` or `felhom-agent`** — the only hits there are comments and a test asserting the ALREADY-retired „Visszaállító **kód**” is absent, so the §5 halt did not fire and no bake was needed. Operator-facing surfaces call it *"Retrieval Password"* in English and the installer uses `FELHOM_RETRIEVAL_PASSPHRASE` as an identifier; neither is customer copy and neither was touched. **THE NAME, argued against the three-secret table rather than chosen by habit.** The phrase proves the account owns the box being bound — **it restores nothing, so the old name was simply false.** Both suggested names were rejected with reasons: **„Fiókjelszó” is worse than the trap it fixes**, because there IS an account password (the dashboard login), so it would collide with a *different* real secret; and **„Összekötési jelszó” recreates the trap structurally**, because the OTHER factor on the very same page and in the same mail is the **„Párosító kód”** — naming this one after the same act would leave the two factors a customer types in one sitting separated only by kód-versus-jelszó, which is exactly the „Visszaállító kód”/„Visszaállító jelszó” shape being removed. **„Tulajdonosi jelmondat” is distinct on BOTH axes** — stem (Tulajdonosi vs Beállító / Helyreállítási / Párosító) and noun (jelmondat vs kód / jelszó) — and it says what the phrase does. *If a plainer noun is ever wanted, „Tulajdonosi jelszó” is a one-word change; the stem is what carries the separation.* **Naming only:** the form field is still `name="passphrase"`, no acceptance logic moved, and `TestSelfBindPassphrase_StillAcceptedAfterTheRename` drives the real handler with the same messy human spacing and asserts the appliance still binds. **NO CUSTOMER-FACING DOCUMENT NAMES THE OLD PHRASE** — the tester agreement does not mention it at all and the runbooks call it by its English operator name, so **nothing printed is stranded**; the phrase reaches a customer out-of-band from the operator, which means the only stale copy is whatever was said in a message or on the telephone | **CLOSED — shipped hub v0.105.0** | R-295, R-324 | — | CC |
| **R-324** | **The hub's customer copy is under a guard for the first time — and the guard has been watched catching, ignoring and releasing.** Closes the scope gap filed as R-322. `retrieval_promise_gate.py` lives in `felhom-controller` and scans that repo only; it was extended to Go strings on 2026-08-12 on the express ground that the recovery screen's copy *"had never been scanned"* — and the identical sentence was true one repo over the whole time, for the surface a customer reads FIRST. **`scripts/hub_copy_gate.py`, registered in `repo_gates.py`, two checks with a deliberate difference.** **(1) RETIRED NAMES are banned outright, across the WHOLE hub** (95 files scanned), with no allowlist: a name a different secret now owns is never correct anywhere. Comments are stripped — prose explaining a rename is not the rename returning, and the register rows quote the retired names by necessity. **(2) RETRIEVAL STEMS are registered, not banned**, in four declared customer surfaces (`notify/templates.go`, `web/selfbind.go`, `api/handler.go`, `notify/dispatcher.go`), a missing declared surface being a FAILURE rather than a skip. The allowlist is **empty, and that is a measurement**: the hub makes no retrieval promise today. **POSITIVE CONTROL, because a guard never seen catching anything proves nothing**`--selftest` runs plant → convict → remove → pass, and it **found a defect in its own instrument on the first run**: the synthetic source was named `<selftest>`, comment-stripping keys off the `.go` extension, and step 3's control convicted a comment. The bug was in the guard, and the control is what found it. **Vocabulary is NOT duplicated:** both lists live in `scripts/customer_copy_vocab.py`, the same shared-gate home `reuse_refs_check.py` and `instructions_gate.py` already use from both repos | **CLOSED — shipped, selftest green** | R-295, R-299, R-311, R-322, R-323, R-325 | — | CC |
| **R-325** | **The shared copy vocabulary is imported by ONE of its two consumers, and drift-checked into the other.** `customer_copy_vocab.py` is the single list; `hub_copy_gate.py` imports it. **`felhom-controller/controller/scripts/retrieval_promise_gate.py` still carries its own `STEMS` literal**, because the session that created the shared module was under a hard end-state requirement to leave `felhom-controller` untouched — its target box was being re-deployed the same evening. **Two copies of a word list is not a theoretical risk in this project: it is the R-299 defect exactly**, where a guard asserted one inflection of a Hungarian verb and the plural walked past it. **So the gap is instrumented rather than left open: `hub_copy_gate.py` READS the controller gate's `STEMS` and FAILS if the two disagree** — single-source semantics tonight without a cross-repo edit. **Watched failing:** removing one stem from the shared list produced *"the shared vocabulary is no longer shared"* with both lists printed, and restoring it returned the gate to green. An ABSENT sibling clone is **INCONCLUSIVE (exit 2), never a pass** — the G-1 lesson. **This is a scaffold, not the destination** | **READY (S) — NEW 2026-08-13, RANK 3** | R-299, R-324 | Make `retrieval_promise_gate.py` import `felhom.eu/scripts/customer_copy_vocab.py` and delete its own literal — a felhom-controller change of a few lines, needing no bake (a gate is not shipped code). Then the drift check becomes redundant and should be removed with it, rather than left as a second mechanism nobody re-reads | CC |
| **R-326** | **"Which claims are unproven?" is a question a machine can answer now — and the number everyone was repeating answered a different question.** On 2026-08-13 a session was asked to report on *"the nine grey claims"*, could not determine which nine, and **declined to guess. It was right, and the refusal is the finding.** **WHERE NINE CAME FROM, established rather than assumed: it is real, and it is the count of claims carrying `verdict: downgraded`** — the ones the 2026-08-09 verification pass LOWERED. That is not "unproven"; it is "re-judged". **THE REAL NUMBERS, measured from `where-felhom-stands.yaml`: 55 claims — `walked` 23, `partial` 14, `built` 14, `missing` 4. NOT WALKED: 32 of 55.** And the evidence half, which is the sharper cut: **all 23 walked claims cite an evidence document** (`check_stands.py` convicts a `walked` claim without one), while of the 32 that are not walked **only 6 cite evidence and 26 are prose only**. **`scripts/unproven.py`** prints every not-walked claim with its status, band, verdict and whether it cites evidence; `--summary` prints the counts alone. It reads the dataset ONLY — it opens no evidence, judges nothing and contacts no machine, because a status is the capability map's business and the map moves first. **Wired into the end-of-session checklist** in `CLAUDE.md`, so a status that moves is noticed. **ITS FIRST RUN FOUND A STALE CLAIM:** `claim.code-naming` is still `partial` and its title still describes the defect R-295 and R-323 have now closed — see R-327. **NOT DONE, and deliberately: the capability map is not restructured.** Its illegibility is real and filed with two measured costs, but it is surgery on this project's memory and wants daylight and a session of its own — recorded here so it does not read as forgotten | **CLOSED — shipped** | R-327 | — | CC |
| **R-327** | **The standing picture still describes a defect that has been fixed twice over.** Found by the first run of `unproven.py` (R-326), which is the argument for having built it. `where-felhom-stands.yaml`'s `claim.code-naming` is `status: partial` and its title reads *"The same word is used for two different secrets across three surfaces; the email points at a page a rebuilt machine does not show"***both halves of which are now false.** The box side shipped 2026-08-10 (R-295), the hub half and the page-naming fix on 2026-08-13 (R-295 hub, new `reenroll` mail kind), and the third near-homograph on 2026-08-13 (R-323). **NOT MOVED BY THIS SESSION, deliberately and by the dataset's own rule:** *"A status may not be RAISED here — if the evidence supports a stronger status than the capability map records, the MAP changes first and this file follows it."* Raising it here would be the exact inversion the file's header forbids, and the map edit is a separate judgement about what "walked" means for a naming change that no customer has yet met | **READY (S) — NEW 2026-08-13, RANK 4** | R-295, R-323, R-326 | Decide the capability-map status for the naming arc, then let the dataset follow it. **Note the honest difficulty: no customer has typed „Tulajdonosi jelmondat” yet**, so `walked` would be an over-claim; `built` is probably right, and the title needs rewriting either way because it describes a defect rather than a capability | operator + CC |