Skip to content

row-groups: remind when Row groups is on but a script names no plan row - #582

Merged
MendixMau merged 73 commits into
masterfrom
claude/loving-gates-hauc1n
Oct 28, 2026
Merged

MendixMau merged 73 commits into
masterfrom
claude/loving-gates-hauc1n

Conversation

@MendixMau

Copy link
Copy Markdown
Owner

What

With Row groups: on, a script that names no build-plan BUILD row used to exit 3, "not checked", which nobody saw. Now row-groups.sh check exits 4 with a hint: start the script with -- rows: N (or -- rows: N,M,… for a group). exec.sh prints that hint as a ⚠ warning and notes rows: no -- rows: header (not grouped) in the BUILD-LOG row. It never refuses.

Why

In the #581 A/B (purchase-requests app, Sonnet, 2026-10-27), the build with Row groups: on wrote 31 scripts numbered on their own sequence (052-…, 076-…), none with a -- rows: header. All 31 read "not checked", so row grouping never ran once. The speed gain in that run came from the lint diff and hot reload, not from grouping. Projects that switch grouping on should be told when it isn't taking effect.

Impact on existing projects

  • Row groups off (the default): nothing changes. Exit 3 stays exit 3, and no new output.
  • Row groups on: one warning line per un-headed script, plus a note in the BUILD-LOG row. No refusals, and exit codes of exec.sh are unchanged.
  • Always-loaded skill text: +0 words. The reminder sits in the instrument output, at the moment it's needed.

Tests

tests/wave2/test-row-groups.sh G4 (new):

  • opted in, a script numbered past the plan → exit 4 with the hint;
  • opted in, an unnumbered script → exit 4;
  • not opted in, the same script → still exit 3.

The first two fail on the previous row-groups.sh. Full fixture: 20/20. check-scripts and check-pr-discipline are clean.


Generated by Claude Code

claude added 30 commits October 26, 2026 20:35
…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
claude added 28 commits October 26, 2026 21:12
Review follow-up: the #564 fixture checked the functions and the wiring
by inspection only. It now also walks a three-step journey through
runJourney() in headless Chromium against a localhost stand-in app:
a /xas/ POST answered 560 behind a page that still lands gives
reached PASS + no5xx FAIL naming the 560; Back lands home, no 5xx;
Back on a first page throws "Back left the app". SKIPs without a
Playwright browser. journey-runner.js exports runJourney and results
for this. 12/12.

Refs #564

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
… message is conditional

Review follow-ups on #578. doctor: when JAVA_HOME was set in a loaded
toolkit.env, point at that file, not the shell profile. exec: "no statement
is in the model" only when mxcli printed "Nothing was written" -- a failed
rollback (cmd_exec.go) can leave the project partly updated.

Refs #576, #539

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
# Conflicts:
#	CHANGELOG.md
#	tests/wave2/test-verify-module-446.sh
…ister row (#565)

New register row: an object created in a page-triggered microflow and
saved only via commitInSeparateDatabaseTransaction passes every model gate
and forward-only journey; after browser Back the runtime refuses every
request ("Attempt to illegally add an object to the state", HTTP 560) for a
role without Create. +81 baseline words (render-routing --check 63,877 ->
63,958).

Short A/B, 6 reps per arm, gate role, planted sign-off task: M found the
Back defect 0/6 (mentioned Back 1/6), T 6/6 with the illegal-state symptom
and the rollback-refresh fix; read_all 36/36; no metric worse.
Results: tests/behaviour/results/2026-10-27-baseline-adds.tsv

Refs #565

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…#567)

A hand-written step() that returns a defect string reads PASS when the
runner treats only a throw or false as failure (5 false-PASS rows in one
cook-off). +51 baseline words (render-routing --check 63,877 -> 63,928).

Short A/B, 6 reps per arm, test role: both arms caught the defect 6/6
(ceiling); with the row, 6/6 recommended journey-runner.js against 0/6,
which is the issue's point (the harness lessons do not reach hand-written
scripts). read_all 12/12, no metric worse.
Results: tests/behaviour/results/2026-10-27-baseline-adds.tsv

Refs #567

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…resolved Python in two fixtures

