Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@ moment updating it became a separate chore). One line per change:
Kinds: `new` · `fix` · `learn` (a skill/learning) · `process` (rules, templates, CI).
Credit the person or project that surfaced the change — the credit line is the thank-you.

## 2026-09-10
- fix(bug-logs/mxcli-bugs, learned-mdl-preflight): **the `marketplace install` STOP (#879) is LIFTED — fixed upstream in v0.21.0, and this toolkit told four days of sessions otherwise.** Install no longer shells out to `mx module-import`; it copies units with mxcli's own writer and MPR v2 survives, with the destructive path now opt-in behind `--allow-format-change` so the corruption can only be produced deliberately. Re-probed 2026-09-10 on a real 501-unit split-model project: **501 → 1075 `.mxunit`, `.mpr` 84 KB → 156 KB** (an index, not the 35 MB blob this bug used to produce), native mxbuild **0 errors**, app boots, two e2e journeys unchanged. **The cost of not re-probing is the finding, not a footnote:** v0.21.0 shipped 2026-09-06 and the project carried *"marketplace install is BLOCKED, needs a human in Studio Pro"* in its register until 2026-09-10 — with both `.mpk` files already downloaded and sitting in the project root the whole time, because the blocker was never the download. `retesting-learned-rules.md` exists for exactly this and nobody ran it; **a STOP is a claim about a binary version and it expires.** Also records the zero-risk way to re-probe a formerly-corrupting command on a real project — `git clone --depth 1 file://$(pwd) /tmp/probe`, install into the clone, count `.mxunit` and run `mx check` there, decide from the measurement — which is cheaper than the documented recovery and answers what a changelog cannot. **Three new traps replaced the old one, all live on v0.21.0 and none self-announcing:** (1) marketplace packages **do not carry their dependencies**, and the failure is not "module missing" but 406 individual `CE1613` element errors — the aggregation one-liner that turns that wall into a shopping list is in the entry, and the closure for Email Connector 6.4.3 is MxModelReflection + Encryption + CommunityCommons, which checks at 0; (2) the two `mxcli fix` repairs the installer prints are **mandatory, not advisory** — 128 units and 12 units changed on the confirming run, and both exist precisely because Mendix's own tools would collapse MPR v2 without them; (3) a **bundled widget can silently fail to land and the installer cannot self-repair it** — `widgets/RichText.mpk` landed on the probe and not on the real run (33 vs 34 widgets, 3 × CE0462 over an otherwise clean model), a re-run refuses with *"already installed"*, and the repair is to `unzip -o -j` it out of the `.mpk` the installer already downloaded, so **count `widgets/` before and after every install**. One thing genuinely still needs Studio Pro and is now scoped rather than assumed: SAML + UserCommons install cleanly but leave `CE0066` ("Entity access is out of date"), there is no `mxcli fix security`, and an MDL `GRANT` was tried and does not clear it — Maurits Visser, from a MOC/PSSR app replacement
- learn(learned-css-that-never-applied): **the difference between a UI the user called "poor" and one they called "much better", same day, same design system, was that the first pass verified the SCRIPT EXECUTED and the second verified THE PIXEL CHANGED.** Everything green in the first pass was true and irrelevant. Three ways a perfectly correct rule paints nothing, all three met in one field run on a MOC/PSSR app replacement, 2026-09-10: **(1) matches nothing** — `ds.css` styled `.ds-tablewrap`/`table.ds-table`, but DataGrid2 renders a row as `<div class="tr">` and there is no `<table>` on any page, so not one table rule had EVER applied, through a full design port, two build phases, mxbuild clean, lint clean and two journeys green; and three top-bar selectors (`.navbar`, `header.navbar`, `.mx-layoutgrid-fluid`) were guessed in one sitting and all three matched zero elements, where one read of the live element chain named the real carrier `.mx-scrollcontainer-top.region-topbar`. **(2) matches too much** — the instinct after (1) is to widen, and `.mx-page { background }` painted the nav bar with it: white menu text on a white bar, an invisible top nav. **(3) matches and loses the cascade** — `.mx-listview-empty` named exactly the right element, sat ~11,000 lines after Atlas in the compiled sheet, and still lost: Atlas ships `.mx-listview > ul .mx-listview-empty { border-style: none; background-color: transparent }` at **0,2,1** against a bare class's **0,1,0**, so source order was never consulted; and that declaration means Atlas is *erasing* the element, not merely failing to style it. The diagnostic is two reads before you touch the rule — computed style, then (only if not found) a six-level `parentElement` walk printing tagName+classList — and the three possible answers have three different fixes, so **a blind rewrite would have been wrong in all four field misses, and in case (2) the rewrite WAS the outage**. Completion criterion carries a denominator: *every component class a pass claims to have shipped has one computed-style read against a named element in the running app, or is reported unverified* — the run that justifies it had row tone implemented, screenshotted and **looking fine while rendering a rejected project amber**, caught only by reading two values. Also records the check that comes first and no CSS instrument can see, because nothing is wrong with the CSS: `check-design-reaches-app.sh` counts classes that ARRIVED in the built sheet, and at the moment the user called the UI poor, four complete semantic tint sets, a five-step elevation scale and a styled empty state were all present, all correct, and referenced by **zero widgets** — the design system was finished and the app was grey. Measure it as *N of M component classes have at least one carrier in the model*; the fix for a zero-carrier class is never to rewrite it, it is to bind it. Three of the five improvements the user reacted to were pure binding of CSS already sitting in the file — Maurits Visser, from a MOC/PSSR app replacement
- learn(learned-mdl-cannot-express): **when MDL cannot set a class, CSS usually can — check before you go looking for the property.** A UI spec carried per-row status tone on three grids as an `M`-sized MDL task prescribing `DynamicRowClass`, a property that exists in neither MDL nor Studio Pro; it had been written months earlier against an imagined API, the same defect as an instrument built against imagined input. The requirement was met with **zero MDL**, because whatever class MDL *can* bind is a hook the stylesheet reads from anywhere in that element's subtree: every grid already bound `DynamicCellClass: 'ds-statecell ds-statecell--<state>'`, so `.tr:has(.ds-statecell--rejected) > .td` gave three pages row tone with no script, no exec and no gate run. Same move fixed a second item the same day — `.ds-card > .ds-cardhead` is unwriteable from a page because a Mendix class lands on its own element only, and `.ds-card:has(> .ds-cardhead) { padding: 0 }` says it. Two caveats: **source order inside your own rule set becomes load-bearing** (an overview row carries two status cells, matched several rules at equal specificity, and rendered a rejected project amber until the rules were reordered weakest-claim-first), and degradation where `:has()` is unsupported is silent and benign — the selector never matches and you get today's appearance, which is why it must be confirmed by value read and not by eye — Maurits Visser, from a MOC/PSSR app replacement
- process(skill-routing): `learned-css-that-never-applied` routed **baseline** for mdl/review/gate at stages 5–6, trigger-phrased on *"a style change that appears to have done nothing, or an app still grey after a design port every instrument called green"*. Baseline rather than situational on this repo's own rule that a skill living only in the situational table goes unnoticed by projects that are not hunting for it — and not being reached is precisely what this one records — Maurits Visser, from a MOC/PSSR app replacement

## 2026-09-09
- new(project-bin/page-fidelity.js): **`class="bound"` — the wireframe author saying "this text is a sample of bound data".** The scorer already had this concept and applied it structurally: `<td>` is excluded from the text corpus because a wireframe's table cells are sample ROWS and a page that correctly BINDS them contains none of that literal text. The same is true of a bound value anywhere else on the screen, and there the structure gives nothing away — an `<h1>` holding a record's number and name looks exactly like an `<h1>` holding page copy, and a chip holding a filename looks exactly like a chip holding a label. Measured on a MOC/PSSR app replacement's project detail page, 2026-09-09: **54%**, and all three misses were sample values the page could not contain — the record's own title, and a mocked attachment's filename, twice. The page was right; the denominator was wrong, and the number was about to be read off as a gate verdict. So the marker is **DECLARED, not guessed**: an element carrying `bound` leaves both the text corpus and the class denominator, and guessing was the alternative and does not work — a heading is bound or it is not, and only the person who drew the screen knows which. Put it on the smallest element that holds only the value (`<h1 class="bound">` leaves no heading behind; `<span class="bound">` inside a chip leaves the chip). Fixture grows to **18 assertions** including that a bound heading leaves the DENOMINATOR rather than merely stopping being reported as missed — otherwise the score would be 1 of 2 and still look clean. Known-bad control without the marker: **5 of 18 fail**. Same page scores 100% (3/3 headings, 2/2 content) with it — Maurits Visser, from a MOC/PSSR app replacement
- process(bug-logs): BUG-114 filed upstream as mendixlabs/mxcli#1076 with BUG-118 as its second reproduction; both drafts and the ledger header stamped FILED — the toolkit merge queue
- fix(project-bin/page-fidelity.js): **structure classed as bound data, and the score of record silently going `null%` again.** A wireframe's own `<style>` defines two very different kinds of class — BOUND-DATA MOCKS (a repeated region of sample rows, whose literal text a correctly *binding* page contains none of) and STRUCTURE (the wrapper, the page header, the toolbar — furniture the page script genuinely must declare) — and the classifier **drops a mock's whole subtree**, so a misclassified structural class deletes page content from the denominator. The test was `uses === 1 && kept < 0.4`, once-used AND dominant, which contradicts the paragraph directly above it stating that a mock is a **repeated** region: a once-used class whose subtree was *small* fell through the second conjunct and was dropped as sample data. Measured on a MOC/PSSR app replacement's project overview, 2026-09-09: `.page-head` (uses=1, kept=0.513) was deleted **with the page's only `<h1>` inside it**, `.toolbar` (uses=1, kept=0.825) with it, and every dimension reported `0 of 0` — which normalizes to **`null%`**, so the run printed a clean report over an empty corpus. That is the same silent-null failure this file's own header note says was worth fixing, arriving a second time through the other conjunct, on a page that scores **100%** once the page is not gutted. The threshold is **removed rather than retuned**: it was a guess, and any value for it splits once-used wrappers on a measurement that has nothing to do with whether their content is bound data; a repeated region is still a mock at any size, which is the half that was always right. New fixture `tests/wave2/test-page-fidelity-mocks.sh`, **14 assertions**, with two captured wireframe shapes and a `CAPTURE.md` stating that only literal text and class prefixes were changed. Its **first assertion is that the score is not `null`, not that it is high** — a null on a wireframe that draws an `<h1>` means the scorer gutted the page, whatever the eventual percentage. Proven against a known-bad control carrying the old rule: **8 of 14 fail** — Maurits Visser, from a MOC/PSSR app replacement
- learn(workflow-structure-rules, learned-workflow-patterns): **two workflow signatures that `mxcli check` passes clean and the native build rejects**, plus a v0.21.0 re-probe of the four constructs a real approval chain needs. (1) **A user task's `PAGE` must take a `System.WorkflowUserTask` parameter, not the workflow's context entity** — a context-parameterised page passes `mxcli check --references`, execs, round-trips through `DESCRIBE`, and the native build then says *"The selected page 'X' should accept a parameter of type 'WorkflowUserTask', but expects parameters of types 'MOCProject' instead"*. (2) **A targeting microflow must accept TWO parameters, `System.Workflow` AND the context entity** — one parameter is the natural thing to write and it is wrong. Neither signature appears anywhere in `mxcli syntax workflow`, whose own targeting example is `TARGETING MICROFLOW HR.GetApprovers` with no signature stated. **The expensive half is the planning consequence: the task pages are a PREREQUISITE of the workflow row, not a later UI row** — a plan that builds the workflow at row 41 and its task pages at row 45 cannot make row 41 green, which is exactly how one project's Phase 7 was ordered. Also: with the signatures right, user task + targeting microflow, **multi-user task**, `CALL MICROFLOW` with a quoted `WITH`, and a **backward `JUMP TO`** inside an outcome all build clean on v0.21.0. That result is only worth having because **the same run included the construct known to be broken as a control**: a scripted `DECISION` passed `mxcli check`, printed `Created workflow`, and left the project unopenable (`StorageLoadException` → `BUILD FAILED`), so BUG-76 is open on v0.21.0 and the probe demonstrably distinguishes working from broken. A probe with no known-bad control cannot tell *"it works"* from *"the probe is blind"* — this repo has already published one wrong conclusion for that exact reason (BUG-121) — Maurits Visser, from a MOC/PSSR app replacement
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,7 @@ The "When to use which skill" table above is *situational* — load a skill when
| Before calling any module tested — what testing a module means, and the false-green register of confirmed ways a test reports green over a broken feature | `skills/testing-shape.md` |
| Finishing any module — before calling it done. One command that runs every instrument and keeps "instrument faulted" apart from "feature failed"; in a wired project run the installed copy at bin/verify-module.sh | `project-bin/verify-module.sh` |
| Any time an exit code, a tool's output or a subagent's report is about to become a stated finding — verify before you conclude | `skills/tool-output-is-not-ground-truth.md` |
| A style change that appears to have done nothing, or an app still grey after a design port every instrument called green — the three ways a correct rule paints nothing (matches nothing / matches chrome / loses the cascade), the two reads that tell them apart, and the class that arrived in the stylesheet and is bound to no widget | `skills/learned-css-that-never-applied.md` |
| Before trusting a green check/exec/DESCRIBE result as proof, or when a runtime symptom appears over a fully green model — the register of constructs that pass early rungs and fail later ones | `skills/learned-detection-gaps.md` |
| Creating any entity, or calling a module security-ready — entity and grants land in one script, and ready means SHOW SECURITY MATRIX proves it | `skills/security-is-not-a-later-script.md` |
| A CE error or behavior that looks like a known mxcli quirk rather than a modeling mistake — `bin/bug-lookup.sh CE0117` / `BUG-102` / "keyword" prints the matching ledger entries, so the session reads one entry, not the 32k-word ledger | `bin/bug-lookup.sh` |
Expand Down
1 change: 1 addition & 0 deletions ROUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ picks the row up. That is the whole procedure — there is no second list to rem
| After drafting and again after exec'ing any page script — scores the page MDL (or `mxcli describe` output on stdin) against its wireframe: headings/actions/content/classes, weighted. The scored companion to check-page-shell's binary gate; 32% median measured without it, 90% first-draft with it. Every run is appended to the project's docs/PAGE-FIDELITY.tsv — first non-stub row per page = first-build score of record vs the ≥80% target (forward-reference stubs score with --stub, exempt) | `project-bin/page-fidelity.js` | mdl,gate,review | 5 | baseline |
| Designing the brand and ONE ANNOTATED WIREFRAME PER SCREEN before building pages — the design system alone is half the deliverable | `skills/design-artifacts.md` | architect | 3 | ondemand |
| Before a wireframe or a design commits to a WIDGET — and when a page script hits a parse error that looks like a syntax mistake: the short list of things MDL cannot write at all, and the four-minute probe that answers it at Stage 3 instead of at build time | `skills/learned-mdl-cannot-express.md` | architect,design,mdl | 3,5 | ondemand |
| A style change that appears to have done nothing, or an app still grey after a design port every instrument called green — the three ways a correct rule paints nothing (matches nothing / matches chrome / loses the cascade), the two reads that tell them apart, and the class that arrived in the stylesheet and is bound to no widget | `skills/learned-css-that-never-applied.md` | mdl,review,gate | 5,6 | baseline |

#### Build — the loop itself

Expand Down
1 change: 1 addition & 0 deletions agents/gate-agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ own bug log before running anything you have not run here before.
| `skills/testing-shape.md` | Before calling any module tested — what testing a module means, and the false-green register of confirmed ways a test reports green over a broken feature |
| `project-bin/verify-module.sh` | Finishing any module — before calling it done. One command that runs every instrument and keeps "instrument faulted" apart from "feature failed"; in a wired project run the installed copy at bin/verify-module.sh |
| `skills/tool-output-is-not-ground-truth.md` | Any time an exit code, a tool's output or a subagent's report is about to become a stated finding — verify before you conclude |
| `skills/learned-css-that-never-applied.md` | A style change that appears to have done nothing, or an app still grey after a design port every instrument called green — the three ways a correct rule paints nothing (matches nothing / matches chrome / loses the cascade), the two reads that tell them apart, and the class that arrived in the stylesheet and is bound to no widget |
| `skills/learned-detection-gaps.md` | Before trusting a green check/exec/DESCRIBE result as proof, or when a runtime symptom appears over a fully green model — the register of constructs that pass early rungs and fail later ones |
| `skills/security-is-not-a-later-script.md` | Creating any entity, or calling a module security-ready — entity and grants land in one script, and ready means SHOW SECURITY MATRIX proves it |
| `bin/bug-lookup.sh` | A CE error or behavior that looks like a known mxcli quirk rather than a modeling mistake — `bin/bug-lookup.sh CE0117` / `BUG-102` / "keyword" prints the matching ledger entries, so the session reads one entry, not the 32k-word ledger |
Expand Down
Loading
Loading