Skip to content

QA run · release-18.1.0-browser-retest-new-pin (9/9) · d44c8936 · 2026-10-23 · 6 PASS / 2 PARTIAL / 1 FAIL / 0 BLOCKED / 0 NOT-RUN #25517

Open

Description

@objectstack-fleet

This record re-drives the browser-observed items of the 18.1.0 manual sweep on the new console pin, after #25455 moved .objectui-sha 5fef032b1ada → 6fb31dcc9954 (12 objectui commits, including objectui#13370, which fixes the #25438 console build break). The first measurements are QA run #25478 (P0) and QA run #25479 (extended set), both on main 77392e9. The set was named by hand: the nine items whose verdicts read the console. Every item has a verdict (9/9), and every clause was re-measured live rather than copied.

Environment fingerprint

  • framework d44c8936b1a2 (main after chore(console): move the objectui pin 1d178e06ac5e → 6fb31dcc9954, past objectui#13370, so the console builds against the spec again #25455). .objectui-sha = 6fb31dcc9954844b2631ecfa96e999c4f73c4881.
  • console: built by pnpm objectui:build directly on this main at the pin, with no sibling-worktree deviation this time. packages/console/dist/.objectui-sha equals the pin. pnpm build was 76/76.
  • boots: stock showcase via objectstack dev --ui --seed-admin, with OS_PORT exported. Each runner had its own ports (47701 / 47711–47712 / 47721–47722) and its own file DBs. Health was 200 within 14–26 s.
  • browser: playwright-core 1.63.0, /opt/pw-browsers/chromium, headless, one context per persona, with identity proved through get-session.
  • execution: three runner agents (login/nav/CRUD · account/first-run/feedback · approvals/actions). All servers were stopped by process group, and git status stayed clean.

Scope and verdicts

item priority rev verdict vs first run
platform-core.console-login P0 4 PASS same
platform-core.builtin-apps-nav-render P0 7 PARTIAL (marketplace catalog blocked(environment): 502 MARKETPLACE_PROXY_FAILED, egress denied) same
records-forms.crud-roundtrip P0 13 PASS same
approvals.account-app-entry P0 4 PASS same
studio-authoring.first-run-loop P0 6 PASS same
approvals.record-page-decisions P2 4 FAIL (negative[1], objectui#13393 still reproduces) same
approvals.inbox-metadata-actions P1 5 PASS same
records-forms.action-location-matrix P1 14 PARTIAL (A3 fail-closed half not consultable on stock; A4 half (a) blocked(fixture), knownGaps) same
ux-conventions.write-feedback P1 4 PASS same

Derived: 6 PASS / 2 PARTIAL / 1 FAIL / 0 BLOCKED / 0 NOT-RUN. No item verdict changed against the first run. The P0 subset is 4 PASS / 1 PARTIAL / 0 FAIL.

Per-clause evidence

platform-core.console-login

Driven on two fresh contexts with identical results.

  • A1 pass: sign-in 200 sets the session cookie and lands on /_console/home (launcher, no sidebar).
  • A2 pass: after a reload on a showcase route, get-session, discovery and meta/app all return 200 and the URL is unchanged.
  • A3 pass: sign-out returns 200. The same bearer then gets 401 UNAUTHENTICATED.
  • A4 pass: navigation redirects to /login?redirect=….
  • A5 pass: re-login lands on the same route; the data read returns 200 and the write 201.
  • negatives hold: a wrong password gives 401 INVALID_EMAIL_OR_PASSWORD, sets no cookie, and shows a named alert.

platform-core.builtin-apps-nav-render

  • A1 blocked(environment) on the catalog leg only. Setup renders 42/42 served destinations and Account 8/8, with 0 pageerror. Browse Marketplace shows a named "Failed to load marketplace · HTTP 502" state.
  • A2 pass: the served Setup and Account nav payloads are byte-identical to the first run (9 groups with 42 leaves; 8 leaves).
  • A3 pass: the member sees a named "You don't have access to this app" page (/meta/app/com.objectstack.setup 403), and Account opens on Profile.
  • A4 pass: forged requests as the member give ?id=setup 200 items:[] and the direct reads 403 PERMISSION_DENIED.
  • A5–A6 pass: entry, service and object gates resolve to absence as before.
  • A7 pass: off-capability destinations are absent.
  • pin delta (objectui#13365): navigation groups now start open unless the payload declares expanded:false. Only Setup › Advanced and Account › Developer start closed.

records-forms.crud-roundtrip

  • A1 pass: create 201, every value verbatim.
  • A2 pass: the PATCH body is only annual_revenue; a full-row diff shows that field and updated_at.
  • A3 pass: delete 200, then total 0 and RECORD_NOT_FOUND.
  • A4 pass: the list is correct after a clean reload.
  • A5 pass: History shows display values.
  • A6 pass: a CJK name round-trips byte-identical, and $search returns 2 hits.
  • A7 pass: the clone re-derives owner and autonumber, and a planted readonly lead_score is reported in droppedFields.
  • A8 pass: a contributor cloning an RLS-invisible invoice gets 404 RECORD_NOT_FOUND.
  • negatives hold: empty name is blocked client-side, API missing name gives 400 VALIDATION_FAILED, and a bad tax_id gives 400 invalid_format.

approvals.account-app-entry

  • A0 pass: the stamp equals the pin, and the entry chunk registers approvals:inbox.
  • A1 pass: Avatar › Profile › Inbox › Approvals renders My Pending (2) / Submitted by me / All, with 0 pageerror. There is now exactly one main landmark (objectui#13366).
  • A2 pass: the persona's app list is [showcase_app, account], and setup is 403.
  • A3 pass: the record page bar matches the declared predicates. Approve returns 200 and progress moves from 0 of 2 to 1 of 2. The persona leaves pending_approvers and the bar is removed.
  • A4 pass: a cold deep link ?request=<id> redirects to the request record page on 3 fresh contexts.
  • A5 pass: the invoice href keeps com.objectstack.account.
  • A6 pass: under zh-CN the nav reads 待我审批 and the tabs and badge are translated.

studio-authoring.first-run-loop

  • A0 pass: package create returns 201 with no page load.
  • A1 pass: the picklist needs options before save. Publish all returns 200, and the served options are exactly open / in_progress / done.
  • A2 pass: Studio Add record returns 201 with status:in_progress.
  • A3 pass: the Repair Center app nav is served, the launcher lists it, and the end-user list shows an "In Progress" chip.
  • A4 pass: one boot throughout, and the listener pid was unchanged across the loop.
  • A5 pass: the forged writes into com.example.showcase give 422 WRITABLE_PACKAGE_REQUIRED (new object) and 403 ITEM_LOCKED (add field). Nothing landed.

approvals.record-page-decisions

Fixtures: four project budget PATCHes. One was approved through manager_review, which opened an exec_review request with lock_record:true.

  • A0 pass: the declared action bar sits above the body, not inside the header.
  • A1 pass: Reject opens exactly one dialog with a comment and a file input. Nothing posts before Confirm. One POST to the request id returns 200.
  • A2 pass: the decisions persist (rejected / approved), and the action rows carry the comments.
  • A3 pass (admin side, as the steps scope it): lock true shows the "Locked for approval" band, Edit disabled, and 0 inline affordances. Lock false shows "In approval · editable" with affordances.
  • A4 pass: a forged member approve or reject gets 403. An off-slate admin sees the Override variants. The member sees no declared actions.
  • negative[1] VIOLATED, still reproduces (objectui#13393):
    • A contributor member who is not a participant opens the lockRecord:true record and sees 12 inline-edit affordances, an enabled Edit and no lock band.
    • Saving answers 409 RECORD_LOCKED.
    • Reproduced on 5 fresh loads, and again on a separate fresh-DB boot.
    • The admin on the same record and script sees the lock correctly.
    • resolveApprovalLock (packages/react/src/context/InlineEditContext.tsx) is unchanged at 6fb31dcc. The fix is not in this pin.
  • negatives [0] and [2] hold.

approvals.inbox-metadata-actions

  • A0 pass: the approver's request page shows the declared approver set.
  • A1 pass: the button sets differ by flags. The approver gets no Send reminder or Recall. The admin off-slate gets the Override variants. The admin as submitter gets Send reminder and Recall.
  • A2 pass: every rendered set equals the declared visible CEL for the read's flags.
  • A3 pass: approve returns 200 and the request becomes approved. Remind returns 200 and the request stays pending.
  • A4 pass: exactly one new /actions row per decision.
  • negative holds.

records-forms.action-location-matrix

  • A0 pass: all six surfaces render the declared placements (list_toolbar, list_item, record_header, record_more, record_related, record_section).
  • A1 pass: no extra placements.
  • A2 pass: all six dispatch kinds round-trip:
    • flow wizard: resume 200, and the assignee is re-read.
    • modal: opens.
    • form page: routes to the form.
    • script: Mark Done 200, done false→true.
    • url: popup requested; it renders an egress error.
    • api: recalc 200, estimate_hours 40→136.
  • A3: both visible sides pass. The fail-closed half cannot be consulted on stock, because booleans are validated server-side and no throwing predicate exists.
  • A4: half (b) passes, and showcase_new_task (locations:[]) is absent everywhere. Half (a) is blocked(fixture) (knownGaps).

ux-conventions.write-feedback

  • A0 pass: all 14 driven writes landed (server read) and showed non-empty feedback: create ×2, inline edit ×2, bulk delete, kanban, Mark Done, invite, approval, import, Studio autosave/publish/discard, settings save.
  • A1 pass: the messages name the record, invitee or count. "Task created successfully" and "Settings saved" are the remaining object-only strings, an open ruling question unchanged from the first run.
  • A2 pass: the declared success messages render verbatim.
  • A3 pass: an empty title is blocked client-side with a named field error. An invalid kanban transition gives 400, a named error toast and live region, and the card reverts.
  • A4 pass: a no-op edit sends 0 writes and shows no toast.
  • A5 pass: import Undo restores the data in both update and create modes.
  • pin deltas: toasts now render top-centre (objectui#13363). Studio Discard now confirms in-app (objectui#13368), where it used a native confirm before.

Probes (rule 8)

About 23 minutes in total, across the three boots, as admin, Mei, a contributor member and a non-override approver. Door classes tried:

  • clone, PATCH and DELETE boundaries;
  • session expiry inside the app;
  • ?request= with empty, unknown and whitespace values;
  • re-decide and terminal-state decisions;
  • non-participant levers;
  • headless and unknown actions;
  • RLS-invisible rows;
  • Setup deletes;
  • toast placement at 390 px;
  • import Undo.

Findings:

Low or cosmetic observations, not filed:

  • GET /approvals/requests?object=X&recordId= with an empty recordId drops the empty predicate. It answers all of the caller's requests, still within participant scope.
  • An in-app session expiry shows a named "Sign in required · Retry" state in the shell, without redirecting to login.
  • The single-record delete toast is the generic "Record deleted", while bulk delete names the count.
  • Import "Undo import" still uses a native window.confirm and shows no toast.
  • At 390 px the top-centre toast covers the app bar while it shows.
  • The seeded EXP-DEMO 2-of-3 committee has the admin in all 3 slots, so one approve closes it. This is a seed shape.

Checklist-accuracy notes (for the sweep's anchor card)

  • builtin-apps-nav-render:
    • steps[2]: Configuration is no longer collapsed. Only groups declared expanded:false start closed.
    • A link-based walk counts one extra "All reports" link per app, so count from the payload.
  • console-login: sign-in answers 200, not 201.
  • crud-roundtrip:
    • The New form also submits the defaulted industry.
    • The formula re-derivation is still unobservable.
  • account-app-entry:
    • acceptance[6].verify: Language is now a direct avatar-menu row, not under Preferences.
    • acceptance[3] still says "drawer".
  • inbox-metadata-actions:
    • Steps 2, 3 and 6 say "drawer"; the inbox opens the request record page.
    • The tabs render as My Pending / Submitted by me / All.
    • Name the Request cell, because the Record cell opens the business record.
  • write-feedback:
    • variants[10] "accept the native confirm" is stale, since Discard confirms in-app.
    • variants[6] still says "drawer".
    • knownGaps[3] "no stock surface offers Undo" is stale.
    • steps[3]: the stock member has no edit affordances, so use the contributor binding.
  • record-page-decisions: clause 3 is admin-scoped by its steps while negative[1] is unscoped. The scope ruling is still open.
  • action-location-matrix:
    • The Log Time form heading is the machine name showcase_task.form.
    • The Recalculate Selection toast says "whole selection" on a single-record dispatch.
    • The fail-closed half needs a packaged throwing-predicate specimen or a knownGap line.

Extraction

No new product defect was found on this pin. The one FAIL is the existing card objectui#13393 (extracted from QA run #25479 as #25480 and transferred), and it is unchanged at 6fb31dcc. Its fix still has to land and then move the pin.

Environment vs test time: about 15 minutes on environment (install, build, console build, boots, personas) and about 70 minutes of runner test time across three parallel runners, including probes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions