Skip to content

fix(monkey): recognise non-English sign-out controls, configurable per project (#469) - #481

Merged
MendixMau merged 4 commits into
masterfrom
fix/monkey-signout-i18n
Oct 20, 2026
Merged

MendixMau merged 4 commits into
masterfrom
fix/monkey-signout-i18n

Conversation

@MendixMau

@MendixMau MendixMau commented Oct 20, 2026 •

Copy link
Copy Markdown
Owner

Fixes #469

Direct lane (changes to skills/, bug-logs/, bin/, project-bin/, project-tests/, pipelines)

What changed and why (one paragraph):
project-tests/e2e/monkey.js excluded sign-out controls with /\b(sign|log)\s*(out|off)\b/i, which is English only. In a Dutch app the monkey clicked Afmelden, landed on login.html, scored CRASH 'blank page — no .mx-page or nav tree' and fuzzed nothing more. This PR follows the issue's suggestion: a multilingual default plus a project-configurable pattern.

  1. SIGN_OUT now also matches common sign-out captions in Dutch (afmelden, uitloggen), German (abmelden, ausloggen), French (se déconnecter, déconnexion), Spanish (cerrar sesión), Portuguese (terminar/encerrar sessão) and Italian (disconnetti). These match as the whole caption only (^\s*(?:…)\s*$), because they are also ordinary verbs: "Ziek afmelden", "Afmelden nieuwsbrief", "Vom Kurs abmelden" and "Disconnetti dispositivo" stay fuzzable, and so do sign-in captions (Aanmelden, Inloggen, Anmelden, Se connecter). The issue lists no variants such as "nu afmelden", so none were added. The English phrase keeps its old word match.
  2. A project adds its own captions in project.config.js signOutPattern (a RegExp or a regex string) or the SIGN_OUT_PATTERN env var, read through config.js as cfg.signOutPattern. The project pattern is added to the default, never a replacement. A project RegExp keeps its own flags, merged with i; g and y are dropped because they make .test() stateful. An invalid pattern prints a warning and falls back to the default. The template declares signOutPattern: null, so an older project.config.js without the key keeps working.
  3. rapidTab no longer presses Enter blind. After its 15 Tabs it reads the focused element's text, aria-label and title, and tests each one on its own (isSignOutLabel, exported and unit-tested). If that is a sign-out control, it presses Tab again (at most 5 times), and skips Enter, saying so in the observation, if focus is still on one. This is how a sign-out in the layout's top bar or in a nav item, both outside .mx-page, was reached. The button locator only offers .mx-page buttons, so the keyboard was the only path to them.

Golden input: the captions are the issue's own, verbatim: Afmelden (clicked in the field run), Uitloggen, Abmelden, Se déconnecter. The fixture keeps the captured English ones from the 2026-09-26 run.

Field evidence (rule 4):
Reported by jopterhorst: monkey.js --rounds 24 --seed 204262061 on a Dutch-UI app gave 3 observations and 1 crash-class, all from the sign-out. The reporter's local workaround (the same two Dutch words plus a Tab-past in rapidTab) gave 24 observations and 0 crash-class on the same seed. This PR is that workaround, generalised. Owed by the maintainer: a re-run of that seed against a non-English app. The author session had no running Mendix app, so the browser path (focusIsSignOut) is verified by its static guard and by node --check, not by a live run.

Impact

Row Answer
Process: human steps or gates added/removed; does anything new block; new stage artifacts none
Dependencies: shared files touched; order vs other open PRs; new tools/platform assumptions; new artifact reads + their producer project-tests/e2e/config.js gains one optional key, read by monkey.js only. Its producer is project.config.js, from project.config.template.js (which now declares it as null) at install-tests.sh time, or the env. A missing key means the default. No new tools. No ordering constraint against #470/#471/#477 beyond a trivial CHANGELOG.md line merge.
Context cost: always-loaded words per role, base → head none: no routed or always-loaded file touched (bin/render-routing.sh --check clean).
Behaviour: A/B for agent-read text n/a: scripts only.
Runtime One page.evaluate per rapidTab round, plus at most 5 more when focus sits on a sign-out control. Each is milliseconds, against the round's fixed 1.8 s settle.
  • No client data anywhere in the diff (whole-word grep of added lines for the denylist terms, /Users/ and /home/user: 0 hits; LEAKGUARD_ALLOW_NO_DENYLIST=1 bin/check-no-client-data.sh clean)
  • Size cap: 5 files, about 75 lines changed outside the fixture and CHANGELOG (the branch also carries a merge of origin/master)
  • Test tier reached: T1. tests/wave2/test-monkey-left-app.sh project-tests/e2e/monkey.js gives 22/22. New cases: the issue's captions, sign-in near-misses, the four over-match captions, a padded whole caption, a project RegExp and a project string, the RegExp's own flags, a project pattern adding to the default, an invalid or absent pattern, per-label focus testing, config/template plumbing, and the rapidTab focus check. On master's monkey.js it gives 9 FAIL; on this PR's first head (8427edc), 3 FAIL. The rapidTab static guard is now scoped to the rapidTab branch, because the old one also matched the ABUSES list and the function definition. Mutation check: with the rapidTab branch replaced by a blind press('Enter'), the new guard FAILs and the old one passed. test-journey-preflight.sh (loads the same config.js) gives 75/0. bin/check-scripts.sh, bin/check-portability.sh, bin/render-routing.sh --check and bin/check-pr-discipline.sh origin/master are clean.
  • For a changed instrument: golden captions are verbatim from the issue. Layouts: no path handling changed (the fixture builds the usual tests/e2e/ under a project root). Platforms: pure Node regex and Playwright calls; no shell-outs added.
  • For a new skill: n/a
  • CHANGELOG.md line appended, crediting jopterhorst
  • New bug entries: n/a

Left open: the issue also suggested detecting sign-out by the button's action instead of its caption. I did not do that here. Mendix renders a Forms$LogoutButton, but I could not confirm the DOM class or attribute it carries without a running app, and guessing a selector is the imagined-input failure the field-proof rule warns about. An icon-only sign-out button inside .mx-page that has no caption is still offered to the button picker, because the hasNotText filter sees text only. rapidTab does catch such a control through its aria-label/title.

https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw


Generated by Claude Code

…r project (#469)

SIGN_OUT matched English captions only, so a Dutch app's "Afmelden" was
clicked, the monkey landed on login.html and scored a false CRASH. The
default now covers nl/de/fr/es/pt/it captions, a project adds its own via
project.config.js signOutPattern or SIGN_OUT_PATTERN, and rapidTab steps
past a focused sign-out control instead of pressing Enter on it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
…ct flags (#469 review)

The non-English words are ordinary verbs, so a word match left "Ziek
afmelden", "Afmelden nieuwsbrief", "Vom Kurs abmelden" and "Disconnetti
dispositivo" unfuzzed; they now match only as the whole caption, and the
focus check tests text, aria-label and title one by one. A project
RegExp keeps its flags (g/y dropped). The rapidTab static guard is
scoped to that branch: the old one passed a blind-Enter mutation, the new
one fails it. Fixture 22/22; 8 FAIL on master, 3 on the previous head.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
@MendixMau
MendixMau merged commit 1de6904 into master Oct 20, 2026
2 checks passed
MendixMau added a commit that referenced this pull request Oct 20, 2026
Merges six independently reviewed bug fixes. Each was MERGE after one fix round.
- #486 progress-report nav (#479 items 1-3)
- #480 conformance-check (#470)
- #482 page-fidelity popup (#471)
- #481 monkey sign-out i18n (#469)
- #484 bare $VAR before non-ASCII (#467)
- #485 \t in sed/grep brackets (#468)

Verified on the integrated tree:
- check-scripts, check-portability, render-routing --check, pr-discipline and the leak guard are clean.
- progress-report polish 53, field-fixes 105 and pages 54 pass.
- conformance-absent-marker 24, monkey-left-app 22, page-fidelity-mocks 78, status-bare-var 3, sed-tab-bracket 9, context-pack 55 and bug03-gates 47 pass.
Field runs on real projects are owed by the maintainer.

Fixes #479 items 1-3, #470, #471, #469, #467, #468.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

monkey.js SIGN_OUT is English-only: a non-English app's sign-out button logs the monkey out and scores a false crash

2 participants