From faf196eee8fc5132dcc05567bf88318a5366038c Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 13 Oct 2026 13:06:37 +0000 Subject: [PATCH 1/9] e2e: read OQL rows by alias; liveness for negative-only span claims; APP-DOWN between journeys #154: helpers.js built OQL rows with Object.values(r) and oqlScalar read rows[0][0]. mxcli v0.26.0 prints keys alphabetically, omits an all-null column and, over a view entity, adds ID beside the alias, so columns shifted and a view's count read as its ID. The brace counter ignored strings, so a value holding ] or } returned null. Rows are now keyed by the parsed SELECT aliases (SELECT order, explicit nulls), oqlScalar reads the first alias, new oqlRows, string-aware slicing. Golden: the released v0.26.0 binary's verbatim output against a stub admin API (tests/wave2/fixtures/oql-json/); test-oql-rows.sh 15/15, 0/15 on master. #150 remainder: a mustNotFire-only step with zero spans was INVALID on every run. Rung 2 (now traceRung) waits the full window and requires a declared spans.liveness span or any service span since the journey began (otel.js liveness) before judging; the trace-negative mutant injects the forbidden name after that check. #285 harness half: probe baseUrl before each journey (APP-DOWN, not walked) and after each (flag its FAIL rows). APP_PROBE=0 disables. test-journey-liveness.sh 27/27 over the captured Jaeger trace. No live-app field run yet. Closes #154 Refs #150 #285 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw --- CHANGELOG.md | 2 + project-tests/e2e/helpers.js | 151 ++++++++++--- project-tests/e2e/journey-runner.js | 181 +++++++++++++--- project-tests/e2e/otel.js | 32 ++- skills/journey-proof.md | 36 +++- skills/learned-db-assertions.md | 23 ++ .../wave2/fixtures/oql-json/admin-api-stub.js | 27 +++ tests/wave2/fixtures/oql-json/allnull.stderr | 2 + tests/wave2/fixtures/oql-json/allnull.stdout | 6 + tests/wave2/fixtures/oql-json/bracket.stderr | 2 + tests/wave2/fixtures/oql-json/bracket.stdout | 6 + tests/wave2/fixtures/oql-json/cases.txt | 7 + tests/wave2/fixtures/oql-json/nullcol.stderr | 2 + tests/wave2/fixtures/oql-json/nullcol.stdout | 12 ++ tests/wave2/fixtures/oql-json/view.stderr | 2 + tests/wave2/fixtures/oql-json/view.stdout | 6 + tests/wave2/test-journey-liveness.sh | 198 ++++++++++++++++++ tests/wave2/test-oql-rows.sh | 131 ++++++++++++ 18 files changed, 770 insertions(+), 56 deletions(-) create mode 100644 tests/wave2/fixtures/oql-json/admin-api-stub.js create mode 100644 tests/wave2/fixtures/oql-json/allnull.stderr create mode 100644 tests/wave2/fixtures/oql-json/allnull.stdout create mode 100644 tests/wave2/fixtures/oql-json/bracket.stderr create mode 100644 tests/wave2/fixtures/oql-json/bracket.stdout create mode 100644 tests/wave2/fixtures/oql-json/cases.txt create mode 100644 tests/wave2/fixtures/oql-json/nullcol.stderr create mode 100644 tests/wave2/fixtures/oql-json/nullcol.stdout create mode 100644 tests/wave2/fixtures/oql-json/view.stderr create mode 100644 tests/wave2/fixtures/oql-json/view.stdout create mode 100644 tests/wave2/test-journey-liveness.sh create mode 100644 tests/wave2/test-oql-rows.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index b46921d3..9e69376c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ Sections dated before 2026-09-19 predate the cycle and stay as they are. ## Unreleased +- fix(e2e): **`helpers.js` reads OQL rows by SELECT alias, never by position.** `mxcli oql --direct --json` prints keys alphabetically, leaves out a column that is null in every row, and over a view entity adds `ID` beside the alias. `Object.values(r)` therefore shifted columns, and `oqlScalar` returned a view row's ID instead of its count; a string value holding `]` or `}` truncated the brace-counting slice, so a real answer read as "no measurement" ([#154](https://github.com/MendixMau/mxcli-project-toolkit/issues/154), card-disbursement build). Rows are now keyed by the parsed SELECT aliases in SELECT order with explicit nulls, `oqlScalar` reads the first alias (null rather than a guess when the list has no alias), new `oqlRows`, string-aware JSON slicing; the admin preflight uses the same parser. Golden: the released mxcli v0.26.0 binary's verbatim stdout/stderr for four queries against a stub admin API (`tests/wave2/fixtures/oql-json/`); fixture `tests/wave2/test-oql-rows.sh` (15 cases, 0/15 on the old helper). No live-app field run yet — MendixMau +- fix(e2e): **a negative-only span claim is judged against a liveness reference, and an app that dies mid-suite reads APP-DOWN, not FAIL.** A `mustNotFire`-only step (Cancel on a reset confirmation) captures zero spans, which also happens when Jaeger is down, so it was INVALID on every run and its control mutant was unsupported ([#150](https://github.com/MendixMau/mxcli-project-toolkit/issues/150)). Rung 2 now waits the full window and requires a declared `spans.liveness` span or any service span since the journey began (`otel.js liveness`); no evidence stays INVALID. The `trace-negative` mutant injects the forbidden name after that check. Between journeys the runner probes `baseUrl` (3 tries); down before a journey → `APP-DOWN` INVALID, not walked; down after one → its FAIL rows are flagged ([#285](https://github.com/MendixMau/mxcli-project-toolkit/issues/285) harness half; a watch rebuild took a runtime down mid-suite on 2026-10-12). `APP_PROBE=0` disables it. Fixture `tests/wave2/test-journey-liveness.sh` (27 cases over the captured Jaeger trace and a real local HTTP server); main-loop wiring not fixtured (needs a browser), no field run yet — MendixMau - feat(lint): **Lint Batch 3 — TXT001 build-process words in user-visible text, TXT002 non-ISO dates in user-visible text, UI001 Data grid 2 / Atlas input layout traps.** From the 2026-10-12 UX-fix retros ([#280](https://github.com/MendixMau/mxcli-project-toolkit/issues/280), [#282](https://github.com/MendixMau/mxcli-project-toolkit/issues/282), [#276](https://github.com/MendixMau/mxcli-project-toolkit/issues/276)): leaked words reached 3 of 3 apps and non-ISO dates 2 of 3, each past a one-off glossary grep; a list view in a grid column and a width on an Atlas input each cost fix rounds. Warning severity, `_rule` finding on a missing field, an empty `strings()` under a FULL-catalog rule, or vocabulary that matches nothing; 23 cases in `tests/lint-rules/test-batch3-rules.sh` (harness gained a `strings()` mock). Field run (mxcli 0.26.0, 21-module Mendix 11.12 model): 0/0/0 over 478 user-visible strings and 271 widgets, with loosened positive controls returning 27/50/17 through the same accessors. TXT002 cannot see format strings inside expressions — that half is a blocked row. `process/lint-backlog.md` Batch 5 lists all 17 candidates from the three issues (rows 32–48) — MendixMau - new(process): **feedback typed mid-build gets a change log in `PROJECT.md`, written before any edit, and the BRD/decision/architecture/wireframe is edited before the MDL.** Across 12 mid-build changes on real projects, 12 went straight into MDL and 0 updated a BRD, build plan or wireframe; the drift-sync `UNSYNCED` marker was never written once, and its absence is invisible, so every gate passed on silence. At the other extreme, one already-settled entity change cost ~270k tokens through two helper agents, and one screenshot-driven fix took 4 rounds because it regressed twice. New `skills/change-intake.md` (baseline, lead+ba, Stages 2–7; routing trigger "the user gives feedback or asks for a change mid-project"): one `## Change log` row per ask (`CR | Date | Source | Verbatim ask | Class | Size | Entry artifact | Status | Closed-by`), six classes, each mapped to its entry artifact (a decision is superseded by a new row, never edited; a built page's visual change is recorded as a before/after screenshot pair instead of wireframe upkeep; impl/bug need only a regression journey). Ceremony is proportional: a small change the user typed gets a one-line receipt and no question, a medium one gets one batched question at the next module gate, a large one or one that contradicts a CONFIRMED decision is asked and stopped on, and stakeholder asks wait for the user. Statuses run open → refined → agreed → applied → proven, or rejected. `bin/lib/change-log.sh` holds the one template and the parser: `init-project.sh` writes the section, `sync-project.sh` appends it once to older projects, and `gate-check.sh` prints a **warn-only** `Change log:` line plus a dashboard row (rows not yet applied, N of M; applied/proven rows with no Closed-by; unrecognised statuses). It becomes blocking only after two projects' counts match a hand count. `project-bin/exec.sh --cr CR-NN` tags the BUILD-LOG detail cell (metrics-ledger columns unchanged). Ownership contradiction fixed: the lead marks; ba-agent flushes BRDs and briefs; architect-agent flushes wireframes and `architecture/` (runbook §3b, `iterative-build-loop.md`, `agent-roles.md`, both stubs, `close-the-loop.md`). Inbox TD-04's change-loop half is promoted here, and its row is narrowed to the two unpromoted items. Fixture `tests/wave2/test-change-log.sh` (39 cases, PROJECT.md built by the real init) — MendixMau - feat(exec): **per-project exec lock with stale takeover, opt-in `--commit-first`, a post-exec "restart needed / watch can apply this" verdict, a scoped `bin/app-restart.sh`, and `bin/test-scratch.sh` for `mxcli test` on a locked copy** ([#287](https://github.com/MendixMau/mxcli-project-toolkit/issues/287) items 3-4, [#284](https://github.com/MendixMau/mxcli-project-toolkit/issues/284), [#275](https://github.com/MendixMau/mxcli-project-toolkit/issues/275), [#289](https://github.com/MendixMau/mxcli-project-toolkit/issues/289) items 1-2, [#285](https://github.com/MendixMau/mxcli-project-toolkit/issues/285), [#278](https://github.com/MendixMau/mxcli-project-toolkit/issues/278) recipe half). In a 20-task UX-fix field run over three apps (2026-10-12), 57 of 148 `exec.sh` runs applied nothing (26 refused on uncommitted model changes, 15 gate failures, 16 mxbuild exit 1), a machine-wide `pgrep "mxcli exec"` guard blocked an exec because another project was writing, watch mode silently missed recreated microflows, grants, attributes, pages, page URLs and theme SCSS/JS (~26 restarts), and 24 implementer restart-resumes cost 41.6M tokens because only the lead could restart apps. `exec.sh` now locks per project (atomic, `