fix(findings): recover 13 lost pattern pages; close the digest's blind spot - #364
Merged
Conversation
87 of the 95 cmd/mxcli findings (92%) now belong to a named class. This is the tooling surface rather than the model, and the classes look nothing like the executor's. - test-runner-cannot-fail (14). The one class whose cost is confidence rather than debugging time. `@expect 1 = 2` passed; `@verify` was parsed and read by nothing but --list; --require-assertions exited 0 on a suite that asserted nothing. The mechanism is silent ABSENCE — an annotation parsed into a field no consumer reads — amplified by two result-assembly paths. The remedies that held are structural: fail closed on an annotation that cannot be honoured, one constructor and one pre-run verdict function, each pinned to a single call site. - local-loop-silence (16). The warm loop orchestrates mxbuild, a JVM, a bundler, PostgreSQL and a browser, so the thing that breaks is not the thing that reports: a missing client bundle answers HTTP 200, a dead runtime leaves the CLI spinning, and the log being captured is not the log the user needs. - styling-compiles-to-nothing (11). Nothing validates CSS. Location decides whether SCSS compiles at all, an unrecognised token is indistinguishable from a design never applied, and contrast is a correctness property no check measures. - package-operations-damage (11). Handing the project to tools mxcli does not control, and being told it went fine — the MPR v2 to v1 collapse reporting 0 errors is the worst of them. - cli-contract-defects (14). The class with no Mendix document in it. It matters disproportionately because agents take the tool's word: help that teaches unparseable syntax, an unqualified "Check passed!" that resolved nothing, a flag that parses and does nothing. Every sources: path and [[wiki-link]] verified before committing. Seed table extended and five rows appended to SYNC_LOG.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
82 of the 83 mdl/backend findings now fall under a named class. Only three pages are new: most of the area reuses classes written for mdl/executor and cmd/mxcli, which is the digest working rather than a shortcut. - engine-divergence (30). The dominant class here. Two implementations behind one interface, with the newer, less complete one as the default — so a gap is the behaviour most users get while tests formed against legacy still pass. A gap on one engine is invisible from inside that engine: everything is self-consistent, and the field that never existed is never missed. The cross-engine DESCRIBE matrix (write with A, read with B, all four) is the only check that sees it. Two failure modes and only one is honest — a refusal naming MXCLI_ENGINE=legacy costs a flag, a `-- Empty action` placeholder makes describe→exec delete the construct. The worst instance was a read that under-reported page access. - mutator-addressing (19). ALTER edits a stored document in place, which means naming a node — and DataGrid2 columns, object-list items and layout regions store no Name at all. Derived names are unstable, ambiguity is refused rather than resolved, and hand-built BSON drifts from codec-built BSON in ways only a dump-diff shows. Getting a typed-array marker wrong turns a silent no-op into an unopenable project. - access-rule-reconciliation (6). Small and graded high: GRANT looks additive and is a read-modify-write, so both widening and narrowing report success. Records two method points — the writer was innocent and a later reconcile removed the rules, and the reported trigger (WHERE) was a red herring that a scoped fix would have satisfied. The ~33 MCP/PED findings are deliberately NOT given a page: that subsystem already has architecture/mcp-backend.md and models/ped-mutation-constraints.md, and restating them would break the never-restate rule. Recorded as its own SYNC_LOG row so the omission reads as a decision rather than an oversight. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
49 of the 53 mdl/grammar findings (92%) now fall under a named class. Three pages are new; the rest reuse describe-round-trip-gaps and silent-property-drop. - capability-gap-as-parse-error (36 touched, ~20 primary). The distinctive one. Someone tries to express something Mendix supports, the parser says `no viable alternative`, and they conclude the FEATURE is impossible — a parse error is indistinguishable from a mistake they made. So the reports in this class are not feature requests, they are workarounds: an admin screen hand-rolled as five pages because a tab container was believed not to exist, "use a Java action" for a binary upload, "go to Studio Pro" as the standing answer to translation, a headless pipeline ending in a manual step. The gap is bidirectional — DESCRIBE of a document that HAS the construct must do something, and in the mapping findings it emitted MDL that parsed and rebuilt a different document, which is worse than a parse error. Also records that a narrow/wide statement pair (SET vs REPLACE) is a whitelist extended one bug report at a time, and that "not in the metamodel" is not a conclusion until the namespace is right. - keyword-collisions (22 touched, ~8 primary). The distinguishing question is how a collision fails, not whether one happens: a parse error is recoverable, a different valid parse is not — a widget conditional calling trim() was silently dropped. Records that a grammar alternative and its visitor case are ONE change (accepting -7 without the AST case serialized `[Amount > ]`), and the control-binary sweep for proving a relaxation causes no regressions. - scripts-that-cannot-rerun (5). Statement-level idempotence, kept deliberately apart from ADR-0008's write-level idempotence, which is what people usually mean when they say mxcli is idempotent. `exec` halting on the first error turns "90% already applied" into "none of the remaining 10% applied", and the silent variant — a duplicated index — is worse than the error. Coverage stated in CLAUDE.md was corrected to the measured 92% before committing; the first draft claimed 98% from memory. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
27 of the 28 mdl/visitor findings (96%). Two pages are new and one is a re-sync — the first any page has had since the initial synthesis on 2026-05-24. - expression-translation-drift (13). Deliberately distinct from platform-semantics-gaps: there the MDL is illegal Mendix, here the MDL is correct, the emitted Mendix expression is well-formed, and it says something else. The worst instance is the quietest — an additive chain rebuilt with its operators reordered, so a microflow computed a different number than its source said with mxcli check, mx check and the build all green, and the corruption in the stored document rather than in DESCRIBE. Three ways meaning is lost (a literal changes type, an operator changes, a function resolves to the wrong overload), plus the ANTLR trap behind the standard fix: GetText() excludes hidden tokens and a source-interval slice includes them, so preserving raw source inherits every comment in that span. - misleading-diagnostics (6). Graded above "the message could be clearer" because a wrong hint costs however long the reader spends acting on it: they blamed their quoting, renamed an attribute that was fine, or concluded a construct was unsupported. A hint's precision matters more than its coverage — the "unescaped apostrophe" hint matched any short lowercase word and so fired on every genuine error at `on`, `in`, `as`, `to`, `by`. - visitor-wiring-gaps — RE-SYNCED. It described one size of gap (a field); the findings show three. A field, a structure (ELSIF arms, which Mendix has no native form for and which must be lowered into nested ifs), and a whole statement that parses, exits 0 and dispatches to nothing — the last presenting as an empty result rather than a missing feature, which is what lets it survive. Added the neighbouring failure where a field is wired to the WRONG thing, which reports success and changes meaning rather than losing it. Every sources: path and every [[wiki-link]] across all 25 pages verified to resolve. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…d spot Two problems, found by running `make digest-status` on main after the stack merged. **13 pattern pages never reached main.** All six PRs report MERGED and only #356's content is on main: the stacked PRs each merged into their BASE BRANCH, which by then was no longer on the path to main. GitHub was telling the truth — they merged into what they targeted. This branch is docs/bug-patterns-visitor, which holds all 25 pages, merged with current main. Verified: 25 pages, 883 findings, every sources: path exists and every [[wiki-link]] resolves. **The digest report said 0% outstanding while 249 findings were undated.** Undated records were skipped by the "since last sync" comparison entirely, so an area could go completely undigested and the headline would still read current — the exact failure the report exists to prevent, in the report itself. Three changes: - the 249 undated findings are backfilled from git blame on the shards (mdl/executor gained 250 records from other sessions since the last pass); - an undated finding now COUNTS AS NOT DIGESTED rather than being skipped, and the headline says "not yet digested" rather than "added since", which is what it always meant; - `date` is now required by check-findings. Warning was not an option: 249 records accumulated undated, and nobody saw the warning that was not there. Two limits are documented in the script header rather than engineered away, because both make the number look better than reality: `date` is day-resolution and the comparison is strictly greater-than, so 256 mdl/executor findings carrying the sync's own date read as digested when ~250 arrived after the pages were written; and the blame-based backfill invalidated the blame it read, so the field is now the only record. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Found by running
make digest-statusonmainafter the stack merged. Two problems.13 pattern pages never reached
mainAll six PRs report MERGED, and
mainhas 12 pages where it should have 25. GitHub was telling the truth: the stacked PRs each merged into their base branch, which by then was no longer on the path tomain. Only #356 targetedmaindirectly.This branch is
docs/bug-patterns-visitor(all 25) merged with currentmain. Verified: 25 pages, 883 findings, everysources:path exists, every[[wiki-link]]resolves.That's a process lesson, not a code one: a stacked chain has to be merged bottom-up with each PR retargeted to
mainas its base lands, or it merges into itself and reports success. Worth avoiding stacks of five next time.The digest report said 0% outstanding while 249 findings were undated
Undated records were skipped by the "since last sync" comparison entirely, so an area could go completely undigested and the headline would still read current. That is the exact failure the report exists to prevent, occurring in the report.
git blameon the shards —mdl/executorhad gained 250 records from other sessions since my pass.dateis now required bycheck-findings. A warning was not an option: 249 records accumulated undated, and nobody saw the warning that was not there.Two limits documented rather than engineered away
Both make the number look better than reality, so they belong in the script header where the next reader will see them:
dateis day-resolution and the comparison is strictly greater-than, so findings appended on a sync's own day count as digested. Measured: 256mdl/executorfindings carry the sync's date, ~250 of which landed after the pages were written.datefield is the only record from here on, which is why it is required rather than recovered.Read the per-area
in a pagecolumn as the actionable signal and the counts as a hint.🤖 Generated with Claude Code