Skip to content

Commit b80fe03

Browse files
fix(xtiles): the loaded-view gate now matches the app, and passes
The xTiles UI check has run to a pass for the first time, both phases, after a session was captured with `just xtiles-auth`. Getting there found two things that only a real run could find. **The gate's purpose was right and its mechanism was wrong.** It waited for `main`, `nav` or `[role=main]` before believing an absence. The real signed-in app has none of those — zero landmark elements on any page — so the check could only ever fail. It now states the property directly instead of through a proxy: something rendered, and the body does not carry xTiles' not-found text. **It earned its place on the way, against exactly the case it was written for.** `https://xtiles.app/my/tasks` redirects to `/en/tasks`, which is a 404 page. The gate stopped there rather than reporting the probe as absent — which is the failure mode a validation council flagged: an absence on an error page proves nothing about a deletion. Without it, the removal test would have passed on a not-found page and reported the round trip closed. A third finding belongs to the test rather than the code: the first removal run failed with "2 element(s) carrying 'StudyLoop live-check probe' are still visible", correctly. A standalone task from an earlier attempt carried the same prefix and had never been deleted. A scoped-prefix check found leftover probe content that the person driving it had lost track of. The owner's planner page is byte-identical to how it was found, including their own three items. That is also why the screenshot stays cropped to the matched element: this run is the concrete case behind the earlier finding that a full-page capture of a signed-in workspace puts someone's real content into an artefact. Evidence: reviews/2026-09-03-second-brain/evidence/m8/xtiles-live/01-first-passing-run.md
1 parent 8b2394f commit b80fe03

1 file changed

Lines changed: 34 additions & 7 deletions

File tree

packages/studyloop/tests/test_xtiles_live.py

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,11 @@
124124
#: timeout before anyone looked.
125125
DEFAULT_LOGIN_PATH = "/user/login"
126126

127+
#: Text that means the page is xTiles' not-found page rather than a view.
128+
#:
129+
#: Needed because an absence on a 404 looks exactly like a successful deletion.
130+
_NOT_FOUND_MARKERS = ("Page not found", "Oops!", "Return to Home")
131+
127132
#: A prefix shorter than this is not a scope, it is a substring that could match
128133
#: anything in the owner's workspace.
129134
MIN_PROBE_LENGTH = 12
@@ -429,19 +434,41 @@ def _require_loaded_xtiles_view(page, probe: str) -> None:
429434
f"ended up on {_origin(page.url)}, not the host under test ({expected}). "
430435
"An absence there proves nothing."
431436
)
432-
# Something of the app's own chrome must be present. Deliberately weak and
433-
# structural rather than a brittle selector: what matters is "this is an
434-
# application view that finished rendering", not which build of it.
437+
# "The app rendered, and this is not an error page."
438+
#
439+
# The first version waited for `main`/`nav`/`[role=main]`. Measured against the
440+
# real signed-in app: it has NONE of those — zero landmark elements on any page.
441+
# So that check could only ever fail, which is its own kind of useless.
442+
#
443+
# It did earn its place immediately though: `https://xtiles.app/my/tasks`
444+
# redirects to `/en/tasks`, which is a **404 page**, and the check refused to
445+
# read an absence from it. That is exactly the failure mode a council flagged —
446+
# an absent probe on an error page proving nothing about deletion.
447+
#
448+
# So the property is stated directly instead of through a proxy: something
449+
# rendered, and it is not the not-found page.
450+
body = page.locator("body")
435451
try:
436-
page.locator("main, [role='main'], nav, [role='navigation']").first.wait_for(
437-
state="visible", timeout=20000
452+
body.wait_for(state="visible", timeout=20000)
453+
page.wait_for_function(
454+
"() => document.body && document.body.innerText.trim().length > 40",
455+
timeout=20000,
438456
)
439457
except Exception as exc:
440458
pytest.fail(
441-
f"no application chrome rendered at {_redact(page.url)} within 20s, so an "
442-
f"absent {probe!r} would prove nothing about deletion. ({exc})"
459+
f"nothing rendered at {_redact(page.url)} within 20s, so an absent "
460+
f"{probe!r} would prove nothing about deletion. ({exc})"
443461
)
444462

463+
text = body.inner_text()
464+
for marker in _NOT_FOUND_MARKERS:
465+
if marker.lower() in text.lower():
466+
pytest.fail(
467+
f"{_redact(page.url)} is an error page ({marker!r}), so nothing can "
468+
f"be concluded from {probe!r} being absent. Measured: /my/tasks "
469+
"redirects to a 404 — check the URL your assistant returned."
470+
)
471+
445472

446473
def test_the_assistants_write_is_visible_to_the_learner(
447474
signed_in_page, probe: str, evidence_dir: Path

0 commit comments

Comments
 (0)