Repository navigation
Bug sweep 2026-10-26: 29 fixes across gates, runners, doctor and skill text - #578
Merged
Merged
Conversation
…t unparsed ones The page-name sed printed the whole declaration line when it did not match, so `create page if not exists "M"."P"` went on as the page name into a false "has no wireframe" STOP. Accept the optional IF NOT EXISTS, print only on a match, report an unparsed declaration as such, and skip a placeholder that the same file declares again for real. Fixes #517 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…scratch copy gate_selftest copied every sibling of the .mpr, including <App>.mpr.lock, so mxcli refused the known-bad injection into the throwaway copy whenever Studio Pro had the project open, and the self-test proved only its baseline half. Case 11 added to test-doctor-gate-selftest.sh (fails on master, 32/32 with the fix). Fixes #577 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…ng it "not transactional" STOP #22, the detection-gaps register row, iterative-build-loop's gate invariants and exec.sh's failed-exec message taught the pre-v0.27 behaviour (earlier statements stay written). On v0.27+ any write-time failure rolls the whole run back, so a non-idempotent statement placed last now fails every re-run and drops the edits above it. STOP #22's rule is unchanged; only the reasoning and the consequence move. Baseline 63,877 -> 63,872 words. Fixes #539 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
Trap 3 said no API creates a first cloud environment, contradicting the
same file's Free App section. POST /api/1/apps {ProjectId} created the Free
App sandbox in a field run; deploys to it stay manual (packages -> 500).
Fixes #516
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
typeSafely() wrote through the native value setter, which skips the maxlength attribute, so a 5000-char payload reached String(200) attributes and every capped box gave a crash-class HTTP 560 that no user can reach. It now cuts to el.maxLength (UTF-16 units, like the server) and returns the cap, which the round notes in the finding. Fixture: tests/wave2/test-monkey-oracle.sh (5/5; master: 0/1). Fixes #544 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…ODULES Step 0 now says how to verify each marketplace install: module packages via SHOW MODULES, widget-only packages (Charts) via widgets/<Name>.mpk. Fixes #510 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
monkey-test.md defines a crash as a page exception, an error page or dialog, a 5xx, or an ERROR span. oracle() also counted "spinner still up after 8s", so a slow but successful batch job failed the run. It now returns those hits as `slow`; round() files them as their own severity when no crash signal fired, and the exit code still counts crash-class only. Verdict table and summary line in monkey-test.md updated. Fixture: tests/wave2/test-monkey-oracle.sh (10/10; without the fix 5/7). Fixes #562 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…563) land() swallowed navTo's "not found" throw and then only asked whether any .mx-page was visible, which the previous target's page always is. A missing target was fuzzed on another page and its findings filed under the wrong name. land() now returns the reason ('' = landed); main and the re-land read it, and the summary prints reached r of t with the unreached targets listed. Fixture: tests/wave2/test-monkey-oracle.sh (14/14; without the fix 10/12). Fixes #563 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
Header text comes from the popup page Title; the h4 is invisible by default (fix with a token-scoped rule in main.scss); width is a shared !default variable set in custom-variables.scss that also widens the sidebar chat. Fixes #574 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…uest copy new A page-triggered microflow that saves an object only via commitInSeparateDatabaseTransaction leaves the request's copy uncommitted; after browser Back a role without Create gets 'Attempt to illegally add an object to the state'. Fix: rollback $X refresh. On-demand text only; the detection-gaps register row is baseline and waits for an A/B. Part of #565 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…ch the model The gate self-test counted errors in a $(...) subshell, so MXTK_MXBUILD_WHY never reached it and an mxbuild that exited 3 with "release version 25 not supported" was reported as "gate cannot read mxbuild's error file". The self-test now keeps the errors file and quotes mxbuild's reason, and mxtk_mxbuild_why appends the compiler's "error:" line from details. The Build toolchain section now WARNs when the Java major does not match a Mendix 11 model (11.14+ -> 25, <=11.13 -> 21; Studio Pro's bundled JRE is never flagged) and names the fix when JAVA_HOME is exported in the shell. WARN only: no verdict flips. A MXTK_JAVA_HOME override (ask 3) is left out. Cases 12-13 in test-doctor-gate-selftest.sh (fail on master, 39/39 with the fix); test-mxbuild-version-match 18/18, test-find-java-version 17/17. Fixes #576 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…retro traps Snippet top-level text has no context object (wrap it in a DataView on the parameter); Nova theme points the File Uploader icons at images nothing ships. The rest of #282 was already in ui-loop.md, lint UI001 and the licence-cap skills. Fixes #282 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
The toolkit's conv010 rule allowlisted MicroflowCallAction but not NanoflowCallAction, so an ACT_ nanoflow delegating to a SUB_ nanoflow was flagged as business logic. mxcli's stock copy allows it. Field proof: mxcli v0.28.0, scratch copy of mendixlabs/mxcli testdata/pedapp with an ACT_ nanoflow calling a SUB_ nanoflow: 1 CONV010 finding before, 0 after. test-stock-hashes 35/35, test-lint-receipt-revert 55/55, test-exec-lint-autorestore 17/17. Fixes #512 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
checkA11y() kept only rule, impact, node count and help, so the rung 7 a11y row read `button-name(critical,x1)` with no evidence. It now keeps the first 5 nodes per rule (axe selector + opening tag), and the new a11yEvidence() turns them into `selector` evidence entries, lifting the Mendix mx-name-<widget> class when the element carries one, with the help text/URL; the page screenshot is attached too. report-render.js renders a selector entry instead of "NO POINTER". Verdicts unchanged. Fixture: tests/wave2/test-design-audit-a11y-evidence.sh over a captured axe-core 4.10.2 run (8/8; master 0/1). nav-map 26/26, css-corpus 7/7. Fixes #561 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
The build-ready placeholder check greps {{...}} per line, so a
placeholder whose description spans lines (mdl-agent's
PROJECT_LOCAL_SOURCES_OF_TRUTH) was never seen and an untouched stub
read "no unfilled placeholders". Detect it with a multi-line match and
print a named WARN; the verdict is unchanged so no project flips.
Fixes #509
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
named-controls.js proves a control by finding mustFail in a check
name; the outcome check was always "<id> end state", so a control
tagged in outcome.label read NOT PROVEN even when the outcome FAILed.
outcomeCheckName() appends ": <label>" when a label is set (the prefix
is kept, so mustFail "end state" still matches; unlabelled outcomes keep
their name and id). report-normalize.js builds the same name. A no-match
NOT PROVEN now lists the FAIL checks; journey-proof.md says which
fields reach a check name.
Fixtures: test-named-controls.sh 28/28 (original: 22/26);
test-journey-{control-exit,id,liveness,persona,preflight},
test-report-normalize-two-tree, journey-rung4-scope.test.js,
report-normalize --selftest all pass.
Fixes #538
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
The page-scope rung had a fixed 300 s budget and the watchdog killed only the bash PID it started, so page-scope.sh's Python child survived, and wrote page-scope.json after the design audit had read the previous one. Add VM_TMO_PAGESCOPE (default 900), kill the instrument's descendants on timeout, and write page-scope.json via rename. Fixes #541 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
#560) --positive-control walks its mutants on one data set. For a journey whose action consumes its seed state, later mutants stopped at "seeds resolved = INVALID" and their control rows said FAIL "BROKEN PRECONDITION WENT GREEN". judgeMutant() now returns INVALID "mutant not run: <row>" when nothing FAILed but a row was INVALID; "went green" is kept for an all-green walk. A journey that declares `consumes` gets a WARN before its mutants. Exit code and proven count unchanged. Not done (proposed): the issue's per-mutant reset hook and --only-rung. Fixture: test-journey-control-exit.sh 12/12 (original 7/9); journey id/liveness/persona/preflight and named-controls fixtures pass. Refs #560 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…gle file A module keeping one journey per file under journeys/<Module>/ got FAULT "no journeys/<Module>.journey.json" while its journeys sat one level down. When the single file is absent, pass every journeys/<Module>/*.journey.json to one runner call (and to the positive control). The single file keeps precedence when both exist. Part of #542 (per-persona runs not included) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…#536) Playwright's locator.isVisible() ignores `timeout` and returns at once. #547 fixed the landing guard; the click / fill / combobox actions and helpers.gotoTarget()'s ready wait still used it, so an element that was attached but still appearing threw "not visible" in 0 ms. New helpers.visibleWithin(loc, ms) waits via waitFor({state:'visible'}); those four sites use it. Instant probes elsewhere are unchanged. Fixture: tests/wave2/test-e2e-visible-wait.sh 4/4 (stand-in locator + the issue's Chromium reproduction; original 0/3). Journey, monkey, named-controls, navto-missing-item and oql-rows fixtures pass. Refs #536 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
… are git-ignored A project .gitignore with /.claude/ kept lint-baseline.json, lint-acceptances.tsv and project-local lint rules out of git; a fresh clone then took a new baseline and lost the accepted-rise record, and no check said so. status.sh (brief and full screen) now adds a WATCH entry naming each ignored path and the .gitignore line, decided by check-ignore -q so a '!' negation counts as tracked. No gate verdict changes. New fixture test-status-lint-unversioned.sh: 4/4 (T1 and T4 fail on master). test-status-bare-var 3/3, test-status-existing-app 27/27, test-status-session-cwd 10/10. Fixes #523 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…t names A per-module coverage-ledger.md was measured against every BRD in the project, so BRDs only other modules claim read fully UNCLAIMED. When every pointer in it carries a BRD prefix, measure only the BRDs the prefixes name and list the rest as another module's, as the directory form already does. Slash-pointer and project-wide ledgers are unchanged. Part of #543 (option 1; cross-ledger UNCLAIMED is option 2) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
Ports the reporter's ~36-line patch. `{ "do": "back" }` calls goBack
(networkidle timeout is a WARN, not a failure) and throws when Back
left the app (backLeftApp: login page, about:blank, another origin).
`"ui": { "no5xx": true }` collects every response >= 500 from the
step's first action to its landing guard and records one row before
any bail-out (action failed / not reached); seal() removes the
listener. Opt-in, so existing journeys are unchanged.
validate-journeys.js accepts `back` and checks no5xx is a boolean;
journey-examples.md documents both.
Field evidence (reporter's project, Mendix 11.14): Back journey
60 PASS / 2 FAIL on the defective build, 62/62 after the fix.
Fixture: tests/wave2/test-journey-back-no5xx.sh 10/10 (original 0/4);
validate-journeys --selftest 25/25; journey fixtures, selftest and
rung4-scope pass.
Not done: making no5xx the default and a positive-control mutant for
it (the issue's asks 2-3) — they change results for existing journeys.
Fixes #564
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…to edit by hand The check tested settings.json per line, so a single-line file holding the installed (CLAUDE_PROJECT_DIR) form and a relative form passed. Each "command" string is now split onto its own line first. A hand-written variant, which install-claude-permissions.sh --hooks-only never rewrites, now gets an "edit it by hand" note next to the --hooks-only fix. L8-L9 in test-look-hook-cwd.sh (fail on master, 9/9 with the fix); test-look-ledger-hook-repair 13/13, test-doctor-gate-selftest 39/39. Part of #502 (the doctor item; the other follow-ups stay open). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…statuses conformance-check.sh kept only ledger rows whose pointer starts with "/", so the single-file multi-BRD ledger brd-to-build-plan.md writes (F002/modules/0) exited 2 as "an index, not a ledger", and its `not built` and `blocked (..)` statuses read UNKNOWN-STATUS. Accept a BRD prefix and map both statuses to not-built. Part of #515 (review-module.sh's BRD-path lookup not included) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
Logs written within one clock tick tie on mtime, and `ls -t` breaks the tie by name ascending, so the prune could keep the oldest log; this made test-exec-gate-log case C flake under load. Sort by the time-stamped file name instead, and make case C deterministic. Fixes #505 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
BRDs that carry identifiers as domainEntities[].name / pages[].name gave facts-lock nothing to harvest, so a respelled entity across BRDs went unnoticed. Read `name` inside identifier-bearing arrays into a separate set and report disagreeing spellings as WARN lines; never frozen, exit codes unchanged. Fixes #519 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
From the reporter's comment on #522: `back` takes no required fields; `timeout`, if present, is a positive number. `back` and ui.no5xx were accepted in the #564 commit. offline/online and notMeasurableWhen are NOT accepted: the toolkit runner does not implement them (#521), so the "unknown action — the runner throws" message is still true here. validate-journeys --selftest 26/26; test-validate-journeys-spans 15/15; test-journey-back-no5xx 10/10. Refs #522 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
The leak guard (check-no-client-data.sh) blocks CJK characters in tracked files; test-monkey-oracle.sh (#544) carried the payload literally. Same string, as monkey.js's own PAYLOADS writes it. test-monkey-oracle.sh 14/14; leak guard clean (1185 files). Refs #544 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…-changing git pull/checkout The restatement guard's ledger only saw exec.sh writes, so a pull that brought newer model work in left it saying "05 wrote last" and a replay of 05 over that work stayed quiet. install-project-hooks.sh now installs post-merge + post-checkout hooks that append a RESTORE row (as restore-mpr.sh does) when the operation changed the .mpr or mprcontents/. Squash merges and file checkouts give the hook no range, so they always mark: the cost is one capped DESCRIBE round. Fixture test-restatement-git-hooks.sh: real git, both layouts, chained foreign hook, idempotent re-install; 26/26, and the #504 repro fails on master. test-model-stamp 35/35, test-mx-metadata-note 40/40, test-restatement-guard 58/58. Not done: restore-mpr.sh taking the exec lock (optional ask) — draft PR #379 moves the lock into _common.sh; do it on top of that. Fixes #504 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
This was referenced Oct 26, 2026
[retro 2026-10-12] Atlas / Datagrid 2 / watch-mode traps that cost fix rounds in all three apps
#282
Closed
MendixMau
pushed a commit
that referenced
this pull request
Oct 28, 2026
…via a088b4e); keeps the push fast-forward
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
One PR for the nightly bug sweep. There is one commit per issue so it can be reviewed by area. It is batched because a separate PR per fix would serialize ~25 CHANGELOG conflicts at ~30 min CI each.
Every code fix adds a fixture case that fails on master and passes here. Only scoped fixtures were run, per CLAUDE.md. Each commit carries its own CHANGELOG line.
Gates / verify
create page if not existsas the page name and reports a present wireframe as missing #517 check-page-shell readscreate page if not exists.VM_TMO_*override, and on timeout the Python child survives, writespage-scope.jsonlater, and the design audit has already read the stale one #541VM_TMO_PAGESCOPEoverride, kills the whole timed-out process tree, atomicpage-scope.json.journeys/<Module>.journey.json; a module that keeps one journey per file underjourneys/<Module>/gets FAULT "no journeys/<Module>.journey.json" #542 journeys folder formjourneys/<M>/*.journey.json.--module: a single-filecoverage-ledger.mdis measured against every BRD in the project, so BRDs the module never claims read fully UNCLAIMED, and leaves other modules claim read UNCLAIMED too #543 a per-module ledger is scoped to the BRDs it names.not built/blockedstatuses that brd-to-build-plan.md sanctions, then calls the ledger 'an index, not a ledger' #515 BRD-prefixed pointers andnot built/blockedstatuses.namekeys, then check reports "agree with all 0 frozen fact(s)" #519 name-keyed identifiers, WARN only.Runners / monkey / design-audit
typeSafely()writes the value through the native setter, bypassing the input'smaxLength, so every length-capped text box yields a crash-class HTTP 560 that no user can reach #544 typed payload cut to maxLength.slowfinding, not crash-class.button-name(critical,x1)withevidence: [], so the failing element has to be found with a hand probe; axe already returns the selectors #561 a11y findings name the failing element.mustFailcan only matchdata.oqllabels;outcome.labelis never used in a check name, so a control tagged there always reads NOT PROVEN #538outcome.labelreaches the check name.--positive-controlruns every mutant back to back on the same data: a journey whose action consumes its seed state leaves the later mutants INVALID at "seeds resolved", and the control row then says "BROKEN PRECONDITION WENT GREEN" #560 (part) a mutant that never ran reads INVALID.locator.isVisible({ timeout }), which never waits: the 12 s budget is not applied, so a page slower than the per-action settle reads NOT-REACHED #536 (rest)visibleWithin()at the 4 remaining sites.{ "do": "back" }and"ui": { "no5xx": true }) #564{do:"back"}and opt-inui.no5xx(reporter's patch, ported).back.timeoutvalidation.Doctor / lint / status
.mpr.lockis left out of the self-test scratch copy..claude/lint files are git-ignored.settings.json.Skill text (on-demand only)
execis all or nothing; STOP #22, learned-detection-gaps, iterative-build-loop and exec.sh still say it is "not transactional", and the "non-idempotent statement last" pattern no longer works #539 v0.27+ exec is all-or-nothing. STOP Docs: "Where you run this" visual (guide §5, README, SVG) and the Docker-on-WSL2 / lanes-mix notes #22 is reworded; baseline 63,877 → 63,872 words (render-routing.sh --check).Not in this PR
These are DISCUSS or roadmap items: #518 (can flip PASS→FAIL on 26/55 wireframes), #524 rest, the #564 default-on, #148, #521 (separate PR), and the remaining items of #560 and #502.
Field proof gap
None of the runner changes have been run live against a Mendix app. The #564 patch has the reporter's own field run (60/2 → 62/62).
Generated by Claude Code