95c10954ae
gates / gates (push) Successful in 23s
10-localisation.md §10.3: the saved notes follow the box language at write time, with the one-night consequence stated rather than hidden; the globe, and the table of WHO reads which page and where its globe posts — getting that wrong makes the button do nothing, which it did on /recovery until the live probe found it. Decision 6 superseded a second time; decision 8 (a claim carries the visitor's language) recorded. Decision 5 of §11's anonymous-surface line: changing what a VISITOR reads is within what an anonymous request may do; changing anything the household owns is not, and POST /lang can do only the first. R-578 — the deadlock, and why it is a row rather than a fixed bug: UpdateOffboxStatus holds the settings write lock while running its callback, boxLang() wants the read lock, sync.RWMutex is not reentrant. On a real box an off-site run would have hung FOREVER holding that lock. The symptom was a test suite going from 8 minutes to a 25-minute timeout. Fixed and guarded, but the guard covers one package and three helper names; the class needs a gate. R-577 — a guest share visitor still has no way to pick a language, and the household's setting is the wrong default for a stranger. Deliberately left, pinned by a test, and the operator's to decide because it is a promise the share feature makes. .claude/rules/live-probes.md, unconditional: never send a deploy request for an app that is not installed, not even expecting a refusal — the endpoint accepts first and validates later. Two sessions made that mistake in two days, the second WITH a prompt line forbidding it. A prompt is read once; a rule file is loaded every session. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
75 lines
4.2 KiB
Markdown
75 lines
4.2 KiB
Markdown
# Live validation — controller v0.254.0 on demo-hp guest 9201 (2026-09-18, release C)
|
|
|
|
**Method: endpoint-level, stated as such.** No browser on DooPlex. Nothing was installed, created,
|
|
formatted or deleted, and **the deploy endpoint was not touched at all** — the new rule
|
|
(`.claude/rules/live-probes.md`) written after yesterday's mistake. The password was passed as a file
|
|
and deleted from host and guest afterwards.
|
|
|
|
## 1. A visitor's language is their own (no session) — before and after
|
|
|
|
| probe | 0.253.0 | 0.254.0 |
|
|
|---|---|---|
|
|
| globe on `/login` | **0** | **1** |
|
|
| `POST /lang lang=en back=/login` | 302 (no such route → the login redirect) | **303, `felhom_lang=en` set** |
|
|
| `/login` with that cookie | `<html lang="hu">` | **`<html lang="en">`**, and "Forgot password" present |
|
|
| **`settings.json` `language` after it** | `"hu"` | **`"hu"` — unchanged.** An anonymous request cannot write what the household owns |
|
|
| `POST /lang lang=xx` | 302 | **400**, no cookie |
|
|
| `POST /lang back=//evil.example/x` | the login redirect | **`/`** — a protocol-relative URL is another origin |
|
|
| globe on `/claim` | 0 | **1** |
|
|
|
|
## 2. A signed-in household reads their own setting, never the cookie
|
|
|
|
`/launcher` with a session **and** the `felhom_lang=en` cookie → **`<html lang="hu">`**. The cookie is
|
|
not read once there is a session; that is the row that keeps a household from inheriting a language a
|
|
previous visitor picked in the same browser.
|
|
|
|
## 3. The dashboard globe, end to end
|
|
|
|
`POST /settings/language lang=en` (session CSRF) → 302 → `settings.json` `"language": "en"` →
|
|
`/launcher`, `/backups`, `/backups/remote` all `<html lang="en">` → switched back → `"hu"`.
|
|
|
|
The footer renders in order — version, globe, sign-out — and the old two-text-link switch is gone
|
|
(`lang-switch-btn` count 1 → **0**):
|
|
|
|
```
|
|
<div class="sidebar-footer">
|
|
<span class="version">0.254.0</span><details class="lang-globe">
|
|
<summary class="lang-globe-btn" aria-label="Nyelv" title="Nyelv"><svg class="ico" …globe…/></summary>
|
|
<ul class="lang-globe-menu">
|
|
<li><form method="POST" action="/settings/language">…<button … class="lang-globe-item current" aria-current="true">Magyar</button></form></li>
|
|
<li><form method="POST" action="/settings/language">…<button … class="lang-globe-item">English</button></form></li>
|
|
</ul>
|
|
</details>
|
|
<a href="/logout" class="logout-link">Kijelentkezés ↗</a>
|
|
```
|
|
|
|
## 4. The saved note, and the §16 consequence, seen live
|
|
|
|
With the box switched to English, the stored tier-2 note stayed as it was written:
|
|
`"last_warning": "A belső SSD-n csak a konfiguráció, adatbázis és a köte…"`. **That is the operator's
|
|
choice working, not a bug:** a saved note is written in the box's language at write time and shown
|
|
verbatim afterwards, so a household that switches sees the previous run's note in the old language
|
|
until the next run rewrites it.
|
|
|
|
## 5. What could NOT be proven live, and why
|
|
|
|
**The `/recovery` globe.** `recoveryPageHandler` redirects to `/backups/remote` unless
|
|
`recoveryOffer()` is true — the page exists only while a box is in a lost-machine situation, and
|
|
demo-hp is not. It 302s with or without a session. So its globe is proven by the render tests
|
|
(`TestGlobeOnAnonymousShells`, `TestI18nDirectRenderPagesFollowLanguage`) and by its 7 parity
|
|
fixtures, **not live**. Said plainly rather than left to be assumed from the other rows.
|
|
|
|
That page is also where release C's own defect was: it is an AUTHENTICATED route, so its globe must
|
|
write the household's SETTING; the first draft gave it the anonymous form, which sets a cookie
|
|
`langFor` ignores once there is a session — the button would have done nothing. Found by this probe
|
|
reporting no globe on `/recovery` and then reading the route table.
|
|
|
|
**The `<details>` menu opening in a browser.** `claude-in-chrome` is not available on DooPlex. The
|
|
markup is asserted; whether it looks and behaves right on screen is a manual click-through.
|
|
|
|
## 6. State left behind
|
|
|
|
Controller **0.254.0**; saved language **`hu`**; the visitor cookie was set only inside the probe's
|
|
own curl jar and is gone with it. 23 standing containers up, unchanged. Nothing installed, nothing
|
|
removed, no drive touched, no floor raised, no golden baked. **Provisioned nothing.**
|