Skip to content
Merged
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Sections dated before 2026-09-19 predate the cycle and stay as they are. Named m
`docs/RELEASE-PROCESS.md` §8.

## Unreleased

- new(progress-report, file-bugs): **the progress report has tabs (Overview, Build, Changes, Performance, Pages, Notes), a Changes tab that reads the `PROJECT.md` Change log as a backlog, a Build tab that leads with the phase being built plus three recent unfinished phases (the rest folded), and open bugs from `docs/bugs.jsonl` with buttons that copy their `file-bugs.sh` command, one per repo.** The page never posts anything; the person runs the command, which redacts, searches duplicates, asks y/N and files through `gh`. The copied command quotes every path and uses forward slashes, so it pastes whole for a project path with a space and in Git Bash. `file-bugs --to mxcli|toolkit` files the same finding to the other repo too (the second URL goes under `also.<repo>`); without `gh` or a login, `--file` exits 0, posts nothing and names `gh auth login` or `--links`. Without JavaScript every section shows on one page, as before. Fixtures: `test-progress-report-polish.sh` P8–P10 (P9 runs the copied command for a path with a space), `test-file-bugs.sh` section O. — MendixMau (SCG field run)
- new(test-stack-up, check-requirements): a local lane — a down app starts with `mxcli run --local --watch --detach` (auto when no container runtime answers, or `--local` / `MXTK_APP_LANE=local`), free mxbuild serve port per project, restarts on the project's own APP_PORTS; container calls follow MXCLI_CONTAINER_CLI / docker (Desktop, colima, OrbStack) / podman; a missing runtime is no longer a missing requirement; a themed index.html no longer hides a Mendix app: `/mxclientsystem/mxui/mxui.js` counts only when served as JavaScript, so an SPA catch-all answering 200 HTML on every path stays not-Mendix (refs #525). Fixture `test-stack-up-local.sh` T17–T19. Field run: macOS with Docker Desktop removed and colima running, local-lane cold start 76 s then 43 s, five apps side by side — MendixMau
- fix(lint): **the toolkit's CONV020 (page actions give user feedback) is now `MXTK-UX003` (`mxtk_ux003_action_user_feedback.star`), because mxcli v0.28.0 ships a built-in CONV020 ("Created object never persisted", mendixlabs/mxcli#1518) and has no duplicate-ID guard.** Captured on a public model (`tests/wave2/fixtures/lint-conv020-v028/`): v0.28.0 reported two CONV020 findings, one per rule, `-l` listed CONV020 twice, and `CONV020: enabled: false` switched both off. `bin/sync-project.sh` migrates projects: an unedited old copy (md5 of any shipped version, CR-insensitive, or the receipt row) is replaced, `lint-baseline.json` findings whose message is the toolkit rule's are rekeyed to MXTK-UX003 (the built-in's stay CONV020), and a `lint-rules-disabled.txt` line follows the file. A lint-config opt-out of CONV020 is carried over too: a `lint-rules-disabled.txt` line for the new file keeps MXTK-UX003 off (the key stays; on v0.28.0 it switches off only the built-in). It is read the way mxcli v0.28.0 reads it (yaml.v3, captured per spelling): `enabled:` `false`/`False`/`FALSE` or `n`/`no`/`off` in any of yaml.v3's casings (`No`, `NO`, `Off`, `OFF`…, plain or quoted), as a direct child of a bare, single- or double-quoted `CONV020` key or in its flow map, from the first of `.claude/lint-config.yaml`, `lint-config.yaml`, `.lint-config.yaml`; an `enabled` nested under `options:` and a quoted `"false"` (mxcli fails to load that config) are not opt-outs. An edited copy is left in place with a warning and manual steps (with the `lint-rules-disabled.txt` line to keep such an opt-out), and the new rule is not installed beside it. A counts-only baseline, `lint-config.yaml` keys and `PROJECT.md` lines that name CONV020 get a NOTE, not a guess, printed once. New toolkit rules take an `MXTK-` id (`lint-rules/README.md` "Rule IDs"). After any mxcli upgrade, `lint-gate.sh --update-baseline` now records `mxcli_version`, and `bin/doctor.sh` prints the re-baseline hint when the installed mxcli differs from the recorded one (a baseline with no recorded version gets a note, no command; `skills/lint-that-actually-runs.md`). Decision #12 — mxcli v0.28.0 test pass
- process(routing, mdl-agent): **the mdl helper no longer preloads the kind-specific MDL skills at Stage 5; it loads them per script through `bin/mdl-rules.sh`** — lazy-load PR 2b. `learned-microflow-patterns.md`, `microflow-preflight.md` and `ui-preflight-pages.md` move to on-demand; `learned-mdl-preflight.md`, `design-spacing.md`, `learned-detection-gaps.md`, `security-is-not-a-later-script.md` and `retesting-learned-rules.md` become on-demand for mdl only (`mdl?`), unchanged for every other role; a new baseline `mdl-rules` row (Stages 5 and 6, so a Stage 6 mdl pack keeps the detection-gaps and retesting rules; mdl Stage 6 preload 9,476 words) replaces them. Baseline 72,891 → 63,877 words; mdl Stage 5 preload 29,388 → 14,600 (per script, after reading the `mdl-rules` output, the helper reads ≈21.4k words for page only, ≈22.5k for microflow+access, ≈28.1k for page+microflow, ≈29.5k for all kinds: ≈0–8k saved by kind; the A/B covered rule sufficiency with kinds pre-selected, not step 4a) (the 3,347-word core of `bin/mdl-rules.sh` counted, like the runbook slice). The mdl stub's workflow step 4a and report line ask for "STOP rows for kinds K: n/n checked". `context-pack.sh`'s "Rules" list names `<toolkit>/bin/mdl-rules.sh <kinds>` with the step's kinds (page / microflow / entity) — after this change the only route `microflow-preflight`, `security-is-not-a-later-script`, `design-spacing`, `learned-detection-gaps` and `retesting-learned-rules` have to a pack-fed helper (fixture: a page step and a logic step). `gate-check.sh` build-ready item 2 accepts `bin/mdl-rules.sh` as well as `ui-preflight-pages`, so a project synced after this change does not flip to FAIL (fixture: both layouts). No skill text changed — lazy-load plan, option C (maintainer)
Expand Down
1 change: 1 addition & 0 deletions bin/file-bugs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# bin/file-bugs.sh [--project DIR] # dry run: redacted title + body, duplicates
# bin/file-bugs.sh --file PBUG-02 [--file ...] # file that bug, after a y/N per bug
# bin/file-bugs.sh --all # every open bug, still a y/N per bug
# bin/file-bugs.sh --file PBUG-02 --to mxcli # file it to the other repo as well (row keeps its target)
# bin/file-bugs.sh --links # prefilled github new-issue URL per open bug
# bin/file-bugs.sh --json # redacted bugs + URLs as JSON (for the report)
# bin/file-bugs.sh --add --target mxcli|toolkit --title T --repro R --expected E --actual A \
Expand Down
14 changes: 12 additions & 2 deletions bin/lib/file-bugs.py
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,9 @@ def main():
ap.add_argument("--links", action="store_true")
ap.add_argument("--json", action="store_true")
ap.add_argument("--name", action="append", default=[], help="extra project name to redact")
ap.add_argument("--to", choices=sorted(TARGETS), help="file to this repo instead of the row's target: a finding that is "
"really both is two submissions (skills/upstream-feedback.md). The row keeps its target and status; "
"the issue URL is recorded under also.<repo>")
ap.add_argument("--add", action="store_true")
for k in ("target", "title", "repro", "expected", "actual", "workaround", "mxcli", "mendix", "toolkit-version"):
ap.add_argument("--" + k)
Expand All @@ -654,7 +657,9 @@ def main():
sys.exit("file-bugs: no %s" % path)
want = set(a.file)
sid = lambda d: str(d.get("id"))
todo = [(i, d) for i, d in rows if d.get("status", "open") == "open" and (not want or sid(d) in want)]
also = lambda d: bool(a.to) and a.to != d.get("target") # a second submission, to the other repo
todo = [(i, d) for i, d in rows if (d.get("status", "open") == "open" or (also(d) and d.get("status") == "filed"))
and not (also(d) and (d.get("also") or {}).get(a.to)) and (not want or sid(d) in want)]
for w in want:
if not any(sid(d) == w for _, d in rows):
sys.exit("file-bugs: %s is not in %s" % (w, path))
Expand Down Expand Up @@ -684,6 +689,7 @@ def main():
for _, d in todo:
target = d.get("target")
repo = TARGETS.get(target) if isinstance(target, str) else None
if repo and a.to: repo = TARGETS[a.to]
if not repo:
sys.stderr.write("file-bugs: %s has target %s, not one of %s; skipped\n" %
(sid(d), json.dumps(target)[:40], "/".join(TARGETS)))
Expand All @@ -710,6 +716,9 @@ def main():
dp = dupes(repo, title)
if dp is None:
print("Duplicates: search unavailable (gh missing or not authenticated)")
if posting:
print("Nothing breaks: the bug stays open in docs/bugs.jsonl with its workaround. To file it later, install gh and run "
"`gh auth login`, or print a pre-filled link for someone with a GitHub account: file-bugs.sh --links " + sid(d))
elif not dp:
print("Duplicates: none found")
else:
Expand All @@ -731,7 +740,8 @@ def main():
if p.returncode != 0 or not m:
print("gh issue create failed: " + (p.stderr or p.stdout).strip()[:300])
continue
write_back(path, sid(d), {"status": "filed", "issue_url": m.group(0)})
if also(d): write_back(path, sid(d), {"also": dict(d.get("also") or {}, **{a.to: m.group(0)})})
else: write_back(path, sid(d), {"status": "filed", "issue_url": m.group(0)})
print("filed: " + m.group(0))
if a.json:
print(json.dumps(out, indent=2, ensure_ascii=False))
Expand Down
Loading
Loading