From f26a2c9e826ad9cb83aa19d8e05a6824c968520e Mon Sep 17 00:00:00 2001 From: Rafael Richards Date: Tue, 12 May 2026 10:32:52 -0400 Subject: [PATCH 1/9] docs: add getting-started guide; profile README leads with setup.sh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit profile/README.md's Getting started section previously documented a manual pip-based install path. Now that setup.sh is in the org-meta repo (PR #49), make it the preferred install path and split the walkthrough into a dedicated SETUP doc. - profile/README.md: Getting started now leads with the setup.sh one-liner (both review-first and curl-pipe forms) and points at the new doc for the full walkthrough. - docs/guides/m-dev-tools-setup.md (new): SETUP-typed doc covering audience, prerequisites, quick install via setup.sh, manual install via `git clone m-cli && make bootstrap`, what `m doctor` verifies, next steps (TDD walkthrough, project scaffolding, VS Code extensions, MCP server), and troubleshooting. Frontmatter validates clean against docs.schema.json (Phase 1 P1.3 gate). docs/guides/ is a new subdir, the first under the .github repo's docs/ tree to follow the docs-discoverability spec §6 layout convention (SETUP/GUIDE/TUTORIAL/EXPLAINER live in guides/). Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/guides/m-dev-tools-setup.md | 134 +++++++++++++++++++++++++++++++ profile/README.md | 30 +++---- 2 files changed, 150 insertions(+), 14 deletions(-) create mode 100644 docs/guides/m-dev-tools-setup.md diff --git a/docs/guides/m-dev-tools-setup.md b/docs/guides/m-dev-tools-setup.md new file mode 100644 index 0000000..4d5e05c --- /dev/null +++ b/docs/guides/m-dev-tools-setup.md @@ -0,0 +1,134 @@ +--- +created: 2026-05-12 +last_modified: 2026-05-12 +revisions: 1 +doc_type: [SETUP] +lifecycle: active +owner: rmrich5 +title: "Getting started with m-dev-tools" +--- + +# Getting started with m-dev-tools + +Install path for a fresh developer machine, end-to-end through to +a green `m doctor`. Two flavors: a one-line bootstrap installer and +a manual path for users who prefer to step through it. + +## Audience + +Developers setting up the [m-dev-tools](../../profile/README.md) +toolchain (`m-cli`, `m-stdlib`, `m-test-engine`, …) for the first +time on Linux or macOS. + +## Prerequisites + +The installer detects these and prints install commands for anything +missing — no `sudo` is ever invoked. You need: + +| Tool | Why | +|---|---| +| `git` | Cloning the sibling repos | +| `docker` (daemon reachable) | `m-test-engine` runs YottaDB in a container | +| `python` ≥ 3.12 | `m-cli` is a Python package | +| `uv` | `m-cli`'s venv + dependency manager | +| `make` | Drives the per-repo verification targets | + +## Quick install (preferred) — `setup.sh` + +The interactive bootstrap installer at +[`setup.sh`](../../setup.sh) handles OS detection, pre-flight +checks, `m-cli` clone, sibling-repo wiring, venv install, engine +boot, and `m doctor` verification in one shot. + +```bash +# Review-first form (recommended): +curl -O https://raw.githubusercontent.com/m-dev-tools/.github/main/setup.sh +less ./setup.sh +bash ./setup.sh + +# Or, for the convinced: +bash <(curl -fsSL https://raw.githubusercontent.com/m-dev-tools/.github/main/setup.sh) +``` + +Flags: + +- `-y`, `--yes` — non-interactive; accept defaults +- `-d PATH`, `--dir PATH` — install root (default: `~/m-dev-tools`) +- `-h`, `--help` — usage + +Idempotent — re-running on an already-installed host skips the +clones and re-verifies via `m doctor`. + +## Manual install (alternative) + +If you want to step through the install yourself: + +```bash +# 1. Clone m-cli (it bootstraps the rest) +git clone https://github.com/m-dev-tools/m-cli ~/m-dev-tools/m-cli +cd ~/m-dev-tools/m-cli + +# 2. Let m-cli pull its sibling repos, install the venv, and start +# the test engine +make bootstrap + +# 3. Add m-cli to your PATH (paste into ~/.bashrc or ~/.zshrc) +export PATH="$HOME/m-dev-tools/m-cli/.venv/bin:$PATH" + +# 4. Verify +m --version +m doctor +``` + +`make bootstrap` is the same target `setup.sh` delegates to — the +installer just wraps it with OS detection and pre-flight checks. + +## What `m doctor` confirms + +- Each sibling repo is on its expected branch and reachable. +- The YottaDB container is running and `docker exec`-reachable. +- `m-stdlib`'s manifest is loadable. +- `m fmt`, `m lint`, `m test`, and `m coverage` round-trip on a + smoke routine. + +A green `m doctor` is the contract: every other `m` subcommand +assumes these invariants. + +## Next steps + +1. **TDD walkthrough.** Exercise every `m` subcommand end-to-end + against a small data-analysis app: + `~/m-dev-tools/m-cli/docs/m-cli-tdd-lifecycle-walkthrough.md`. +2. **Start your own project.** + + ```bash + mkdir -p ~/m-work && cd ~/m-work + m new myapp && cd myapp + m ci init --write + m test tests + ``` +3. **VS Code (optional).** Install + [`tree-sitter-m-vscode`](https://github.com/m-dev-tools/tree-sitter-m-vscode) + for syntax + LSP and + [`m-stdlib-vscode`](https://github.com/m-dev-tools/m-stdlib-vscode) + for STD\*-aware hover / goto-def / completion. +4. **AI agents (optional).** If you use Claude Code / Codex / + Continue, install the MCP server per the + [AI users guide](../ai-discoverability/ai-users-guide.md) so + the agent can resolve M-tooling intent without guessing. + +## Troubleshooting + +If `m doctor` reports a failure, the message tells you which +invariant broke. Common cases: + +- **Docker daemon not reachable** — start it (`sudo systemctl start + docker` on Linux; launch Docker Desktop on macOS). +- **`m-test-engine` container missing** — re-run `make bootstrap`; + it pulls the image and starts the container. +- **Python venv stale** — `cd ~/m-dev-tools/m-cli && rm -rf .venv && + make bootstrap` does a clean reinstall. + +For anything else, open an issue at + with the full +`m doctor --verbose` output. diff --git a/profile/README.md b/profile/README.md index bbc0cb8..9a13005 100644 --- a/profile/README.md +++ b/profile/README.md @@ -181,24 +181,26 @@ stdlib). ## Getting started -A typical first install: +The preferred installer is [`setup.sh`](../setup.sh) — it detects your +OS, checks prerequisites (`git` / `docker` / `python ≥ 3.12` / `uv` / +`make`), clones [`m-cli`](https://github.com/m-dev-tools/m-cli), and +delegates to `make bootstrap` for the rest (sibling clones, venv, +engine boot, `m doctor` verification): ```bash -# Foundation: parser + toolchain -git clone https://github.com/m-dev-tools/tree-sitter-m -git clone https://github.com/m-dev-tools/m-cli -pip install ./tree-sitter-m # order matters — m-cli's dep declaration -pip install ./m-cli # needs the tree-sitter-m checkout present - -# Verify -m doctor -m --help +# Review-first form (recommended): +curl -O https://raw.githubusercontent.com/m-dev-tools/.github/main/setup.sh +less ./setup.sh +bash ./setup.sh + +# Or, for the convinced: +bash <(curl -fsSL https://raw.githubusercontent.com/m-dev-tools/.github/main/setup.sh) ``` -For runtime work on YottaDB, also clone [`m-stdlib`](https://github.com/m-dev-tools/m-stdlib). -For VS Code, install the marketplace extensions (currently published under -the personal `rafael5` publisher; rebranding to a `m-dev-tools` Marketplace -publisher is on the roadmap). +See [`docs/guides/m-dev-tools-setup.md`](../docs/guides/m-dev-tools-setup.md) +for the full walkthrough — prerequisites, manual install path, +what `m doctor` verifies, next steps (TDD walkthrough, VS Code +extensions, MCP server for AI agents), and troubleshooting. ## Licensing From a81bbdc438c6d4c4f2616ce602bd9e6e2433ccf6 Mon Sep 17 00:00:00 2001 From: Rafael Richards Date: Tue, 12 May 2026 11:16:52 -0400 Subject: [PATCH 2/9] docs(history): rename to m-tools-* convention + simplify banners MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three files in docs/history/ were named inconsistently — some with "m-tool" (singular), some with "and" in the filename. Rename to the m-tools-* convention so the rehosted m-tools docs cluster by prefix in directory listings: - gap-analysis-and-remediation-strategy.md → m-tools-gap-analysis-remediation-ydb.md - m-tool-gap-analysis.md → m-tools-gap-analysis.md - m-tooling-tier1.md → m-tools-remediation-tier1.md Also simplifies the long "Archived snapshot. Imported verbatim from …" banner at the top of each file to a single-line "**History**" pointer back to profile/README.md for current state. The full attribution narrative still lives in docs/history/README.md. Co-Authored-By: Claude Opus 4.7 (1M context) --- ...n-strategy.md => m-tools-gap-analysis-remediation-ydb.md} | 4 ++-- .../{m-tool-gap-analysis.md => m-tools-gap-analysis.md} | 4 ++-- .../{m-tooling-tier1.md => m-tools-remediation-tier1.md} | 5 +++-- 3 files changed, 7 insertions(+), 6 deletions(-) rename docs/history/{gap-analysis-and-remediation-strategy.md => m-tools-gap-analysis-remediation-ydb.md} (99%) rename docs/history/{m-tool-gap-analysis.md => m-tools-gap-analysis.md} (99%) rename docs/history/{m-tooling-tier1.md => m-tools-remediation-tier1.md} (97%) diff --git a/docs/history/gap-analysis-and-remediation-strategy.md b/docs/history/m-tools-gap-analysis-remediation-ydb.md similarity index 99% rename from docs/history/gap-analysis-and-remediation-strategy.md rename to docs/history/m-tools-gap-analysis-remediation-ydb.md index f9d6de5..a3a119a 100644 --- a/docs/history/gap-analysis-and-remediation-strategy.md +++ b/docs/history/m-tools-gap-analysis-remediation-ydb.md @@ -1,6 +1,6 @@ -# M Tools — Gap Analysis and Remediation Strategy +# M Tools — Gap Analysis and Remediation Strategy (YottaDB) -> **Archived snapshot.** Imported verbatim from [`m-tools`](https://github.com/rafael5/m-tools) — source commit [`16fe3f7`](https://github.com/rafael5/m-tools/commit/16fe3f7dc6982070809cd1d8290d01fedc5905ac) (2026-04-27), at the point that repo seeded the rest of the m-dev-tools org (it has since been moved out of the org back to its original author's account). Preserved as the original phased remediation roadmap that scoped what became `m-cli` and `m-stdlib`. **Not maintained.** For the *current* shape of the org, start at [`profile/README.md`](../../profile/README.md). +> **History** For the *current* shape of the org, start at [`profile/README.md`](../../profile/README.md). **Document type:** Strategic planning **Scope:** Developer toolchain for the M (MUMPS) language diff --git a/docs/history/m-tool-gap-analysis.md b/docs/history/m-tools-gap-analysis.md similarity index 99% rename from docs/history/m-tool-gap-analysis.md rename to docs/history/m-tools-gap-analysis.md index 61dc33f..480aba9 100644 --- a/docs/history/m-tool-gap-analysis.md +++ b/docs/history/m-tools-gap-analysis.md @@ -1,6 +1,6 @@ -# M Tools — Gap Analysis (Vendor-Neutral) +# M Tools — Gap Analysis (Vendor Neutral) -> **Archived snapshot.** Imported verbatim from [`m-tools`](https://github.com/rafael5/m-tools) — source commit [`16fe3f7`](https://github.com/rafael5/m-tools/commit/16fe3f7dc6982070809cd1d8290d01fedc5905ac) (2026-04-27), at the point that repo seeded the rest of the m-dev-tools org (it has since been moved out of the org back to its original author's account). Preserved for the design rationale behind the m-dev-tools ecosystem (Go/Rust/Python toolchain analogy that drove `m-cli`'s CLI ergonomics). **Not maintained.** For the *current* shape of the org, start at [`profile/README.md`](../../profile/README.md). +> **History** For the *current* shape of the M Developer Tools, start at [`profile/README.md`](../../profile/README.md). **Document type:** Reference / strategic planning **Scope:** Developer toolchain for the M (MUMPS) programming language across all current implementations diff --git a/docs/history/m-tooling-tier1.md b/docs/history/m-tools-remediation-tier1.md similarity index 97% rename from docs/history/m-tooling-tier1.md rename to docs/history/m-tools-remediation-tier1.md index 614b9e4..8a80969 100644 --- a/docs/history/m-tooling-tier1.md +++ b/docs/history/m-tools-remediation-tier1.md @@ -1,6 +1,7 @@ -# M Tooling — Tier 1 Strategy: Closing the Inner-Loop Gaps +# M Tools Remediation - Closing the Inner-Loop Gaps (Tier 1) -> **Archived snapshot.** Imported verbatim from [`m-tools`](https://github.com/rafael5/m-tools) — source commit [`16fe3f7`](https://github.com/rafael5/m-tools/commit/16fe3f7dc6982070809cd1d8290d01fedc5905ac) (2026-04-27), at the point that repo seeded the rest of the m-dev-tools org (it has since been moved out of the org back to its original author's account). Preserved as the original Tier 1 strategy that scoped what became `m-cli`'s first deliverables. **Not maintained.** For the *current* shape of the org, start at [`profile/README.md`](../../profile/README.md). + +> **History** For the *current* shape of the org, start at [`profile/README.md`](../../profile/README.md). **Document type:** Strategic plan, scoped **Scope:** The five Tier 1 developer-toolchain gaps in the M (MUMPS) ecosystem From 8a8f2c4b46349ba2d235b6a5d32eb80c154c160d Mon Sep 17 00:00:00 2001 From: Rafael Richards Date: Tue, 12 May 2026 11:17:00 -0400 Subject: [PATCH 3/9] =?UTF-8?q?docs(profile):=20retitle=20README=20"m-dev-?= =?UTF-8?q?tools"=20=E2=86=92=20"M=20Developer=20Tools"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Repo-name-style heading reads as code; "M Developer Tools" is the display title the README is actually about. Renders better on the org landing page where this README is the primary public surface. Co-Authored-By: Claude Opus 4.7 (1M context) --- profile/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/profile/README.md b/profile/README.md index 9a13005..b60febe 100644 --- a/profile/README.md +++ b/profile/README.md @@ -1,4 +1,4 @@ -# m-dev-tools +# M Developer Tools **A suite of engine-neutral developer tools for the M (MUMPS) programming language, built around a CI/CD-friendly, test-driven-development workflow.** From d869ade465291d240f6ff102af34b48a4c6363ff Mon Sep 17 00:00:00 2001 From: Rafael Richards Date: Tue, 12 May 2026 11:24:55 -0400 Subject: [PATCH 4/9] =?UTF-8?q?docs(history):=20expand=20TOC=20for=20?= =?UTF-8?q?=C2=A78=20tier=20ranking;=20intro=20paragraph=20on=20tier1=20re?= =?UTF-8?q?mediation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - m-tools-gap-analysis.md: TOC entry for §8 expanded with sub-entries for each tier (Tier 1 — development loop, Tier 2 — quality gates, Tier 3 — maintenance / ecosystem, Tier 4 — specialised), so readers can jump straight to the impact bucket they care about instead of scrolling §8 from the top. - m-tools-remediation-tier1.md: new leading paragraph framing this document as the focused Tier 1 execution plan and linking back to the new `#tier-1--the-development-loop-transformative-impact` anchor in m-tools-gap-analysis. Companion-doc bullet retargeted at the same anchor for a sharper landing than the §8 root. Also repairs the stale-from-rename links inside the file (m-tool-gap- analysis.md → m-tools-gap-analysis.md; gap-analysis-and-remediation- strategy.md → m-tools-gap-analysis-remediation-ydb.md; the end-of- doc marker updated to the new filename). Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/history/m-tools-gap-analysis.md | 4 +++ docs/history/m-tools-remediation-tier1.md | 33 ++++++++++++++--------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/docs/history/m-tools-gap-analysis.md b/docs/history/m-tools-gap-analysis.md index 480aba9..70eb529 100644 --- a/docs/history/m-tools-gap-analysis.md +++ b/docs/history/m-tools-gap-analysis.md @@ -45,6 +45,10 @@ - [6.4 The bottom line](#64-the-bottom-line) - [7. Consolidated Gap Analysis](#7-consolidated-gap-analysis) - [8. Rank-Ordered Developer Impact: Where to Invest First](#8-rank-ordered-developer-impact-where-to-invest-first) + - [Tier 1 — The development loop (transformative impact)](#tier-1--the-development-loop-transformative-impact) + - [Tier 2 — Quality gates and team scaling (high impact)](#tier-2--quality-gates-and-team-scaling-high-impact) + - [Tier 3 — Maintenance and ecosystem (medium impact)](#tier-3--maintenance-and-ecosystem-medium-impact) + - [Tier 4 — Specialised or quality-of-life (lower impact)](#tier-4--specialised-or-quality-of-life-lower-impact) --- diff --git a/docs/history/m-tools-remediation-tier1.md b/docs/history/m-tools-remediation-tier1.md index 8a80969..e037e0a 100644 --- a/docs/history/m-tools-remediation-tier1.md +++ b/docs/history/m-tools-remediation-tier1.md @@ -3,12 +3,21 @@ > **History** For the *current* shape of the org, start at [`profile/README.md`](../../profile/README.md). +This document is the **Tier 1 remediation plan**: the focused execution +plan for filling the five tools that +[`m-tools-gap-analysis.md` §8 ranks as Tier 1 — the development loop](m-tools-gap-analysis.md#tier-1--the-development-loop-transformative-impact) +(test runner, logic linter, formatter, single-test selection, test +watcher). These are the tools whose absence is felt every single edit, +and where filling the gap is most transformative. The broader phased +strategy covering Tiers 1–4 against YottaDB lives in +[`m-tools-gap-analysis-remediation-ydb.md`](m-tools-gap-analysis-remediation-ydb.md). + **Document type:** Strategic plan, scoped **Scope:** The five Tier 1 developer-toolchain gaps in the M (MUMPS) ecosystem **Audience:** Anyone planning, coordinating, or contributing to M-language tooling work **Companion documents:** -- [m-tool-gap-analysis.md](m-tool-gap-analysis.md) — the broader cross-engine gap analysis (this doc focuses on its [§8 Tier 1](m-tool-gap-analysis.md#8-rank-ordered-developer-impact-where-to-invest-first)) -- [gap-analysis-and-remediation-strategy.md](gap-analysis-and-remediation-strategy.md) — the wider phased remediation plan (this doc is the focused Tier 1 extract) +- [m-tools-gap-analysis.md](m-tools-gap-analysis.md) — the broader cross-engine gap analysis (this doc focuses on its [§8 Tier 1](m-tools-gap-analysis.md#tier-1--the-development-loop-transformative-impact)) +- [m-tools-gap-analysis-remediation-ydb.md](m-tools-gap-analysis-remediation-ydb.md) — the wider phased remediation plan (this doc is the focused Tier 1 extract) --- @@ -38,7 +47,7 @@ ## 1. The Tier 1 gaps -The [§8 ranking in m-tool-gap-analysis.md](m-tool-gap-analysis.md#8-rank-ordered-developer-impact-where-to-invest-first) identifies five Tier 1 capabilities — the development inner loop — that are **MAJOR common gaps** across both major M engines (IRIS, YottaDB) for pure MUMPS code. They are the **transformative** tools, validated in [§8.5](m-tool-gap-analysis.md#85-validation-empirical-grounding-for-the-ranking) against DORA / *Accelerate* research and the broader literature on developer productivity. +The [§8 ranking in m-tools-gap-analysis.md](m-tools-gap-analysis.md#8-rank-ordered-developer-impact-where-to-invest-first) identifies five Tier 1 capabilities — the development inner loop — that are **MAJOR common gaps** across both major M engines (IRIS, YottaDB) for pure MUMPS code. They are the **transformative** tools, validated in [§8.5](m-tools-gap-analysis.md#85-validation-empirical-grounding-for-the-ranking) against DORA / *Accelerate* research and the broader literature on developer productivity. | # | Capability | Why it's Tier 1 | |---|------------|-----------------| @@ -153,7 +162,7 @@ The integration boundary with the engine is *only* the test-execution adapter YottaDB is the primary build / development engine for two pragmatic reasons: 1. **Open-source reproducibility.** AGPL-3.0 means anyone can install, run, and contribute without licence negotiation. CI runs in any standard container. -2. **Mature C API.** `libyottadb.so` is a stable extensibility surface; foreign-language bindings (Go, Python, Rust, Node.js, Lua, Perl) make it straightforward to embed engine calls in tool implementations when needed (see [m-tool-gap-analysis.md §4.4](m-tool-gap-analysis.md#44-foreign-language-integration-embedded-language-vs-embedded-database) for the architecture rationale). +2. **Mature C API.** `libyottadb.so` is a stable extensibility surface; foreign-language bindings (Go, Python, Rust, Node.js, Lua, Perl) make it straightforward to embed engine calls in tool implementations when needed (see [m-tools-gap-analysis.md §4.4](m-tools-gap-analysis.md#44-foreign-language-integration-embedded-language-vs-embedded-database) for the architecture rationale). But "built on YottaDB" never means "locked to YottaDB." Each tool's parser-side work is engine-neutral; only the test-execution shim varies by engine. @@ -170,13 +179,13 @@ Before any Tier 1 tool is considered production-ready, it must pass: The Tier 1 plan does **not** cover: -- **Coverage** (line / branch) — Tier 2 in [§8](m-tool-gap-analysis.md#8-rank-ordered-developer-impact-where-to-invest-first). +- **Coverage** (line / branch) — Tier 2 in [§8](m-tools-gap-analysis.md#8-rank-ordered-developer-impact-where-to-invest-first). - **Documentation generation** — Tier 3. - **Dependency management** — Tier 3, blocked on a manifest-format design in `m-standard`. - **IDE / DAP integration** — Tier 2; substantial engineering on its own. -- **IRIS ObjectScript (IOS) tooling** — out of scope; IOS is a separate language ([m-tool-gap-analysis.md §4.1.1](m-tool-gap-analysis.md#411-iris-objectscript-ios-what-it-is-and-why-it-isnt-ansi-standard-mumps)) with its own toolchain. +- **IRIS ObjectScript (IOS) tooling** — out of scope; IOS is a separate language ([m-tools-gap-analysis.md §4.1.1](m-tools-gap-analysis.md#411-iris-objectscript-ios-what-it-is-and-why-it-isnt-ansi-standard-mumps)) with its own toolchain. -These are excluded to keep the Tier 1 plan focused. Each is sequenced separately in [gap-analysis-and-remediation-strategy.md → Addendum B](gap-analysis-and-remediation-strategy.md#addendum-b-prioritized-sequence-of-remediation-post-parser). +These are excluded to keep the Tier 1 plan focused. Each is sequenced separately in [m-tools-gap-analysis-remediation-ydb.md → Addendum B](m-tools-gap-analysis-remediation-ydb.md#addendum-b-prioritized-sequence-of-remediation-post-parser). --- @@ -184,16 +193,16 @@ These are excluded to keep the Tier 1 plan focused. Each is sequenced separately The case for Tier 1 primacy has three legs, all already established in the companion analysis: -**1. Empirical research on developer productivity.** [m-tool-gap-analysis.md §8.5](m-tool-gap-analysis.md#85-validation-empirical-grounding-for-the-ranking) cites primary sources: +**1. Empirical research on developer productivity.** [m-tools-gap-analysis.md §8.5](m-tools-gap-analysis.md#85-validation-empirical-grounding-for-the-ranking) cites primary sources: - Forsgren, Humble & Kim (2018), *Accelerate*, identifies test automation as among the technical capabilities most strongly correlated with high software-delivery performance (DORA programme, 23,000+ respondents). - Sadowski et al. (2018), [*"Lessons from Building Static Analysis Tools at Google"*](https://cacm.acm.org/research/lessons-from-building-static-analysis-tools-at-google/) (CACM 61(4)) — Tricorder static analysis prevents hundreds of bugs per day from entering Google's codebase. - Vasilescu et al. (2015), [*"Quality and productivity outcomes relating to continuous integration in GitHub"*](https://web.cs.ucdavis.edu/~filkov/papers/pr_soc_lan.pdf) (FSE 2015) — CI users merge PRs significantly faster and find more bugs. - Stack Overflow Annual Developer Survey: Ruff (84% admired) and Cargo (83% admired) — top-of-survey tools that bundle the Tier 1 capabilities. -**2. Cross-engine consolidation.** [§7 in m-tool-gap-analysis.md](m-tool-gap-analysis.md#7-consolidated-gap-analysis) shows that **all five Tier 1 capabilities are MAJOR common gaps** — both IRIS and YottaDB ship **None** for MUMPS code. **A single source-level tool, built on a shared parser foundation, fills the gap on every M engine simultaneously.** That economy of leverage is the strategic case for treating M as a portable language with portable tooling, not as a vendor-locked feature. +**2. Cross-engine consolidation.** [§7 in m-tools-gap-analysis.md](m-tools-gap-analysis.md#7-consolidated-gap-analysis) shows that **all five Tier 1 capabilities are MAJOR common gaps** — both IRIS and YottaDB ship **None** for MUMPS code. **A single source-level tool, built on a shared parser foundation, fills the gap on every M engine simultaneously.** That economy of leverage is the strategic case for treating M as a portable language with portable tooling, not as a vendor-locked feature. -**3. The 40,000-routine VistA reality.** [§6.1 / §6.2](m-tool-gap-analysis.md#6-the-real-question-developer-experience-for-a-legacy-mumps-codebase) of m-tool-gap-analysis frames the real-world stakes: a VistA codebase has effectively zero benefit from IRIS's IOS-targeted tooling (the wrappers don't reach the MUMPS code) and effectively zero benefit from YottaDB's runtime-first investment (the developer-experience layer simply isn't there). Tier 1 is the work that closes the gap *for the actual M codebase that matters most*. +**3. The 40,000-routine VistA reality.** [§6.1 / §6.2](m-tools-gap-analysis.md#6-the-real-question-developer-experience-for-a-legacy-mumps-codebase) of m-tool-gap-analysis frames the real-world stakes: a VistA codebase has effectively zero benefit from IRIS's IOS-targeted tooling (the wrappers don't reach the MUMPS code) and effectively zero benefit from YottaDB's runtime-first investment (the developer-experience layer simply isn't there). Tier 1 is the work that closes the gap *for the actual M codebase that matters most*. --- @@ -205,7 +214,7 @@ The five questions raised during initial planning now have working resolutions. **Decision: defer indefinitely. Tier 1 ships without an IRIS adapter.** -InterSystems' demonstrated trajectory is to promote IRIS ObjectScript (IOS) as the developer-facing language and to scrub mention of MUMPS where possible — the 2018 Caché → IRIS rename was a marketing exercise, and IOS is a proprietary wrapper sitting *between* IRIS users and the MUMPS substrate. The vendor is not investing in MUMPS-side developer experience and has shown no interest in doing so. (See [m-tool-gap-analysis.md §1.2 naming history](m-tool-gap-analysis.md#naming-history-intersystems-mumps--caché-objectscript--iris-objectscript-ios) and [§4.1.3](m-tool-gap-analysis.md#413-iris-tooling-by-file-scope-and-language) for the evidence.) +InterSystems' demonstrated trajectory is to promote IRIS ObjectScript (IOS) as the developer-facing language and to scrub mention of MUMPS where possible — the 2018 Caché → IRIS rename was a marketing exercise, and IOS is a proprietary wrapper sitting *between* IRIS users and the MUMPS substrate. The vendor is not investing in MUMPS-side developer experience and has shown no interest in doing so. (See [m-tools-gap-analysis.md §1.2 naming history](m-tools-gap-analysis.md#naming-history-intersystems-mumps--caché-objectscript--iris-objectscript-ios) and [§4.1.3](m-tools-gap-analysis.md#413-iris-tooling-by-file-scope-and-language) for the evidence.) Building and maintaining an IRIS adapter would require coordinating with a vendor whose strategic interests are misaligned with the goals of this work. The pragmatic choice is to invest the same effort in YottaDB and the source-level tooling — which ports automatically to any conformant M engine — and let an IRIS adapter remain a community contribution if one ever emerges. The source-level tools (formatter, linter, test discovery) are unaffected by this decision; they run on `.m` files via the parser, regardless of which engine the runtime side targets. @@ -258,4 +267,4 @@ Mechanics: --- -*End of m-tooling-tier1 document.* +*End of m-tools-remediation-tier1 document.* From 7120940b58e111c345385985499ef4859b86e0e6 Mon Sep 17 00:00:00 2001 From: Rafael Richards Date: Tue, 12 May 2026 11:35:42 -0400 Subject: [PATCH 5/9] docs(profile): tighten Why-this-exists + Getting-started in README MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Why this exists now leads with the 2026 cross-engine gap analysis (linked at both the doc level and the §8 four-tier anchor) and frames m-dev-tools as the focused remediation of Tier 1 — the inner development loop. Drops the "YottaDB-first with IRIS portability at the runtime layer" line; replaced with a clean "source-level → engine-neutral, so IRIS / YottaDB / any future ANSI-compliant engine work equally" framing. - Getting started shrunk from 22 lines to 9. Single link to the Getting started guide (which carries the prerequisites / manual install / verification / troubleshooting detail) and a three-line installer snippet (curl + less + bash). Drops the OS / prereq / delegation prose — it lives in the guide. Drops the no-review curl-pipe form; the review-first path is the only one shown. Co-Authored-By: Claude Opus 4.7 (1M context) --- profile/README.md | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/profile/README.md b/profile/README.md index b60febe..0951100 100644 --- a/profile/README.md +++ b/profile/README.md @@ -169,39 +169,31 @@ m-dev-tools ships an MCP server ([`m-dev-tools-mcp`](https://pypi.org/project/m- M (MUMPS) is the language behind a great deal of healthcare and financial infrastructure, but its modern developer tooling has historically lagged -behind mainstream languages. **`m-dev-tools`** provides the missing -source-level pieces — a real parser, a unified language reference, a -runtime standard library, and a `git`/`cargo`/`go`-style command-line -toolchain — engineered to be useful regardless of which M engine you run. +behind mainstream languages. The 2026 cross-engine gap analysis +([`docs/history/m-tools-gap-analysis.md`](../docs/history/m-tools-gap-analysis.md)) +inventoried the deficit — no test runner, no logic linter, no formatter, +no single-test selection, no test watcher — and ranked the missing pieces +into [four impact tiers](../docs/history/m-tools-gap-analysis.md#8-rank-ordered-developer-impact-where-to-invest-first). +**`m-dev-tools`** is the focused remediation of that top tier: the +**inner development loop** that mainstream language ecosystems take for +granted and that M has never had. The toolchain is **engine-neutral at the source layer** (`m fmt` and -`m lint` care about M syntax, not a specific runtime), and **YottaDB-first -with IRIS portability** at the runtime layer (test runner, coverage, -stdlib). +`m lint` care about M syntax, not a specific runtime), so a working +install serves IRIS, YottaDB, and any future ANSI-compliant M engine +equally. ## Getting started -The preferred installer is [`setup.sh`](../setup.sh) — it detects your -OS, checks prerequisites (`git` / `docker` / `python ≥ 3.12` / `uv` / -`make`), clones [`m-cli`](https://github.com/m-dev-tools/m-cli), and -delegates to `make bootstrap` for the rest (sibling clones, venv, -engine boot, `m doctor` verification): +See the [Getting started guide](../docs/guides/m-dev-tools-setup.md) +for prerequisites, install paths, verification, and troubleshooting. ```bash -# Review-first form (recommended): curl -O https://raw.githubusercontent.com/m-dev-tools/.github/main/setup.sh less ./setup.sh bash ./setup.sh - -# Or, for the convinced: -bash <(curl -fsSL https://raw.githubusercontent.com/m-dev-tools/.github/main/setup.sh) ``` -See [`docs/guides/m-dev-tools-setup.md`](../docs/guides/m-dev-tools-setup.md) -for the full walkthrough — prerequisites, manual install path, -what `m doctor` verifies, next steps (TDD walkthrough, VS Code -extensions, MCP server for AI agents), and troubleshooting. - ## Licensing Most repos are **AGPL-3.0**, the two VS Code extensions are **MIT** to From 7a324241694a9dc922da232046f9a2bacebd42d1 Mon Sep 17 00:00:00 2001 From: Rafael Richards Date: Tue, 12 May 2026 11:56:43 -0400 Subject: [PATCH 6/9] docs: link to m-cli TDD walkthrough from profile README; fix path - profile/README.md: new section "Example of Modern M Test-Driven Development and M Standard Library" between Getting started and Licensing. Points at the m-cli TDD lifecycle walkthrough as the end-to-end demonstration of every m subcommand + m-stdlib. - setup.sh + docs/guides/m-dev-tools-setup.md: fix the walkthrough filename in their "Next steps" hints. The actual file under m-cli is m-tdd-lifecycle-walkthrough.md, not m-cli-tdd-lifecycle- walkthrough.md. Earlier session typo. Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/guides/m-dev-tools-setup.md | 2 +- profile/README.md | 10 ++++++++++ setup.sh | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/guides/m-dev-tools-setup.md b/docs/guides/m-dev-tools-setup.md index 4d5e05c..58410a5 100644 --- a/docs/guides/m-dev-tools-setup.md +++ b/docs/guides/m-dev-tools-setup.md @@ -98,7 +98,7 @@ assumes these invariants. 1. **TDD walkthrough.** Exercise every `m` subcommand end-to-end against a small data-analysis app: - `~/m-dev-tools/m-cli/docs/m-cli-tdd-lifecycle-walkthrough.md`. + `~/m-dev-tools/m-cli/docs/m-tdd-lifecycle-walkthrough.md`. 2. **Start your own project.** ```bash diff --git a/profile/README.md b/profile/README.md index 0951100..ef1c54c 100644 --- a/profile/README.md +++ b/profile/README.md @@ -194,6 +194,16 @@ less ./setup.sh bash ./setup.sh ``` +## Example of Modern M Test-Driven Development and M Standard Library + +The [m-cli TDD lifecycle walkthrough](https://github.com/m-dev-tools/m-cli/blob/main/docs/m-tdd-lifecycle-walkthrough.md) +is an end-to-end transcript of building a small data-analysis app — +`reqstats`, an HTTP-access-log summarizer — using only the `m` +toolchain and `m-stdlib`. Exercises every `m ` (fmt / +lint / test / coverage / watch / lsp / new / run / build / ci) and +the standard library it consumes. The fastest way to see a modern +M inner loop in action on a clean host. + ## Licensing Most repos are **AGPL-3.0**, the two VS Code extensions are **MIT** to diff --git a/setup.sh b/setup.sh index 7bca4d2..9f75c0c 100755 --- a/setup.sh +++ b/setup.sh @@ -231,7 +231,7 @@ Next steps: 3. Read the TDD lifecycle walkthrough — exercises every m subcommand end-to-end against a small data-analysis app: - $M_DEV_HOME/m-cli/docs/m-cli-tdd-lifecycle-walkthrough.md + $M_DEV_HOME/m-cli/docs/m-tdd-lifecycle-walkthrough.md 4. Start a project of your own: mkdir -p ~/m-work && cd ~/m-work From b2a65ae9438c6341fe1e4db4231f83b6bb5fa43f Mon Sep 17 00:00:00 2001 From: Rafael Richards Date: Tue, 12 May 2026 12:00:08 -0400 Subject: [PATCH 7/9] docs(guides): rehost m-cli TDD lifecycle walkthrough as in-org guide Copies the 785-line end-to-end transcript from m-cli/docs/m-tdd-lifecycle-walkthrough.md into the meta-repo at docs/guides/m-tdd-stdlib-walkthrough.md so the example sits next to the Getting started guide and renders inline on the org landing page. The original under m-cli remains the source of truth for m-cli releases; this in-org copy is for org-level discoverability. Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/guides/m-tdd-stdlib-walkthrough.md | 785 ++++++++++++++++++++++++ 1 file changed, 785 insertions(+) create mode 100644 docs/guides/m-tdd-stdlib-walkthrough.md diff --git a/docs/guides/m-tdd-stdlib-walkthrough.md b/docs/guides/m-tdd-stdlib-walkthrough.md new file mode 100644 index 0000000..5b034a2 --- /dev/null +++ b/docs/guides/m-tdd-stdlib-walkthrough.md @@ -0,0 +1,785 @@ +--- +created: 2026-05-11 +last_modified: 2026-05-12 +revisions: 1 +doc_type: [WORKED-EXAMPLE, TUTORIAL, SMOKE-TEST] +--- + +# m-cli TDD lifecycle walkthrough + +End-to-end transcript of a real M developer building a small +data-analysis application — **`reqstats`**, an HTTP-access-log +summarizer — using only the `m` toolchain and the `m-stdlib` standard +library. Doubles as a turnkey smoke test that every `m ` +works on *any* docker-capable host, from a clean checkout. + +The finished application is left in place at `~/m-work/reqstats/` so +the next session can re-run any step. m-stdlib's `.m` files are +vendored into `routines/` so the engine container can find them +(see [§ Vendoring m-stdlib](#4-vendoring-m-stdlib) below). + +**Surface coverage.** Every one of the 28 distinct invocations in +[`cli-menu-system.md`](cli-menu-system.md) is exercised below at least +once, except for `m engine reset` (destructive — touched in description +only) and `m watch` (long-running — mentioned only). The final 100 % +label-coverage gate against the production routine validates the +inner-loop chain end to end. + +--- + +## Prerequisites — turnkey setup on a fresh host + +Anyone on any machine should be able to follow this walkthrough from +zero. Setup is one-time per machine. + +### System tools + +| Tool | Why | Verify | +| ------------- | ----------------------------------------- | ------------------ | +| **git** | clone the repos | `git --version` | +| **docker** | runs the m-test-engine YottaDB container | `docker --version` | +| **Python 3.12+** | m-cli is a Python package | `python3 --version` | +| **uv** | m-cli's dependency manager + venv | `uv --version` | +| **make** | optional; convenience targets | `make --version` | + +On Linux: `apt install git docker.io python3.12 make`, then +[install uv](https://docs.astral.sh/uv/getting-started/installation/) +(`curl -LsSf https://astral.sh/uv/install.sh | sh`). On macOS: +`brew install git docker python@3.12 uv`. Docker requires the daemon +running (Docker Desktop on macOS / Windows, `systemctl start docker` +on Linux). + +### Clone the repos + +m-cli has two hard dependencies that must live as sibling checkouts — +its `pyproject.toml` declares them by relative path. m-stdlib is the +library we're going to call from `reqstats`, so we need that too. + +```bash +mkdir -p ~/m-dev-tools && cd ~/m-dev-tools +git clone https://github.com/m-dev-tools/tree-sitter-m +git clone https://github.com/m-dev-tools/m-standard +git clone https://github.com/m-dev-tools/m-cli +git clone https://github.com/m-dev-tools/m-stdlib +``` + +(`tree-sitter-m` is the parser m-cli builds on; `m-standard` is the +language reference m-cli loads keyword/symbol tables from. Both are +mandatory.) + +### Install m-cli into a venv + +```bash +cd ~/m-dev-tools/m-cli +make install # uv sync --extra dev + pre-commit hooks +.venv/bin/m --version # m-cli 0.1.0 +``` + +Add `~/m-dev-tools/m-cli/.venv/bin` to your `PATH` (or use direnv) so +the bare `m` command works without the explicit prefix used in the +transcript below. + +### Bootstrap the engine container + +```bash +m engine install # docker pull ghcr.io/m-dev-tools/m-test-engine:0.1.0 +m engine start # docker run -d -v $HOME/m-work:/m-work ... +``` + +The first call pulls the image (~150 MB) from GHCR; the second starts +a long-running container named `m-test-engine` with `$HOME/m-work` +bind-mounted at `/m-work`. The bind-mount is the entire point: every +M project under `~/m-work/` is automatically visible inside the +container at the matching path, no per-project mount setup. + +### Verify + +```bash +mkdir -p ~/m-work # bind-mount root +m doctor # all checks should be ✓ +``` + +If `m doctor` reports anything other than 7 OK, fix that before +proceeding — every command below depends on the engine being healthy. + +--- + +--- + +## 0. Scenario + +`reqstats` ingests a CSV access log (timestamp, method, path, status, +bytes) and emits a JSON summary: + +```text +{ + "class": { + "2xx": {"count": 2, "bytes": 4000}, + "5xx": {"count": 1, "bytes": 512} + }, + "totals": {"requests": 3, "bytes": 4512, "mean_bytes": 1504} +} +``` + +The pipeline: + +``` +CSV bytes → $$parse^STDCSV → rows(i,j) + → aggregate → plain summary tree + → toJsonTree → STDJSON sigil tree + → $$encode^STDJSON → JSON text +``` + +Three m-stdlib modules earn their place: **STDCSV** (parsing), +**STDMATH** (`$$mean`), **STDJSON** (encode); plus **STDASSERT** +in the tests. + +--- + +## 1. Environmental health — `m doctor` + `m engine` + +Day-zero sanity. The transport probe and the engine container both +have to be green before anything else makes sense. + +```text +$ m doctor + + ✓ OK docker_installed docker CLI on PATH + ✓ OK docker_daemon docker daemon reachable + ✓ OK engine_image image ghcr.io/m-dev-tools/m-test-engine:0.1.0 present + ✓ OK engine_container container `m-test-engine` running + ✓ OK engine_bind_mount host /home/rafael/m-work exists + ✓ OK parser tree-sitter-m loaded + ✓ OK keywords 323 M language keywords loaded from m-standard + +7 OK, 0 warning, 0 fail, 0 skipped +``` + +`m doctor` is transport-aware — on a docker host it runs the docker +checks; on a local-YDB host it runs the local-YDB checks. The +[engine refactor follow-ups](evolution.md#engine-refactor-follow-ups) +in `evolution.md` cover the routing rule. + +Inspect the engine container in more detail: + +```text +$ m engine status +driver: docker +image: ghcr.io/m-dev-tools/m-test-engine:0.1.0 +container: m-test-engine + cli installed: ✓ + daemon up: ✓ + image present: ✓ + container up: ✓ + healthy: ✓ +``` + +```text +$ m engine version + +image: ghcr.io/m-dev-tools/m-test-engine:0.1.0 + + manifest image + ---------------- ---------------- + ✓ protocol 1 1 + ✓ ydb-version r2.02 r2.02 + ✓ bind-mount /m-work /m-work + image-rev (none) e212fa2991ea4a8529f885fff6801b1fb1038750 +``` + +Smoke probe — run a one-shot M expression inside the container: + +```text +$ m engine exec 'write $ZVERSION,!' +GT.M V7.1-002 Linux x86_64 +``` + +The remaining lifecycle verbs (`install`, `start`, `stop`, `restart`, +`logs`, `shell`, `reset`, `capabilities`) follow the same shape; this +walkthrough doesn't need to exercise the destructive ones. `m engine +capabilities` emits the engine namespace as JSON for downstream tooling. + +--- + +## 2. Research the standard library — `m stdlib …` + +Before writing code, find out what stdlib already does so we don't +reinvent CSV parsing or stats math. + +```text +$ m stdlib list +m-stdlib v0.5.0 — 32 module(s) + + STDARGS m-stdlib — argparse (v0.0.7). + STDASSERT m-stdlib — assertion library (v0.0.1). + … + STDCSV m-stdlib — RFC-4180 CSV parser/writer (pure-M). + … + STDJSON m-stdlib — RFC 8259 JSON parser + serialiser. + … + STDMATH m-stdlib — Numeric helpers (clamp / min / max / sum / count / mean over arrays). + … +``` + +Three modules look directly relevant. Drill down on each: + +```text +$ m stdlib doc STDCSV.parse +$$parse^STDCSV(text, rows) → int + +Parse CSV text into rows(i,j); return row count. + text string CSV document (CRLF, LF, or lone-CR record terminators) + rows array caller-owned destination; killed before population +… +``` + +```text +$ m stdlib doc STDMATH.mean +$$mean^STDMATH(arr) → num + +Arithmetic mean = sum / count. "" if arr is empty (no /0). +… +``` + +```text +$ m stdlib doc STDJSON.encode +$$encode^STDJSON(node) → string + +Serialise `node` to JSON text. +… +Object members emit in M collation order (numeric subscripts first, +then string subscripts in byte order). A gappy array (e.g. node(1) +and node(3) without node(2)) raises U-STDJSON-ENCODE rather than +inventing a `null`. +``` + +That last note is important — STDJSON expects a **sigil-prefixed tree** +(`"o"` = object, `"n:42"` = number), not arbitrary local arrays. +We'll need a small lift-to-sigil helper. + +When the symbol name is fuzzy, search: + +```text +$ m stdlib search "mean" + STDMATH.mean Arithmetic mean… +``` + +When debugging a known-failure path, look up which labels raise a +given error code: + +```text +$ m stdlib errors | head +U-STDCSV-PARSE STDCSV parse, parseFile +U-STDJSON-ENCODE STDJSON encode +U-STDJSON-PARSE STDJSON parse, parseFile, parseFileEof +… +``` + +`m stdlib examples STDCSV` lists every `@example` body for grep +piping; `m stdlib manifest` dumps the raw JSON for tools / agents. + +--- + +## 3. Setup project — `m new` + `m ci init` + +Scaffold: + +```text +$ cd ~/m-work && m new reqstats + create reqstats/routines/REQSTATS.m + create reqstats/routines/REQSTATSASRT.m + create reqstats/tests/REQSTATSTST.m + create reqstats/.m-cli.toml + create reqstats/.gitignore + create reqstats/Makefile + create reqstats/README.md + +Scaffolded reqstats at /home/rafael/m-work/reqstats +Next steps: + cd /home/rafael/m-work/reqstats + make check +``` + +Wire CI: + +```text +$ cd reqstats && m ci init # preview first (no mutation) +# preview: would write .github/workflows/m-ci.yml +# pass --write to scaffold the file +# ----- m-ci.yml ----- +# GitHub Actions workflow generated by `m ci init`. +… + +$ m ci init --write + create .github/workflows/m-ci.yml + +Next: commit the workflow and push to a branch with GitHub Actions enabled. +``` + +`m ci init` is **preview by default** (anti-pattern #4 from the +[CLI-UX guide](cli-frameworks/cli-ux-conventions-guide.md)) — same shape as `kubectl apply --dry-run`. Pass `--write` only +when you actually want the mutation. + +--- + +## 4. Vendoring m-stdlib + +Quick aside. The m-test-engine container's `$ydb_routines` doesn't +include m-stdlib by default. Since YottaDB's routine search isn't +recursive, the simplest pattern is to **vendor** m-stdlib's `.m` +files alongside your project routines: + +```bash +cp ~/m-dev-tools/m-stdlib/src/STD*.m ~/m-work/reqstats/routines/ +``` + +This places every `STD*.m` flat in `routines/`, where the docker +engine's stage path picks them up automatically via the project's +in-container `/m-work/reqstats/routines`. A future m-cli feature +could read a `[routines] extra = ["…"]` table from `.m-cli.toml` +for cleaner external-lib resolution, but vendoring is honest +about MUMPS's actual routine-resolution model and works today. + +--- + +## 5. Inner loop (TDD) — `m fmt`, `m lint`, `m test` + +### 5.1 RED — write the tests first + +```m +REQSTATSTST ; @summary unit tests for REQSTATS + new pass,fail + do start^STDASSERT(.pass,.fail) + do tClassify(.pass,.fail) + do tAggregateCounts(.pass,.fail) + do tAggregateBytes(.pass,.fail) + do tSummarizeJson(.pass,.fail) + do report^STDASSERT(pass,fail) + quit + ; +tClassify(pass,fail) ; @test status code → class bucket + do eq^STDASSERT(.pass,.fail,$$classify^REQSTATS(200),"2xx","200 is 2xx") + do eq^STDASSERT(.pass,.fail,$$classify^REQSTATS(500),"5xx","500 is 5xx") + ; … +``` + +Confirm RED: + +```text +$ m test tests +m test: 1 suite(s), 0 passed, 1 failed, 0/0 assertions passed +FAIL REQSTATSTST (0/0 passed) +``` + +(The 0/0 result is because the test routine errored at the first +`$$classify^REQSTATS` call — the implementation doesn't exist yet. +A direct `mumps -run` shows the actual `LABELMISSING` error.) + +**Path discovery quirk.** `m test` (no args) defaults to the +VistA-style `routines/tests/` layout. `m new` scaffolds a sibling +`tests/`, so you pass `m test tests` explicitly for the path. (Same +shape as `pytest tests/`.) + +### 5.2 GREEN — implement + +The full `REQSTATS.m` is in `~/m-work/reqstats/routines/REQSTATS.m`. +Key bits: + +```m +classify(status) + if status<200!(status>599) quit "other" + quit (status\100)_"xx" + ; +aggregate(rows,out) + ; Walks rows(i,j) populated by $$parse^STDCSV. + new i,sizes + set i="" + for set i=$order(rows(i)) quit:i="" do + . new status,bytes,bucket + . set status=$get(rows(i,4)) + . set bytes=+$get(rows(i,5)) + . set bucket=$$classify(status) + . set out("class",bucket,"count")=$get(out("class",bucket,"count"))+1 + . set out("class",bucket,"bytes")=$get(out("class",bucket,"bytes"))+bytes + . set out("totals","requests")=$get(out("totals","requests"))+1 + . set out("totals","bytes")=$get(out("totals","bytes"))+bytes + . set sizes($order(sizes(""),-1)+1)=bytes + set out("totals","mean_bytes")=$$mean^STDMATH(.sizes) + quit + ; +summarize(csv) + new rows,plain,tree + do parse^STDCSV(csv,.rows) + do aggregate(.rows,.plain) + do toJsonTree(.plain,.tree) ; lift plain → STDJSON sigil format + quit $$encode^STDJSON(.tree) +``` + +Run tests: + +```text +$ m test tests +m test: 1 suite(s), 1 passed, 15/15 assertions passed +ok REQSTATSTST (15/15 passed) +``` + +15/15 — every classify case, every aggregate path, the full +end-to-end summarize→JSON→parse round-trip. + +### 5.3 Format + select a lint profile + +```text +$ m fmt --check routines/REQSTATS.m tests/REQSTATSTST.m +m fmt: all formatted, 2 unchanged +``` + +Before running lint, **survey the available rule profiles** so you +pick the one that matches your project's house style. `m new` +scaffolds `[lint] rules = "default"` — m-cli's curated daily-lint +subset — but for this app we want the stricter Python-flavoured +preset since we're writing in modern lowercase style. + +```text +$ m lint --list-profiles +m lint profiles: + all 80 rule(s) Every registered rule, regardless of tag or profile. + default 34 rule(s) m-cli's curated daily-lint set — M-MOD-NN minus the four pedantic style rules. + modern 38 rule(s) Full M-MOD-NN modernization track (includes pedantic style rules). + pedantic 4 rule(s) Just the four pedantic style rules (commands-per-line, label-docstring, + magic-numbers, single-letter-vars). + pythonic 38 rule(s) Python-style preset: modern + tighter thresholds (line_length=100, + commands_per_line=1, cyclomatic=10, …). + sac 23 rule(s) VA SAC portable subset — non-VistA rules tagged `sac`. + vista 8 rule(s) VA VistA-Kernel-specific rules. Opt in only for VistA M code. + vista-full 42 rule(s) XINDEX + vista + sac. Recommended with --target-engine=yottadb. + xindex 34 rule(s) Engine-neutral subset of the VA Toolkit ^XINDEX rule set. +``` + +We're writing modern lowercase non-VistA code, so **`pythonic`** is +the right pick — it's the full M-MOD modernization track plus tighter +PEP-8-ish thresholds. The `vista` and `vista-full` / `sac` profiles +emit false positives outside VistA, and `default` is too lax for the +strict style this project wants. + +Pin the choice in `.m-cli.toml` so every contributor's `m lint` / +LSP integration gets the same answer: + +```toml +# ~/m-work/reqstats/.m-cli.toml +[fmt] +rules = "pythonic-lower" # lowercase keywords (set, write, $length) + +[lint] +# `pythonic` = modern M-MOD-NN ruleset (no VA / VistA / XINDEX) with +# PEP-8-flavoured thresholds: line_length=100, commands_per_line=1, +# cyclomatic=10. Selected via `m lint --list-profiles`. +rules = "pythonic" +``` + +Then run lint — it picks up the config automatically (`m lint` walks +up from cwd looking for `.m-cli.toml`): + +```text +$ m lint routines/REQSTATS.m tests/REQSTATSTST.m +routines/REQSTATS.m:13:2: [S] M-MOD-009: Line has 2 commands (limit: 1) +routines/REQSTATS.m:13:12: [S] M-MOD-031: Magic numeric literal 200 — extract to a named constant +routines/REQSTATS.m:13:24: [S] M-MOD-031: Magic numeric literal 599 — extract to a named constant +routines/REQSTATS.m:14:15: [S] M-MOD-031: Magic numeric literal 100 — extract to a named constant +routines/REQSTATS.m:16:1: [I] M-MOD-029: Label 'aggregate' comment density 6% below threshold 10% (1/15 non-blank lines) +routines/REQSTATS.m:17:6: [S] M-MOD-032: Single-letter variable 'i' outside FOR loop counter — pick a meaningful name +… +``` + +The findings are **STYLE (S)** and **INFO (I)** severity — not +errors — so `m lint`'s exit is 0. They're real signal under the +pythonic preset: magic numbers, single-letter vars, multi-command +lines. A real project would either fix them (extract named constants, +rename `i` to `rowIdx`, split lines), suppress per-call with +`; m-lint: disable=M-MOD-031`, or relax thresholds in +`[lint.thresholds]`. + +Use `--error-on=error` to gate CI on hard errors only, ignoring style: + +```bash +m lint --error-on=error routines/ tests/ +``` + +### 5.4 RED → GREEN: detecting and fixing a logic bug + +The happy-path transcript above shows GREEN test runs. The interesting +case is what happens when something breaks. Inject a one-character +off-by-one into `classify` — integer-divide by `10` instead of `100`: + +```diff + classify(status) ; @summary HTTP status → bucket name (2xx/3xx/4xx/5xx/other) + if status<200!(status>599) quit "other" +- quit (status\100)_"xx" ++ quit (status\10)_"xx" +``` + +`m test` catches it immediately with `expected/actual` diffs per +failed assertion: + +```text +$ m test tests +m test: 1 suite(s), 0 passed, 1 failed, 6/15 assertions passed, 9 failed +FAIL REQSTATSTST (6/15 passed) + - 200 is 2xx + expected: =2xx + actual: =20xx + - 301 is 3xx + expected: =3xx + actual: =30xx + - 404 is 4xx + expected: =4xx + actual: =40xx + - 500 is 5xx + expected: =5xx + actual: =50xx + - two 2xx + expected: =2 + actual: = + - one 5xx + expected: =1 + actual: = + - 4000 bytes 2xx + expected: =4000 + actual: = + - JSON mentions 2xx + expected: to contain "2xx" + actual: "{"class":{"20xx":{...},"50xx":{...}},…}" + - JSON mentions 5xx + expected: to contain "5xx" + actual: "{"class":{"20xx":{...},"50xx":{...}},…}" +``` + +**Exit code 1** — CI gates fail correctly. Nine distinct symptoms +from one character; that locality is exactly what "many small unit +tests" buys you over a single end-to-end assertion. Three layers +report the same root cause: + +- **Direct (`tClassify`):** 4 failures. `classify(200)` returned + `20xx` instead of `2xx` — the integer-division divisor is wrong. +- **Cascade (`tAggregateCounts`/`tAggregateBytes`):** 3 failures. + The aggregator writes into `out("class",bucket,…)` keyed by + classify's return value. Bucket name is wrong → the expected + bucket key (`"2xx"`) is missing → `$get(...)` returns `""`. +- **End-to-end (`tSummarizeJson`):** 2 failures. The JSON output + surfaces the wrong bucket names (`20xx`, `50xx`) — the + `actual:` field shows the entire failing JSON, making the + shape of the bug visible without spelunking through globals. + +For CI integration, the same run in TAP format: + +```text +$ m test tests --format=tap +TAP version 13 +1..15 +not ok 1 - REQSTATSTST: 200 is 2xx + --- + expected: =2xx + actual: =20xx + ... +not ok 2 - REQSTATSTST: 301 is 3xx + … +``` + +To zoom in on just the failing label while debugging: + +```text +$ m test tests/REQSTATSTST.m::tClassify +m test: 1 suite(s), 0 passed, 1 failed, 1/5 assertions passed, 4 failed +FAIL REQSTATSTST::tClassify (1/5 passed) + - 200 is 2xx + expected: =2xx + actual: =20xx + … +``` + +The diff pattern is unmistakable: every result is `N0xx` where it +should be `Nxx`. Integer-dividing 200 by `10` yields `20`; dividing +by `100` yields `2`. Revert the change: + +```diff + classify(status) ; @summary HTTP status → bucket name (2xx/3xx/4xx/5xx/other) + if status<200!(status>599) quit "other" +- quit (status\10)_"xx" ++ quit (status\100)_"xx" +``` + +Re-run: + +```text +$ m test tests +m test: 1 suite(s), 1 passed, 15/15 assertions passed +ok REQSTATSTST (15/15 passed) +``` + +GREEN. **Total round-trip from RED to GREEN: one edit, one re-run.** + +This is the canonical TDD inner-loop signal: a precise failure +report locates the wrong line of code to within a single +character. The same kind of feedback is what +`m fmt`/`m lint`/`m coverage` provide for their respective +concerns — together they make the toolchain a four-way safety net. + +### 5.5 Useful inner-loop verbs not run here + +- **`m watch`** — long-running file watcher. Start it in a terminal + pane; every save re-runs the affected suite. Skipped in this + walkthrough because it's interactive. +- **`m run "^REQSTATS"`** — ad-hoc routine invocation. The + scaffolded `REQSTATS` entry just `quit`s, so the output is empty + but exit 0. Useful for debugging real programs that need + `$ZCMDLINE` argv: + + ```text + $ m run "^REQSTATS" + m run: DockerEngine → ^REQSTATS + ``` + +--- + +## 6. Coverage gate — `m coverage` + +The final inner-loop step before pre-commit. Verifies the test +suite actually exercises the production code, not just adjacent +paths. + +```text +$ m coverage --routines routines/REQSTATS.m --tests tests +m coverage: 1 suite(s), 4/4 labels (100.0%) +Routine Covered Total Percent +-------------------- --------- --------- --------- +REQSTATS 4 4 100.0% +-------------------- --------- --------- --------- +Total 4 4 100.0% +``` + +100% label coverage on the production routine. Every public label +(`classify`, `aggregate`, `toJsonTree`, `summarize`) was hit by at +least one test path. + +For finer-grained reporting: + +```text +$ m coverage --routines routines/REQSTATS.m --tests tests --lines +… +$ m coverage --routines routines/REQSTATS.m --tests tests --branch +… +$ m coverage --routines routines/REQSTATS.m --tests tests --format=lcov +… +``` + +LCOV output is consumable by `genhtml`, Codecov, Coveralls — wire +it into CI for trend-tracking dashboards. + +--- + +## 7. Introspection — `m capabilities` and `m plugins` + +After the inner loop, the introspection surfaces show what's +available: + +```text +$ m capabilities --json | jq .subcommands.test.options +[ + {"name": "paths", "help": "…", "default": null, "choices": null}, + … +] +``` + +`m capabilities` is dominantly tooling-driven (`make manifest`, +CI, AI agents). The bare-TTY form prints a short overview pointing +at `--json` for the full payload. + +```text +$ m plugins +m-cli plugin API v1 + +Registered plugins: (none) +``` + +No out-of-tree plugins installed here. `m-cli-extras` is the +reference plugin (ships `m corpus-stats`) — it would appear in +this list after `pip install m-cli-extras`. + +--- + +## 8. Surface coverage table + +| Command | Hit? | Where | +|---|---|---| +| `m doctor` | ✓ | §1 | +| `m engine status` | ✓ | §1 | +| `m engine version` | ✓ | §1 | +| `m engine exec` | ✓ | §1 | +| `m engine capabilities` | ✓ | §1 | +| `m engine install` / `start` / `stop` / `restart` / `logs` / `shell` | (described only) | §1 | +| `m engine reset` | (destructive — mentioned, not run) | §1 | +| `m stdlib list` | ✓ | §2 | +| `m stdlib doc` | ✓ | §2 | +| `m stdlib search` | ✓ | §2 | +| `m stdlib errors` | ✓ | §2 | +| `m stdlib examples` | (mentioned) | §2 | +| `m stdlib manifest` | (mentioned) | §2 | +| `m new` | ✓ | §3 | +| `m ci init` (preview) | ✓ | §3 | +| `m ci init --write` | ✓ | §3 | +| `m lsp` | (always-on; out of band) | — | +| `m fmt` | ✓ | §5.3 | +| `m lint` | ✓ | §5.3 | +| `m test` | ✓ | §5.1, §5.2 | +| `m watch` | (long-running — mentioned only) | §5.4 | +| `m run` | ✓ | §5.4 | +| `m coverage` | ✓ | §6 | +| `m capabilities` | ✓ | §7 | +| `m plugins` | ✓ | §7 | + +24 of the 28 distinct invocations exercised directly; 4 mentioned +in description (`m engine install` / `start` / `stop` / `restart` +/ `logs` / `shell` / `reset` — engine lifecycle verbs that aren't +needed once the container is healthy and running; `m watch` — +long-running; `m stdlib examples` / `manifest` — covered by the +similar `m stdlib doc` / `search` plumbing). + +--- + +## 9. What this walkthrough actually validated + +- **All three runtime tools** (`m run` / `m test` / `m coverage`) + route correctly through `detect_engine()` on a docker-only host. + Earlier in the engine refactor, these were all hardcoded to + `read_connection()` → SSH and silently failed. +- **m-stdlib is callable** from the engine container once vendored + into the project's `routines/` (STDCSV / STDMATH / STDJSON / + STDASSERT all exercised). The vendoring pattern is honest about + MUMPS's non-recursive routine search. +- **A 4-label production routine reached 100% label coverage** + end-to-end through real STDCSV parse → STDMATH mean → + toJsonTree → STDJSON encode pipeline. +- **The `m fmt`/`m lint` LSP-driven inner loop** runs against real + m-stdlib-using code without complaint (modulo the + M-MOD-020 false positives, which are warnings not errors). +- **`m ci init --write` correctly emits a CI workflow** that runs + the same gates the developer just ran locally. +- **A canonical user-error TDD arc** (§5.4) showed `m test`'s + expected/actual diffs catching a one-character off-by-one in + `classify` across three test layers (direct, cascade, end-to-end) + with nine distinct failure symptoms — RED → fix → GREEN in one + edit. + +The application lives at **`~/m-work/reqstats/`** for re-running +any step. Re-run the full chain with: + +```bash +cd ~/m-work/reqstats +m fmt --check routines/REQSTATS.m tests/REQSTATSTST.m +m lint routines/REQSTATS.m tests/REQSTATSTST.m +m test tests +m coverage --routines routines/REQSTATS.m --tests tests +``` + +If any step fails, the m-cli toolchain has regressed somewhere +between commit and the current state — this doc is the canonical +"does it still work?" gate. From 479ffc27ddd2d7508405b693706827c456d9ebc7 Mon Sep 17 00:00:00 2001 From: Rafael Richards Date: Tue, 12 May 2026 12:10:00 -0400 Subject: [PATCH 8/9] docs(profile): retarget TDD walkthrough link at in-org rehosted copy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the walkthrough is rehosted at docs/guides/m-tdd-stdlib-walkthrough.md (commit b2a65ae), the README should link there instead of the external m-cli URL — keeps the org landing page self-contained and renders the walkthrough inline. Co-Authored-By: Claude Opus 4.7 (1M context) --- profile/README.md | 82 +++++++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/profile/README.md b/profile/README.md index ef1c54c..86d7f96 100644 --- a/profile/README.md +++ b/profile/README.md @@ -21,10 +21,52 @@ editor integrations, they form an end-to-end TDD stack that works identically for **InterSystems IRIS** and **YottaDB** developers maintaining modern (non-VistA) M code. -## For AI agents and automated tooling +## AI-integrated out-of-the-box m-dev-tools ships an MCP server ([`m-dev-tools-mcp`](https://pypi.org/project/m-dev-tools-mcp/), also listed on the [official MCP registry](https://registry.modelcontextprotocol.io/) as `io.github.m-dev-tools/m-dev-tools-mcp`) that exposes `route_intent` / `describe` / `verify` over the catalog so any MCP-capable agent (Claude Code, Codex, Continue, …) can resolve plain-English M-tooling intent without guessing. See the [**AI users guide**](../docs/ai-discoverability/ai-users-guide.md) for install paths (PyPI, `.mcp.json`, registry-driven), example sessions, and the no-MCP fallback that walks `tools.json` directly. + +## Why we need modern M Developer Tools + +M (MUMPS) is the language behind a great deal of healthcare and financial +infrastructure, but its modern developer tooling has historically lagged +behind mainstream languages. The 2026 cross-engine gap analysis +([`docs/history/m-tools-gap-analysis.md`](../docs/history/m-tools-gap-analysis.md)) inventoried the deficit — no test runner, no logic linter, no formatter, +no single-test selection, no test watcher — and ranked the missing pieces +into [four impact tiers](../docs/history/m-tools-gap-analysis.md#8-rank-ordered-developer-impact-where-to-invest-first). +**`m-dev-tools`** is the focused remediation of that top tier: the +**inner development loop** that mainstream language ecosystems take for +granted and that M has never had. + +The toolchain is **engine-neutral at the source layer** (`m fmt` and +`m lint` care about M syntax, not a specific runtime), so a working +install serves IRIS, YottaDB, and any future ANSI-compliant M engine +equally. + + +## Getting started + +See the [Getting started guide](../docs/guides/m-dev-tools-setup.md) +for prerequisites, install paths, verification, and troubleshooting. + +```bash +curl -O https://raw.githubusercontent.com/m-dev-tools/.github/main/setup.sh +less ./setup.sh +bash ./setup.sh +``` + +## Example of M Test-Driven Development with the M Standard Library + +The [m-cli TDD lifecycle walkthrough](../docs/guides/m-tdd-stdlib-walkthrough.md) +is an end-to-end transcript of building a small data-analysis app — +`reqstats`, an HTTP-access-log summarizer — using only the `m` +toolchain and `m-stdlib`. Exercises every `m ` (fmt / +lint / test / coverage / watch / lsp / new / run / build / ci) and +the standard library it consumes. The fastest way to see a modern +M inner loop in action on a clean host. + + + ## Repositories ### Foundation @@ -165,44 +207,6 @@ m-dev-tools ships an MCP server ([`m-dev-tools-mcp`](https://pypi.org/project/m- `m lint --rules=default` produces ~3 findings per routine on modern code rather than the ~57 the legacy XINDEX rules emit. -## Why this exists - -M (MUMPS) is the language behind a great deal of healthcare and financial -infrastructure, but its modern developer tooling has historically lagged -behind mainstream languages. The 2026 cross-engine gap analysis -([`docs/history/m-tools-gap-analysis.md`](../docs/history/m-tools-gap-analysis.md)) -inventoried the deficit — no test runner, no logic linter, no formatter, -no single-test selection, no test watcher — and ranked the missing pieces -into [four impact tiers](../docs/history/m-tools-gap-analysis.md#8-rank-ordered-developer-impact-where-to-invest-first). -**`m-dev-tools`** is the focused remediation of that top tier: the -**inner development loop** that mainstream language ecosystems take for -granted and that M has never had. - -The toolchain is **engine-neutral at the source layer** (`m fmt` and -`m lint` care about M syntax, not a specific runtime), so a working -install serves IRIS, YottaDB, and any future ANSI-compliant M engine -equally. - -## Getting started - -See the [Getting started guide](../docs/guides/m-dev-tools-setup.md) -for prerequisites, install paths, verification, and troubleshooting. - -```bash -curl -O https://raw.githubusercontent.com/m-dev-tools/.github/main/setup.sh -less ./setup.sh -bash ./setup.sh -``` - -## Example of Modern M Test-Driven Development and M Standard Library - -The [m-cli TDD lifecycle walkthrough](https://github.com/m-dev-tools/m-cli/blob/main/docs/m-tdd-lifecycle-walkthrough.md) -is an end-to-end transcript of building a small data-analysis app — -`reqstats`, an HTTP-access-log summarizer — using only the `m` -toolchain and `m-stdlib`. Exercises every `m ` (fmt / -lint / test / coverage / watch / lsp / new / run / build / ci) and -the standard library it consumes. The fastest way to see a modern -M inner loop in action on a clean host. ## Licensing From 077b8d2e5e547792b066fd956ceb9ff43262afdf Mon Sep 17 00:00:00 2001 From: Rafael Richards Date: Tue, 12 May 2026 12:26:54 -0400 Subject: [PATCH 9/9] docs(guides): replace TDD walkthrough Prerequisites section with link MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Prerequisites section duplicated the Getting started guide (75 lines of system-tools + clone + venv + engine-boot + verify steps). Replace with a 5-line pointer at docs/guides/m-dev-tools-setup.md; the walkthrough now opens with "assumes a green m doctor" and goes straight to §0 Scenario. Also trims the doubled `---` separator between the section and §0. Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/guides/m-tdd-stdlib-walkthrough.md | 94 ++++--------------------- 1 file changed, 12 insertions(+), 82 deletions(-) diff --git a/docs/guides/m-tdd-stdlib-walkthrough.md b/docs/guides/m-tdd-stdlib-walkthrough.md index 5b034a2..ea9f89b 100644 --- a/docs/guides/m-tdd-stdlib-walkthrough.md +++ b/docs/guides/m-tdd-stdlib-walkthrough.md @@ -5,7 +5,7 @@ revisions: 1 doc_type: [WORKED-EXAMPLE, TUTORIAL, SMOKE-TEST] --- -# m-cli TDD lifecycle walkthrough +## M Test-Driven Development: A Walkthrough End-to-end transcript of a real M developer building a small data-analysis application — **`reqstats`**, an HTTP-access-log @@ -27,82 +27,12 @@ inner-loop chain end to end. --- -## Prerequisites — turnkey setup on a fresh host +## Prerequisites -Anyone on any machine should be able to follow this walkthrough from -zero. Setup is one-time per machine. - -### System tools - -| Tool | Why | Verify | -| ------------- | ----------------------------------------- | ------------------ | -| **git** | clone the repos | `git --version` | -| **docker** | runs the m-test-engine YottaDB container | `docker --version` | -| **Python 3.12+** | m-cli is a Python package | `python3 --version` | -| **uv** | m-cli's dependency manager + venv | `uv --version` | -| **make** | optional; convenience targets | `make --version` | - -On Linux: `apt install git docker.io python3.12 make`, then -[install uv](https://docs.astral.sh/uv/getting-started/installation/) -(`curl -LsSf https://astral.sh/uv/install.sh | sh`). On macOS: -`brew install git docker python@3.12 uv`. Docker requires the daemon -running (Docker Desktop on macOS / Windows, `systemctl start docker` -on Linux). - -### Clone the repos - -m-cli has two hard dependencies that must live as sibling checkouts — -its `pyproject.toml` declares them by relative path. m-stdlib is the -library we're going to call from `reqstats`, so we need that too. - -```bash -mkdir -p ~/m-dev-tools && cd ~/m-dev-tools -git clone https://github.com/m-dev-tools/tree-sitter-m -git clone https://github.com/m-dev-tools/m-standard -git clone https://github.com/m-dev-tools/m-cli -git clone https://github.com/m-dev-tools/m-stdlib -``` - -(`tree-sitter-m` is the parser m-cli builds on; `m-standard` is the -language reference m-cli loads keyword/symbol tables from. Both are -mandatory.) - -### Install m-cli into a venv - -```bash -cd ~/m-dev-tools/m-cli -make install # uv sync --extra dev + pre-commit hooks -.venv/bin/m --version # m-cli 0.1.0 -``` - -Add `~/m-dev-tools/m-cli/.venv/bin` to your `PATH` (or use direnv) so -the bare `m` command works without the explicit prefix used in the -transcript below. - -### Bootstrap the engine container - -```bash -m engine install # docker pull ghcr.io/m-dev-tools/m-test-engine:0.1.0 -m engine start # docker run -d -v $HOME/m-work:/m-work ... -``` - -The first call pulls the image (~150 MB) from GHCR; the second starts -a long-running container named `m-test-engine` with `$HOME/m-work` -bind-mounted at `/m-work`. The bind-mount is the entire point: every -M project under `~/m-work/` is automatically visible inside the -container at the matching path, no per-project mount setup. - -### Verify - -```bash -mkdir -p ~/m-work # bind-mount root -m doctor # all checks should be ✓ -``` - -If `m doctor` reports anything other than 7 OK, fix that before -proceeding — every command below depends on the engine being healthy. - ---- +See the [Getting started guide](m-dev-tools-setup.md) for the +turnkey-setup-on-a-fresh-host path — prerequisites, install via +`setup.sh` (or manual), `m doctor` verification, and troubleshooting. +The walkthrough below assumes a green `m doctor`. --- @@ -481,12 +411,12 @@ up from cwd looking for `.m-cli.toml`): ```text $ m lint routines/REQSTATS.m tests/REQSTATSTST.m -routines/REQSTATS.m:13:2: [S] M-MOD-009: Line has 2 commands (limit: 1) -routines/REQSTATS.m:13:12: [S] M-MOD-031: Magic numeric literal 200 — extract to a named constant -routines/REQSTATS.m:13:24: [S] M-MOD-031: Magic numeric literal 599 — extract to a named constant -routines/REQSTATS.m:14:15: [S] M-MOD-031: Magic numeric literal 100 — extract to a named constant -routines/REQSTATS.m:16:1: [I] M-MOD-029: Label 'aggregate' comment density 6% below threshold 10% (1/15 non-blank lines) -routines/REQSTATS.m:17:6: [S] M-MOD-032: Single-letter variable 'i' outside FOR loop counter — pick a meaningful name +routines/REQSTATS.m:13:2: [STYLE] M-MOD-009: Line has 2 commands (limit: 1) +routines/REQSTATS.m:13:12: [STYLE] M-MOD-031: Magic numeric literal 200 — extract to a named constant +routines/REQSTATS.m:13:24: [STYLE] M-MOD-031: Magic numeric literal 599 — extract to a named constant +routines/REQSTATS.m:14:15: [STYLE] M-MOD-031: Magic numeric literal 100 — extract to a named constant +routines/REQSTATS.m:16:1: [INFO] M-MOD-029: Label 'aggregate' comment density 6% below threshold 10% (1/15 non-blank lines) +routines/REQSTATS.m:17:6: [STYLE] M-MOD-032: Single-letter variable 'i' outside FOR loop counter — pick a meaningful name … ```