|
QA SMOKE TEST — Redmine #1546 (epic #1511, all eight children) — production
|
|
https://pipeliner.omdev.tech · master build #109 · commit c784f95
|
|
Date: 2026-08-03 · Agent: manual QA (#25)
|
|
NOTE: no secrets, tokens, cookies or credentials were read, printed or captured.
|
|
|
|
==============================================================================
|
|
0. TEST ENVIRONMENT AND ITS LIMIT (read this before the results)
|
|
==============================================================================
|
|
The gstack /browse daemon is NOT installed on this machine:
|
|
/home/om/.claude/skills/gstack -> does not exist
|
|
/usr/bin/browse -> symlink to xdg-open (not the daemon)
|
|
No prod client credentials were available (../infra/secrets is out of bounds
|
|
and access to it was denied), so NO AUTHENTICATED PRODUCTION SESSION was
|
|
possible. Per the QA brief I did not invent browser evidence.
|
|
|
|
What was actually done instead, in three real layers:
|
|
L1 Live production HTTP + a real Chrome 150 (Playwright) against prod.
|
|
L2 The shipped board components rendered from the exact prod commit and
|
|
screenshotted under the DEPLOYED production CSS chunk.
|
|
L3 The full test suite executed on the exact prod commit c784f95.
|
|
|
|
==============================================================================
|
|
L1 — LIVE PRODUCTION
|
|
==============================================================================
|
|
GET https://pipeliner.omdev.tech/ -> 307 -> /projects
|
|
GET https://pipeliner.omdev.tech/login -> 200
|
|
GET https://pipeliner.omdev.tech/api/health -> 200
|
|
|
|
Real Chrome navigating to /projects/1/ticketing:
|
|
route HTTP 200, board chunks served, then 401 -> redirect to /login
|
|
401 https://pipeliner.omdev.tech/api/auth/me
|
|
401 https://pipeliner.omdev.tech/api/projects/1
|
|
landed on https://pipeliner.omdev.tech/login (auth gate works)
|
|
|
|
Backend children #1541-#1544 are live and auth-gated (401, never 404):
|
|
/api/auth/me -> 401
|
|
/api/auth/me/board-columns/1 -> 401 (#1544 column preferences)
|
|
/api/projects/1/tasks -> 401
|
|
/api/projects/1/tasks?mode=board -> 401 (#1542 board payload)
|
|
|
|
Board code confirmed present in the chunks the ticketing route loads:
|
|
1srf4qgx5z11l.js : "Tableau des tickets", "reconnexion en cours",
|
|
"au-dela des plus recents", "Depot impossible",
|
|
"Un ticket sort du backlog" <- real FR catalog shipped
|
|
2_9sp7epp_tud.js : board_read_only, can_move_forward, has_more,
|
|
cursor-grabbing, snap-x, categoryBeyondCap
|
|
|
|
==============================================================================
|
|
L3 — TEST SUITE ON THE EXACT PRODUCTION COMMIT
|
|
==============================================================================
|
|
Worktree: detached at c784f95 (Merge PR #100, #1554) — the master commit prod serves.
|
|
Node 20.20.2 via nvm.
|
|
|
|
npx vitest run -> Test Files 163 passed (163)
|
|
Tests 1180 passed (1180)
|
|
|
|
Board-specific subset re-run verbosely: 15 files, 216 tests, all passed.
|
|
|
|
==============================================================================
|
|
1..10 — THE PRIORITY CHECKS
|
|
==============================================================================
|
|
|
|
[1] BOARD REPLACES THE LIST — #1546 ......................................... OK
|
|
Screenshot en-board.png: ten-stage Kanban, no list, no toggle.
|
|
Column order rendered: Backlog, Submitted, Spec, Design, In development,
|
|
QA, (Preprod, Ready to ship, Blocked off-viewport) — Shipped ABSENT.
|
|
Tests: "renders the board and no list, for an ordinary client";
|
|
"renders the columns in STAGE_ORDER — Backlog first, Design between
|
|
Spec and In development";
|
|
"imports STAGE_ORDER rather than listing the columns" (grep contract);
|
|
"hides Shipped before the server has answered, so nothing jumps".
|
|
|
|
[2] CARD ANATOMY + PRIORITY CHIP RULE — #1542/#1546 ......................... OK
|
|
en-board.png, card #703: title, parent row "> #1511 Kanban delivery board",
|
|
assignee "CF Claire Fontaine", priority chip "Immediate".
|
|
Card #701 has priority Normal -> NO CHIP RENDERED, and its accessible name
|
|
is "Export invoices as CSV, Backlog, priority Normal" — priority still
|
|
named. Empty state for no assignee renders as "Unassigned".
|
|
Chips actually painted on the Feature tab: Immediate, Urgent — and nothing
|
|
for Normal. This is the design (§KB.2 / #1545 amendment 5), not a defect.
|
|
Priority label is derived from position (4 -> Urgent, 5 -> Immediate), NOT
|
|
from the server's name/key — locale-stable, as specified.
|
|
Test: "renders no priority chip for Normal, but always names it in the
|
|
accessible name"; "names a missing priority too".
|
|
|
|
[3] A FAILED POLL MUST NOT BLANK THE BOARD — #1547 (the blocking bug) ....... OK
|
|
Could not induce a poll failure on prod (no session). Verified at the route
|
|
integration level on the prod commit, which is where the bug lived:
|
|
"A failing poll degrades the board — it never replaces it (§KB.7)"
|
|
> keeps the cards on screen when a later poll fails
|
|
> keeps a first-time client's guidance panel when a later poll fails
|
|
> still shows the full-region error when there is NOTHING to show
|
|
The amber reconnecting line is rendered and screenshotted:
|
|
en-freshness.png : "Updated 4 minutes ago — reconnecting" (amber + warn icon)
|
|
fr-freshness.png : "Actualise il y a 4 minutes — reconnexion en cours"
|
|
Staleness only after THREE missed intervals, not one.
|
|
|
|
[4] TAB PILLS COUNT THE PROJECT, NOT THE VISIBLE CARDS — #1554 .............. OK
|
|
THE CONTRADICTION IS RESOLVED. Screenshot en-bugtab.png, Bugs pill = 12
|
|
with zero cards in view, renders:
|
|
"This tab has 12 tickets, beyond the most recent ones each column loads."
|
|
and does NOT render "No bugs reported yet." The two never co-occur.
|
|
Tests: "shows the twelve bugs the per-status cap kept out of the payload";
|
|
"does not tell a client their twelve bugs do not exist";
|
|
"still says a genuinely empty tab is empty";
|
|
"shows no pill for a category the project genuinely has none of".
|
|
|
|
[5] BACKLOG + BLOCKED RENDER BUT REJECT EVERY DROP, ZERO NETWORK ........... OK
|
|
en-board.png: Backlog column renders with a padlock and "Not a drop target".
|
|
Blocked renders likewise. Neither draws the dashed drop box.
|
|
Network panel not observable without a session; asserted instead at the
|
|
exact call site:
|
|
"refuses a drop on Backlog without asking the write path anything"
|
|
"refuses a drop on Blocked even when the server allows that status"
|
|
"never offers Backlog(16), for anyone" / "never offers Blocked(14)"
|
|
"locks Backlog and Blocked and nothing else"
|
|
"treats a drop back on the card's own column as a no-op, with zero calls"
|
|
FR lock reasons are distinct and correct: Backlog "Un ticket sort du backlog
|
|
en etant soumis, pas en etant glisse." / Blocked "C'est depuis le ticket
|
|
lui-meme qu'on le marque comme bloque."
|
|
|
|
[6] MOVE MENU REACHES BLOCKED + KEYBOARD PATH — #1546 ....................... OK
|
|
The earlier dead path (B1 of the failed code review) is alive:
|
|
"MOVES a card to Blocked when the menu asks — the gesture's ban is not
|
|
the write path's"
|
|
"keeps Blocked, which is the whole point of §KB.4b"
|
|
"is a superset of the drag targets, never a different set"
|
|
"still never moves a card INTO the backlog"
|
|
Keyboard, keys alone:
|
|
"offers a keyboard route to every legal target, driven by KEYS ALONE"
|
|
"closes the Move menu on Escape and returns focus to its trigger"
|
|
"hands focus back to the row when a confirm is cancelled"
|
|
B2 (stale target list) also fixed: "hands back the REAL set once the engaged
|
|
card's detail lands".
|
|
|
|
[7] MANUAL REFRESH — #1547 .................................................. OK
|
|
Rendered and screenshotted (en/fr-freshness.png).
|
|
"refetches on click"
|
|
"says it is busy while a fetch is in flight"
|
|
"issues no second refetch when clicked mid-fetch" <- double-fire guard
|
|
"keeps its place in the tab order while busy — aria-disabled, not disabled"
|
|
"does not change its label while busy, so its width never moves"
|
|
"renders no freshness line before the first successful fetch"
|
|
"turns amber and says reconnecting once polls stop landing"
|
|
|
|
[8] COLUMN FILTER PERSISTS ACROSS A FULL RELOAD — #1544 ..................... OK
|
|
Endpoint live on prod: /api/auth/me/board-columns/1 -> 401 (exists, gated).
|
|
"writes the whole hidden set and survives a reload"
|
|
"reverts the filter when the server refuses the write"
|
|
"applies a toggle immediately and persists the WHOLE set"
|
|
"falls back to the default rather than blanking the board when the read fails"
|
|
"resets to the documented default — Shipped hidden, everything else shown"
|
|
|
|
[9] FRENCH — REAL TRANSLATION, NO ENGLISH FALLBACK ......................... OK
|
|
Screenshot fr-board.png, every board string in French:
|
|
Tickets · Fonctionnalites/Bugs/SecOps · Colonnes · Actualiser ·
|
|
Nouvelle demande · Reindexer · Pret · "Derniere indexation il y a 2 heures"
|
|
Soumis · Specification · En developpement · Recette
|
|
"Depot impossible" · "Aucune tache a cette etape." · "Non assigne"
|
|
"Urgente" · "Immediate" · "+ 52 tickets de plus"
|
|
"Actualise a l'instant"
|
|
Relative time and the freshness line in French (fr-freshness.png):
|
|
"Actualise il y a 4 minutes"
|
|
"Actualise il y a 4 minutes — reconnexion en cours"
|
|
Test: "keeps `tasks.board` AND `tasks.priority` mirrored EN <-> FR";
|
|
"renders relative time through the app's locale, never the browser's".
|
|
|
|
[10] NEW REQUEST + KNOWLEDGESTRIP REINDEX STILL REACHABLE ................... OK
|
|
Both visible in the board toolbar on en-board.png / fr-board.png:
|
|
"Ready · Last indexed 2 hours ago · [Reindex]" (KnowledgeStrip inline)
|
|
"[+ New request]" (the only intake path)
|
|
Tests: "still reaches New request — the only ticket intake path on this screen"
|
|
"still reaches the reindex control — the app's ONLY mount of it"
|
|
|
|
==============================================================================
|
|
WHAT I COULD NOT TEST, AND WHY
|
|
==============================================================================
|
|
a) No authenticated production session. No client credentials were available
|
|
and the secrets store is out of bounds. Everything below therefore rests on
|
|
the shipped components + the prod-commit suite, not on prod runtime:
|
|
- a real mouse drag against the real API,
|
|
- a real 403/409 rollback against real data,
|
|
- the real network panel showing zero requests on a locked-column drop,
|
|
- a real page reload proving the column filter round-trips.
|
|
b) DRAG WAS DELIBERATELY NOT EXERCISED ON PROD. Per the QA brief, the only way
|
|
to drag on production would be to move a real client's live ticket. I stopped
|
|
rather than mutate client data. A safe target (a disposable ticket on a
|
|
throwaway project) is needed to close item [5] and the drag half of [6]
|
|
against the live API.
|
|
c) The language selector in the fr-board.png header still reads "English" —
|
|
that is an artifact of my harness forcing the locale through the intl
|
|
provider rather than through the selector. It is NOT a product defect; the
|
|
board content beneath it is fully French.
|
|
|
|
==============================================================================
|
|
OBSERVATION (cosmetic, not a defect, no ticket owner assigned)
|
|
==============================================================================
|
|
Two freshness/refresh controls sit on the same screen: the pre-existing project
|
|
header "Updated 2 hours ago | Refresh data", and the new board toolbar
|
|
"Refresh | Updated just now". They report different things (project data vs
|
|
board poll) but read as redundant side by side. Pre-existing chrome meeting new
|
|
chrome; worth a design pass, not a QA failure.
|
|
|
|
==============================================================================
|
|
VERDICT: PASS — #1546 stays in QA.
|
|
No acceptance criterion came back KO. No child of epic #1511 is implicated.
|
|
==============================================================================
|