Review follow-ups on #578 (gates area): check-portability flagged the
guarded pgrep/pgrep -P in _kill_tree and a hard-coded python3 in the doctor
self-test fixture. test-verify-module-446: the harness-scan case (renamed
V11 after the #541/#542 cases took V9/V10) takes its own reference verdict.

Refs #541, #567

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…branches

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…ourney ids (#492)

A non-PASS data or setup row whose step name is one word ("Submit: Order +1",
"Locate: geolocation") was read as a journey id, and the rerun then exited 2
with "no journey with id Submit". A never-walked journey is now recognised only
by the row shapes the runner writes for one (app up, precondition, persona,
seeds resolved, back online at the end, a control row, an end state), and in
--rerun-failed mode ids the given journeys do not have are dropped. The
unknown-id exit 2 stays for --only. test-journey-rerun: 2 new cases, 13/15 on
the previous runner, 15/15 here.

Refs #492

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…ambiguous row (#148)

rows.filter({hasText}) is a substring match and rows.last() then picked the
last match: row "Order 1" clicked the "Order 10" row with no error. A row now
matches only when its text, or an element in it, shows the text as whole
words (cells rendered with no whitespace between them still match); the
innermost matching rows are kept, and two or more throw "ambiguous: N rows
say ...". test-journey-row-click: Order 1 / Order 10 and two-identical-rows
cases, 3/5 on the previous runner, 5/5 here (headless Chromium).

Refs #148

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
… note keys are not flagged (#522)

At edit distance 2 every 2-letter step key was "near" `ui`, and ordinary note
keys (`note`, `node`, `url`) were reported as typos, so a step with
`"note": "..."` exited 1. Keys under 5 letters now allow one edit, a swapped
pair counting as one (`nmae` is still caught); longer keys keep two. The
CHANGELOG no longer claims the issue's `notMeasureableWhen` example is
caught: the runner does not read that tag, so it is not checked. Selftest:
the note-keys case failed before, passes here; 30 rules red, 10 clean.

Refs #522

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…, need a captured mxcli

Independent review of #578 part 2:
- md5s of the project-row write, the check and head_md5 are taken with CRs
  stripped, so a Git Bash core.autocrlf checkout of stock rules is not an edit
  (it read BLIND, exit 1, before).
- rows only for names listed in STOCK-HASHES-BUNDLED.txt: a project's own
  rule is never overwritten by mxcli, and editing it read BLIND before.
- no rows when the running mxcli is not a captured version (note names it):
  its unedited rules looked edited and the next upgrade named the wrong
  remedy. File header corrected.
Fixture T16 (a, a2, b, c): 6 checks fail against the previous lint-gate.

Refs #524

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…t value; revert reads its expected value from a setting (#566)

Review follow-ups. The host check looked only at PGHOST: with PGHOST empty and
PGHOSTADDR=<any IP> (or a PGSERVICE entry) it connected anywhere. PGHOSTADDR
is now checked like PGHOST, and after connecting inet_server_addr() must be a
socket or loopback unless FIXTURE_ALLOW_HOST named the host. A NULL current
value made RETURNING NULL: the update COMMITted, then the script died "the
write matched no row" with nothing saved, so it could not be reverted; it is
now refused inside the transaction before the write. Revert's guard read the
saved value spliced into the DO block, where a `$fx$` broke it; it now reads
current_setting('fixture.expect'). T13-T15 failed on the previous template
(21/24), pass here (24/24, PostgreSQL 16 initdb cluster, run as postgres).

Refs #566

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…; sync names all hooks

Independent review of #578 part 2: with core.hooksPath set the installer
printed what to add for pre-commit and post-commit only, so those users never
got the #504 restatement-ledger marker. The advice now includes a snippet
that, pasted as post-merge, marks the ledger on a model-changing pull
(fixture: hooksPath case, both checks fail against the previous installer).
sync-project.sh dry-run wording names all the hooks it installs.

Refs #504

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
Independent review of #578 part 2: the note took the last env file that set
JAVA_HOME and ignored the loader's precedence (shell, then project
toolkit.env, then ~/.mxcli-toolkit.env), and missed `JAVA_HOME = value`.
Now the first file in loader order that sets it decides: its value equal to
JAVA_HOME names that file; otherwise the shell set it. Fixture case 14 (the
"KEY = value" check fails against the previous doctor).

Refs #576

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
… run can be repeated

Review of #578 part 2: the 2026-10-27 A/B behind the +132 always-loaded words
used session-local tasks and a session-local scorer, so nobody could re-run
it. tasks/t511.md, t565.md, t567.md and score-baseline-adds.sh (resolved
Python, AB_WORK for the scratch dir) are committed; the results TSV header
names them.

Refs #565, #567, #511

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
CI leak guard flagged t@example.invalid in test-lint-receipt-revert.sh and
the quoted PGPASSWORD default in test-state-fixture-template.sh. Use t@t like
the other fixtures, and pass the password through a short variable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
test-pipefail-grep-q flagged the #517 placeholder check: under pipefail a
grep -q that exits early can SIGPIPE the printf and flip the test.

Refs #517

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…s no plan row

In the #581 A/B every script of the Row-groups-on build was numbered on its
own sequence with no `-- rows:` header, so row-groups.sh exited 3 ("not
checked") for all 31 and grouping never ran. Opted in, that case now exits 4
with a hint; exec.sh prints it as a warning and notes it in the BUILD-LOG row.
Never a refusal. Zero always-loaded words.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
@MendixMau
MendixMau merged commit c28fc0d into master Oct 28, 2026
2 checks passed
MendixMau pushed a commit that referenced this pull request Oct 28, 2026
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.

2 participants