[ Demonstration ]
A launch-readiness review: sample findings and retests
A sample of the written review we deliver in a QA and launch-readiness engagement, run on an application we built for this purpose with invented data. Some defects were planted on purpose to show the method, and the report says which.
Prepared by Wagenberg Technology Group LLC. Review date: 17 October 2026. Copyright Wagenberg Technology Group LLC, all rights reserved.
1. Summary
| v0.9 pre-QA (baseline) | v1.0 (after fixes, final retest) | |
|---|---|---|
| Automated checks run | 75 | 75 |
| Passed | 48 | 75 |
| Failed | 27 | 0 |
| API and permission tests (node:test) | 30 of 35 passed | 35 of 35 passed |
| Browser tests by role at 1440 px and 390 px (Playwright) | 18 of 40 passed | 40 of 40 passed |
| Scripted exploratory probes flagged | 14 of 41 observations | 0 of 41 observations |
Defects logged: 8 (1 Critical, 1 High, 4 Medium, 2 Low). All 8 were fixed and retested in v1.0. One fix (D-03) was incomplete on the first retest; the retest caught it and it is logged separately as D-08. Four observations remain open for the owner to decide on (section 8).
The first version of the suite had 70 checks (48 passed, 22 failed on v0.9). Five regression checks were added after the exploratory pass found D-06 and D-07, and the baseline was rerun with the full 75-check suite so that before and after numbers compare like with like. Both runs are kept in evidence/ (see evidence/RUN_LOG.md).
2. Scope and boundaries
What was tested
- Application: Job Requests Tracker, builds
v0.9-pre-qa(versions/v0.9-pre-qa/) andv1.0(app/). Node.js HTTP server, SQLite vianode:sqlite, vanilla JavaScript front end. - Roles: requester (Avery Example), manager (Morgan Placeholder), admin (Jordan Testcase), plus a second requester (Riley Sample) and an inactive account (Casey Inactive). All fictional.
- Areas: sign-in and sessions, server-side permission checks on every API route, the approval workflow, the audit trail, input validation, admin user management, layout at two widths, form labelling, basic keyboard operation, security headers, HTML injection in a text field.
- Devices and browser: Chromium 151.0.7922.34 (headless, driven by Playwright 1.62.1) at 1440 x 900 (desktop) and 390 x 844 with mobile and touch emulation, device scale factor 2.
- Runtime: Node.js v26.7.0 on macOS (Darwin kernel 27.0.0). Server bound to 127.0.0.1, fresh in-memory database per run.
- Method: automated API tests, automated browser tests per role and width, scripted exploratory probes, manual review of full-page screenshots, manual
curlreproduction, and a read-through of the server code for the open observations.
What was not tested
- Safari/WebKit, Firefox, Edge, and real phones or tablets (390 px is emulated in Chromium, not a physical device).
- Screen readers. Labelling was checked by script (every visible control has a label or accessible name); no assistive technology was used, and no full WCAG audit was done.
- Load, performance, concurrency between many users, backup and restore, upgrades and data migration.
- Deployment concerns: HTTPS/TLS, reverse proxy, hosting, logging and monitoring. The app ran over plain HTTP on localhost only.
- Security beyond the listed permission and input checks. This is not a penetration test (see section 9).
3. Severity rubric
| Severity | Criteria (any one is enough) | Release guidance |
|---|---|---|
| Critical | A user can perform an action or see data their role does not allow; records can be lost or corrupted; a core workflow is blocked for all users with no workaround. | Should be fixed before release. |
| High | An accountability or compliance control the business relies on (for example the audit trail) is wrong or missing; a core workflow fails for a whole role or case with no reasonable workaround. | Fix before release unless the owner accepts the risk in writing. |
| Medium | A feature works incorrectly, or cannot be used, for some users, devices or inputs, and a workaround exists; an accessibility failure that stops some users completing a task without help; bad data can be saved. | Fix before or soon after release; owner decides. |
| Low | Cosmetic issues, console noise, or confusing messages with no effect on data, permissions or task completion. | Schedule normally. |
Severity describes impact in this application. It is a judgment applied with the written criteria above, not a score from a standard.
4. Test matrix by role
Expected behaviour per role and the checks that cover it. "403" means the server refuses the call even if the user bypasses the screen.
| Capability | Requester | Manager | Admin | Checks |
|---|---|---|---|---|
| Sign in, sign out, session ends server-side | Allowed | Allowed | Allowed | API-02, API-06, E2E-01, E2E-02 |
| Inactive account signs in | n/a | n/a | n/a (refused for any role) | API-04 |
| View requests | Own only; others' by id return 404 | All | All, read only | API-07, API-08, E2E-03 |
| Create a request | Allowed | Allowed | Form hidden | API-09, E2E-04, E2E-11 |
| Approve or reject | 403 | Allowed, not on own requests, once only | 403 | API-10, API-16 to API-20, API-22, API-23, E2E-06, E2E-08, E2E-09, E2E-11, E2E-15 |
| Read audit trail | 403 | Allowed | Allowed | API-03, API-11, API-16, API-18, E2E-08, E2E-09, E2E-12 |
| Manage users (list, add, change role, deactivate) | 403 | 403 | Allowed; cannot deactivate or demote self | API-11, API-21, API-24 to API-27, E2E-10, E2E-12 |
| Input validation | Title, description, priority, content type, JSON, body size | Decision value, rejection note | Name, email, role, duplicates | API-12.1 to API-12.6, API-13, API-14, API-17, API-22, API-24, E2E-05 |
| No sideways scrolling of the page | 1440 and 390 px | 1440 and 390 px | 1440 and 390 px | E2E-13 (each role, each width) |
| Every visible form control labelled | 1440 and 390 px | 1440 and 390 px | 1440 and 390 px | E2E-14 (each role, each width) |
| Keyboard: Tab order on sign-in, Enter submits, decision buttons usable by keyboard, visible focus | Yes | Yes | Yes | E2E-01, E2E-08, exploratory focus and Tab-stop probes |
| HTML in titles shown as text, not run | Yes | Yes | Yes | API-15, E2E-07 |
| Security headers, unknown routes, wrong methods | All | All | All | API-28, API-29 |
Known gap in the matrix: the admin's inability to create a request is checked in the browser (form hidden, E2E-11) but there is no automated API test that an admin POST /api/requests returns 403. The server code restricts that route to requester and manager; adding the API test is recommended.
Each browser check (E2E-xx) runs twice, once per width, which is why 20 browser checks produce 40 results.
5. Defects
D-01 Requester and admin can approve or reject requests through the API
- Severity: Critical (a role can perform an action it must not).
- Origin: Seeded on purpose (S1 in
versions/v0.9-pre-qa/SEEDED_DEFECTS.md). - Found by: API-10, API-23, E2E-06 (both widths), E2E-11 (both widths), exploratory API probe. The screens hid the buttons correctly, so only the direct API checks exposed it.
- Steps to reproduce (v0.9):
- Sign in as
avery.requester@example.com. POST /api/requests/2/decisionwith{"decision":"approve","note":"approved by requester"}. Request 2 belongs to Riley Sample.
- Sign in as
- Expected: HTTP 403, request stays pending.
- Actual (v0.9,
evidence/repro-curl-v0.9-pre-qa-2026-10-17T23-07-29Z.txt):HTTP 200and"status":"approved","decided_by":1, so the requester approved another person's job. API-23 showed the same for the admin:expected 403, got 200. - Evidence:
evidence/v0.9-pre-qa/2026-10-17T23-04-05-710Z/api-tests.txt(API-10:AssertionError: expected 403, got 200),e2e-tests.txt(E2E-06, E2E-11:Expected: 403 Received: 200),exploratory.txt. - Fix in v1.0: the decision route calls
requireRole(ctx, 'manager')before anything else (evidence/v0.9-to-v1.0.diff). - Retest: Pass. curl now returns
{"error":"Your role does not allow this action"} HTTP 403(evidence/repro-curl-v1.0-2026-10-17T23-07-30Z.txt); API-10, API-23, E2E-06, E2E-11 pass.
D-02 Rejections are not written to the audit trail
- Severity: High (the accountability record is incomplete for one of two decision types).
- Origin: Seeded on purpose (S2).
- Found by: API-18 and E2E-09 at 1440 px. At 390 px, E2E-09 could not reach the Reject button because of D-03, so D-03 masked this defect on mobile.
- Steps to reproduce (v0.9): sign in as
morgan.manager@example.com, reject request 3 with a note, then readGET /api/auditand filter to request 3. - Expected: a
request.rejectentry with actor, time and note. - Actual: the request is saved as rejected (
HTTP 200) but the audit list for request 3 is[]. API-18 reportedaudit entries for request 11: ["request.create"]. E2E-09 at 1440 px:expect(locator).toHaveCount(1) ... Received: 0. - Evidence:
evidence/repro-curl-v0.9-pre-qa-2026-10-17T23-07-29Z.txt,evidence/v0.9-pre-qa/2026-10-17T23-04-05-710Z/api-tests.txt,e2e-tests.txt. - Fix in v1.0: both decisions write
request.<decision>with the note. - Retest: Pass. Audit for request 3 now shows
[{"action":"request.reject","actor":"Morgan Placeholder",...,"detail":{"note":"covered by existing contract"}}].
D-03 Page scrolls sideways on a 390 px phone; buttons cannot be tapped
- Severity: Medium (core tasks fail on phones; desktop is a workaround).
- Origin: Seeded on purpose (S3).
- Found by: E2E-13 at 390 px for all three roles, exploratory width probe, and as side effects in E2E-12, E2E-09 and E2E-15 at 390 px.
- Steps to reproduce (v0.9): open the app at 390 px wide, sign in as any role.
- Expected: the page is no wider than the screen; wide tables scroll inside their own box.
- Actual: page width 798 px (requester) and 1062 px (manager, admin) in a 390 px viewport. In emulation, taps on "Add user" (admin), "Reject" and "Approve" (manager) were intercepted by other elements, for example
<td>Jordan Testcase</td> from <section> subtree intercepts pointer events, and the actions timed out. - Evidence:
evidence/v0.9-pre-qa/2026-10-17T23-04-05-710Z/e2e-tests.txt(Error: page is 1062px wide in a 390px viewport), screenshots inevidence/v0.9-pre-qa/2026-10-17T23-04-05-710Z/screenshots/explore-mobile-390-*.png. - Fix in v1.0: each table is wrapped in a labelled, keyboard-focusable scroll region (
.table-wrap { overflow-x: auto }). - Retest: the first retest still failed for manager and admin; see D-08. Final retest: Pass.
D-04 The "Title" field on the new request form has no label
- Severity: Medium (screen-reader and voice-control users cannot identify the required field; placeholder text is not a label).
- Origin: Seeded on purpose (S4).
- Found by: E2E-14 for requester and manager at both widths (
+ "input#req-title"in the list of unlabelled controls), and E2E-04, which looks the field up by its label and timed out:locator.fill: Timeout 5000ms exceeded. waiting for getByLabel('Title'). - Steps to reproduce (v0.9): sign in as a requester, inspect the first field of "New job request": it has
placeholder="Short title"and no<label>,aria-labeloraria-labelledby. - Expected: a visible label "Title" tied to the input.
- Actual: no accessible name except the placeholder.
- Evidence:
evidence/v0.9-pre-qa/2026-10-17T23-04-05-710Z/e2e-tests.txt. - Fix in v1.0:
<label for="req-title">Title</label>added. - Retest: Pass (E2E-04 and E2E-14, all roles, both widths).
D-05 A title made only of spaces is accepted
- Severity: Medium (bad data can be saved; managers see blank requests).
- Origin: Seeded on purpose (S5).
- Found by: API-12.2 and E2E-05 at both widths.
- Steps to reproduce (v0.9): as a requester,
POST /api/requestswith{"title":" ","priority":"normal"}. - Expected: HTTP 400 with
fields.title. - Actual:
HTTP 201and a pending request with"title":" ". In the browser the form showedRequest #4 submitted.instead of the validation message. - Evidence:
evidence/repro-curl-v0.9-pre-qa-2026-10-17T23-07-29Z.txt,api-tests.txt,e2e-tests.txt. - Fix in v1.0: the title is trimmed before the length check.
- Retest: Pass. curl returns
{"error":"Validation failed","fields":{"title":"Title must be 3 to 120 characters"}} HTTP 400.
D-06 Every page load logs a 401 error in the browser console
- Severity: Low (noise only; it can hide real errors from anyone watching the console or error monitoring).
- Origin: Not seeded. Found by the exploratory console probe on v0.9 for all 3 roles at both widths.
- Steps to reproduce (v0.9): open the sign-in page with developer tools open.
- Expected: no console errors on a normal page load.
- Actual:
Failed to load resource: the server responded with a status of 401 (Unauthorized), caused by the page asking/api/mebefore anyone has signed in. - Evidence:
evidence/v0.9-pre-qa/2026-10-17T23-04-05-710Z/exploratory.txt; regression checks API-30 and E2E-16 were added and fail on v0.9 (api-tests.txt,e2e-tests.txt). - Fix in v1.0: new
GET /api/sessionanswers200 {"user":null}when signed out;/api/mestill returns 401 for API clients. - Retest: Pass (API-30, E2E-16 both widths; console probe clean in all 6 contexts).
D-07 Double-clicking "Approve" shows an error after a successful approval
- Severity: Low (data stayed correct: one decision, one audit entry; the manager sees a misleading error).
- Origin: Not seeded. Found by the exploratory double-click probe on v0.9.
- Steps to reproduce (v0.9): as manager, double-click "Approve" on a pending request.
- Expected: one approval and the message
Request #N approved. - Actual: the second click sends a second request, the server correctly answers 409, and the status line shows
Request #4: This request has already been decided. The audit trail had exactly 1 approval entry. - Evidence:
evidence/v0.9-pre-qa/2026-10-17T23-04-05-710Z/exploratory.txt,screenshots/explore-double-click-approve.png; regression check E2E-15 added (Received: "Request #9: This request has already been decided"at 1440 px). - Fix in v1.0: the row's buttons are disabled while a decision is being sent.
- Retest: Pass (E2E-15 both widths; exploratory probe shows the success message and 1 audit entry).
D-08 The first fix for D-03 was incomplete: hidden labels still widened the page
- Severity: Medium (same effect as D-03 for managers and admins on phones).
- Origin: Not seeded. Introduced by the first D-03 fix and found by the first v1.0 retest.
- Found by: E2E-13 at 390 px in retest 1 (
evidence/v1.0/2026-10-17T23-01-29-204Z/):page is 552px wide(manager) andpage is 434px wide(admin). Requester passed. - Cause: the visually hidden labels inside table cells use
position: absolute. The new scroll box was not a positioned element, so those labels were placed relative to the page and escaped the scroll box. - Fix:
.table-wrap { position: relative; }(evidence/D-08-fix.diff). - Retest: Pass in every later v1.0 run (23:02, 23:05 and the final 23:07 UTC run). The exploratory probe was also improved during this step so it reports absolutely positioned elements that escape a scroll box; rerun on the retest 1 code, it flags them (4 flags), and on the final code it flags none.
6. Fixes and retest results
| ID | Severity | Origin | v0.9 baseline | v1.0 retest 1 (23:01 UTC) | v1.0 final (23:07 UTC) |
|---|---|---|---|---|---|
| D-01 | Critical | Seeded S1 | Fail (6 checks) | Pass | Pass |
| D-02 | High | Seeded S2 | Fail (2 checks) | Pass | Pass |
| D-03 | Medium | Seeded S3 | Fail (6 checks) | Partly fixed, see D-08 | Pass |
| D-04 | Medium | Seeded S4 | Fail (6 checks) | Pass | Pass |
| D-05 | Medium | Seeded S5 | Fail (3 checks) | Pass | Pass |
| D-06 | Low | Found in QA | Fail (3 checks) | Pass | Pass |
| D-07 | Low | Found in QA | Fail (1 check; masked by D-03 on mobile) | Pass | Pass |
| D-08 | Medium | Found in retest | Not applicable | Fail (2 checks) | Pass |
| Totals | 48 of 75 passed | 73 of 75 passed | 75 of 75 passed |
The 27 baseline failures add up by defect: 6 + 2 + 6 + 6 + 3 + 3 + 1 = 27. The full change set from v0.9 to v1.0 is in evidence/v0.9-to-v1.0.diff.
7. Corrections to the test tooling (disclosed)
These were problems in the checks, not in the application. They are listed so the numbers can be trusted.
- Mobile width check. The first draft compared page width with
window.innerWidth. In Chromium mobile emulation that value grows with overflowing content, so the check passed on a page that was visibly too wide. It now compares with the configured device width. Fixed before any recorded baseline. - Focus indicator probe. The first recorded v0.9 run (
22-56-37) reported "no focus outline" on the Sign out button in all 6 contexts. The probe used programmatic focus, which does not trigger:focus-visibleon buttons. Changed to real Tab key presses; the outline (solid 3px) is present in every build. Not logged as a defect. - Overflow element probe. Revised twice while investigating D-08 so that it neither ignores nor falsely reports content inside scroll boxes. Its final behaviour was checked against both the retest 1 code (flags the escaping labels) and the final code (no flags).
- Suite growth. The suite grew from 70 to 75 checks after D-06 and D-07 were found. The 75-check suite was rerun on the unchanged v0.9 build to give the baseline in section 1.
8. Open observations (not fixed; owner to decide)
| ID | Observation | How it was found | Suggested severity |
|---|---|---|---|
| O-01 | At 390 px the Approve and Reject buttons sit in the last table column, off screen to the right inside the scroll box, with no visual cue that the table scrolls. A manager on a phone may not find them. | Manual review of evidence/v1.0/2026-10-17T23-07-37-843Z/screenshots/explore-mobile-390-manager.png | Low to Medium (usability). Consider a stacked card layout on narrow screens. |
| O-02 | The temporary password for a new user is shown on the admin's screen. | Code read-through of POST /api/users and the admin form | Process decision. Acceptable for a demo; a production build would normally send an invitation link instead. |
| O-03 | There is no limit on failed sign-in attempts (failures are audited, but not throttled). | Code read-through; not load tested | Medium for an internet-facing deployment. |
| O-04 | Sessions do not expire unless the user signs out or is deactivated. | Code read-through | Medium for shared or public computers. |
9. Limits of this review
- This is not a penetration test. Permission checks were exercised for the listed routes and roles; no attempt was made to find every possible vulnerability.
- This is not a certification of accessibility, security or any standard. Accessibility checks were limited to automated label checks, keyboard Tab order on key screens and a focus outline probe.
- This is not a guarantee. Passing checks show that the listed behaviours worked in the listed environment on the review date. Other browsers, devices, data volumes and deployments may behave differently.
- Results are for the exact code in this folder at the time of the runs. Any later change needs a fresh run.
10. Release decision
The client decides whether to release. This report gives evidence and a severity view; it does not approve or block a release. On this evidence, every logged defect has a passing retest in v1.0 and the open observations in section 8 are for the owner to accept, schedule or fix.
The application code and the raw test evidence are kept privately by Wagenberg Technology Group. For the service itself, see QA and launch readiness.
Talk it through
Request a consultation through the contact form on this website, or email thomas@wagenbergtech.com.