| title | m-stdlib — implementation plan | |
|---|---|---|
| status | in progress (Phase 0 not yet started) | |
| last-updated | 2026-04-30 | |
| companion | m-libraries-remediation.md (background; this doc is the live work plan) | |
| created | 2026-04-30 | |
| last_modified | 2026-05-09 | |
| revisions | 12 | |
| doc_type |
|
This is the live, continuously updated plan for building m-stdlib.
Tick boxes as work lands. Update the Current state section at the
top of every working session. The companion m-libraries-remediation.md
holds the background and rationale; this document holds the work.
| Phase | Status | Tag |
|---|---|---|
| Phase 0 — bootstrap | done (2026-04-30) | — |
| Phase 1 — pure-M quick wins | done (2026-05-05) — v0.1.0 shipped (9 modules: STDASSERT, STDUUID, STDB64, STDHEX, STDFMT, STDLOG, STDDATE, STDCSV, STDARGS) |
v0.1.0 |
| Phase 1b — TDD primitives | in progress — STDMOCK (v0.1.2) + STDSEED (v0.1.3) green; STDFIX (v0.1.1) pending |
→ M1 |
| Phase 2 — pure-M heavy lifting | in progress — STDCOLL ✅ green; STDURL ✅ green; STDREGEX ✅ engine green (Passes A–E + raise-helper fix; non-engine items in flight per TODO §"In flight"); STDJSON substance landed and observed-healthy (53 consecutive ok mid-stream before m-cli's per-suite budget; 0/0 was a runner-timeout artifact, not a real failure — see memory project_m_stdlib.md) |
→ v0.2.0 |
| Phase 3 — host-call integrations | not started | → v0.3.0 |
Next concrete unit of work: Phase 1b sequencing — STDFIX (v0.1.1)
or M1 sync (each Phase 1b module pairs with a m-cli companion track,
per tdd-orchestration-plan.md). In parallel: complete Phase 2
modules (STDREGEX passes A–E; STDJSON; STDURL).
These rules govern every commit. They are not phase-specific.
- TDD first, always. Write the
*TST.msuite before the implementation. Confirm the test fails (ImportError on the routine, or assertion error). Only then write the routine. Re-run; confirm green. This is the Tier-1 rule for all~/projects/work — it applies here too. - Every module ships with a full unit-test suite. No module
merges without
*TST.mcovering: happy path, all documented edge cases, all error paths, all RFC/spec corner cases where applicable (RFC-4180 for CSV, RFC-4648 for B64/HEX, RFC-4122 for UUID, RFC-8259 for JSON, RFC-3986 for URL, ISO-8601 for STDDATE). - Every module is exercised on a real project. Unit tests prove the module works in isolation; real-project exercise proves it works under the m-cli toolchain end-to-end (fmt, lint, test, coverage, LSP) and integrates with actual M code. See §10 for the strategy.
- All M code is in modern Pythonic style. See §3.
- m-stdlib has priority over m-cli. When stdlib conventions (assertions, log format, error-code shape) tension with m-cli's internals, the stdlib wins; m-cli adapts via a companion PR.
- Per-module acceptance gate in §9 must be green before any module merges. No exceptions.
"Pythonic" here is about workflow and structure, not syntax:
- Project shape mirrors a Python project:
src/,tests/,docs/,Makefile,.devcontainer/,.github/workflows/, pre-commit hooks, branch-protected CI. - TDD-first (per §2.1). Tests live alongside source in
tests/, one*TST.mper*.m. - One responsibility per routine, small focused labels. Labels read like Python functions: short, single-purpose, independently testable. No mega-routines.
- Public API documented at the label. Every public label carries
a
; doc:comment block above it: signature, args, returns, raises, example. Drivesm lsphover and (eventually)m docs. - No print() in library code. Use
STDLOGonce it ships; until then, leave logging to the caller.WRITEonly inexamples/and in the*TST.mfailure messages. - Globals are namespaced:
^STDLIB($J,...)for per-process state,^STDLIBC(...)for shared config. No naked globals from any STD routine. - Errors are structured. Set
$ECODEwith a documented error code; do notWRITE-and-HALT. STDASSERT verifies error codes, not error text. - No mocks unless unavoidable. Tests use real fixtures (real byte strings, real JSON files, real timestamps). Network/IO callouts in Phase 3 are the only place a fake is acceptable.
- m-cli linting is the gate.
m fmt --checkclean,m lint --error-on=errorclean (default profile,--target-engine=any). M-XINDX-057 (mixed-case lvn) is downgraded to INFO in.m-cli.tomlfor parametrised modules (STDFMT, STDJSON); everywhere else it's the default WARNING. - Routine prefix is
STD(reserved family-wide); test-suite suffix isTST.
- License: AGPL-3.0. Per-module relicense escape hatch only if a specific case demands it.
- Versioning: SemVer. Pre-1.0 minors may include breaking changes
(documented in
CHANGELOG.md). - Milestone tags:
v0.0.1— STDASSERT + STDUUID, CI green.v0.0.2–v0.0.7— one Phase-1 module per tag.v0.1.0— Phase 1 complete.v0.2.0— Phase 2 complete.v0.3.0— Phase 3 complete.v1.0.0— API stable for 3 months afterv0.3.0.
- Vendor scope: YottaDB primary; IRIS portable where the cost is
reasonable (dispatch on
$ZASCII/$ASCII,$ZTIMESTAMP/$ZHOROLOG,$ZF/$CLASSMETHOD); GT.M out permanently. IRIS portability job is fail-soft until v0.0.4, then reintroduced. - Repo: local
~/projects/m-stdlib; remotegithub.com/m-dev-tools/m-stdlib, public. - Assertion library: STDASSERT is canonical for m-stdlib and the whole project family. m-stdlib does not depend on m-tools.
m-stdlib/
├── README.md
├── LICENSE # AGPL-3.0
├── CHANGELOG.md
├── Makefile
├── .m-cli.toml # fmt + lint + lsp config
├── .pre-commit-config.yaml # repo: local — invokes locally-installed m
├── .devcontainer/
│ ├── Dockerfile
│ └── devcontainer.json
├── .github/workflows/
│ ├── ci.yml
│ └── release.yml
├── docs/
│ ├── m-stdlib-implementation-plan.md # this file
│ ├── m-libraries-remediation.md # background
│ └── modules/
│ ├── stdassert.md
│ ├── stduuid.md
│ └── ... # one per src module
├── src/
│ ├── STDASSERT.m
│ ├── STDUUID.m
│ ├── STDB64.m
│ ├── STDHEX.m
│ ├── STDFMT.m
│ ├── STDLOG.m
│ ├── STDDATE.m
│ ├── STDCSV.m
│ ├── STDARGS.m
│ ├── STDJSON.m # Phase 2
│ ├── STDREGEX.m # Phase 2
│ ├── STDCOLL.m # Phase 2
│ ├── STDURL.m # Phase 2
│ ├── STDHTTP.m # Phase 3
│ ├── STDCRYPTO.m # Phase 3
│ └── STDCOMPRESS.m # Phase 3
├── tests/
│ ├── STDASSERTTST.m
│ ├── STDUUIDTST.m
│ ├── ... # one TST per src
│ └── conformance/
│ ├── b64/ # RFC-4648 §10 vectors
│ ├── csv/ # RFC-4180 corner cases
│ ├── json/ # JSONTestSuite vendored (Phase 2)
│ └── uuid/ # RFC-4122 test vectors
├── examples/ # runnable demos referenced from docs
└── tools/
└── build-callouts.sh # Phase 3 only
Pull all candidate images locally and pick the most reliable:
-
yottadb/yottadb-base:latest-master -
yottadb/yottadb -
yottadb/yottadb:r2.02(and any newer tagged release line)
Pick on: (a) exists on Docker Hub, (b) starts cleanly, (c) has
mumps and mupip on PATH. Document the choice in the
Dockerfile and ci.yml as a comment.
# Image pinned per §6.0 verification. Reason: <fill in after pinning>
FROM yottadb/yottadb-base:latest-master
USER root
RUN apt-get update && apt-get install -y --no-install-recommends \
python3.12 python3.12-venv python3-pip git build-essential \
libssl-dev libcurl4-openssl-dev libsodium-dev zlib1g-dev libpcre2-dev \
&& rm -rf /var/lib/apt/lists/*
# m-cli installed from git checkout. Distribution model is git-clone-and-install
# (no package registry). tree-sitter-m must be installed first so its local
# checkout satisfies m-cli's dependency declaration.
RUN git clone https://github.com/m-dev-tools/tree-sitter-m /opt/tree-sitter-m && \
git clone https://github.com/m-dev-tools/m-cli /opt/m-cli && \
python3.12 -m venv /opt/m-cli/.venv && \
/opt/m-cli/.venv/bin/pip install /opt/tree-sitter-m && \
/opt/m-cli/.venv/bin/pip install -e "/opt/m-cli[lsp]"
USER yottadb
WORKDIR /workspace[fmt]
rules = "canonical"
[lint]
rules = "default"
disable = []
severity = { "M-XINDX-057" = "INFO" } # mixed-case lvn — STDFMT/STDJSON parametrised
target-engine = "any"
[lsp]
hover.format = "markdown".PHONY: all setup-ydb install-test-deps fmt fmt-check lint test coverage check ci clean
all: check
setup-ydb:
@mkdir -p .ydb .objects
@if [ ! -f .ydb/m-stdlib.gld ]; then \
. /opt/yottadb/ydb_env_set && mumps -run GDE <<EOF ; \
change -region DEFAULT -dynamic_segment=DEFAULT ; \
change -segment DEFAULT -file_name=.ydb/m-stdlib.dat ; \
exit ; \
EOF \
mupip create ; \
fi
install-test-deps:
@/opt/m-cli/.venv/bin/m --version
fmt: ; m fmt src/ tests/
fmt-check: ; m fmt --check src/ tests/
lint: ; m lint --error-on=error src/ tests/
test: ; m test tests/
coverage: ; m coverage --min-percent=85 --format=lcov > coverage.lcov
check: fmt-check lint test coverage
@echo "OK"
ci: check
@m test --format=tap > test-results.tap
@m coverage --format=json > coverage.json
clean:
rm -rf .ydb .objects coverage.lcov test-results.tap coverage.jsonrepo: local form — invokes the locally-installed m:
repos:
- repo: local
hooks:
- id: m-fmt
name: m fmt --check
entry: /opt/m-cli/.venv/bin/m fmt --check
language: system
files: \.m$
- id: m-lint
name: m lint --error-on=error
entry: /opt/m-cli/.venv/bin/m lint --error-on=error
language: system
files: \.m$
# TODO: swap to `repo: https://github.com/m-dev-tools/m-cli` once m-cli ≥ v0.1.0
# publishes its `.pre-commit-hooks.yaml` against a release tag.name: CI
on:
push:
branches: [main]
pull_request:
jobs:
m-stdlib:
runs-on: ubuntu-latest
container: yottadb/yottadb-base:latest-master # pin per §6.0
strategy:
fail-fast: false
matrix:
ydb-version: ["r2.02", "latest-master"]
steps:
- uses: actions/checkout@v4
- name: Install Python toolchain
run: |
apt-get update && apt-get install -y python3.12 python3.12-venv git
python3.12 -m venv /tmp/venv
/tmp/venv/bin/pip install --upgrade pip
- name: Install m-cli (from git until post-Phase-1 publication)
run: |
git clone --depth=1 https://github.com/m-dev-tools/m-cli /tmp/m-cli
/tmp/venv/bin/pip install -e /tmp/m-cli[lsp]
- name: Initialise YDB
run: . /opt/yottadb/ydb_env_set && make setup-ydb
- name: Format check
run: . /opt/yottadb/ydb_env_set && PATH=/tmp/venv/bin:$PATH make fmt-check
- name: Lint
run: . /opt/yottadb/ydb_env_set && PATH=/tmp/venv/bin:$PATH make lint
- name: Test (TAP)
run: |
. /opt/yottadb/ydb_env_set
PATH=/tmp/venv/bin:$PATH m test --format=tap | tee test-results.tap
- name: Upload TAP
uses: actions/upload-artifact@v4
with:
name: tap-${{ matrix.ydb-version }}
path: test-results.tap
- name: Coverage (lcov)
run: |
. /opt/yottadb/ydb_env_set
PATH=/tmp/venv/bin:$PATH m coverage --format=lcov > coverage.lcov
- name: Upload coverage
if: matrix.ydb-version == 'latest-master'
uses: codecov/codecov-action@v4
with:
files: coverage.lcov
fail_ci_if_error: true
# Reintroduce at v0.0.4 per §4 (vendor scope). Until then, this job is omitted.
# iris-portability-check:
# if: github.event_name == 'pull_request'
# runs-on: ubuntu-latest
# container: intersystemsdc/iris-community:latest
# continue-on-error: true
# steps: ...name: Release
on:
push:
tags: ["v*.*.*"]
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Build distributable
run: |
mkdir -p dist
tar czf "dist/m-stdlib-${GITHUB_REF_NAME}-src.tar.gz" \
--transform "s,^,m-stdlib-${GITHUB_REF_NAME#v}/," \
src tests docs README.md LICENSE
- uses: softprops/action-gh-release@v2
with:
files: dist/*
generate_release_notes: true- 7.1 YottaDB image pinned —
yottadb/yottadb-base:latest-master(YottaDB r2.07 at pin time).mumps/mupiplive at/opt/yottadb/current/; reachable after sourcingydb_env_set. Comment recorded in.devcontainer/Dockerfileandci.yml. - 7.2 Skeleton. Layout per §5; root files written;
git init. - 7.3 Devcontainer.
Dockerfile+devcontainer.jsonwired per §6.1–§6.2. Container build deferred (local toolchain is operational; CI will exercise the container). - 7.4 CI.
ci.yml+release.ymllanded per §6.6 with the IRIS portability job omitted (reintroduce at v0.0.4). First green run will follow the first push. - 7.5 README. ≤ 1 page; covers what the project is, milestone tags (§4), license, install-from-git instructions, devcontainer, submodule install, and links to this plan.
- 7.6 STDASSERT bootstrap probe. Stub
STDASSERT.mmirrors^TESTRUN's output protocol exactly (PASS/FAIL/Results: …).STDASSERTTST.mruns three assertions underm test— all 3/3 green via the existingt<UpperCase>(pass,fail)discovery. No m-cli change needed for v0.0.1's whole-suite execution. Single-test selection (m test FILE.m::tLabel) hard-codes^TESTRUNin m-cli/.../runner.py:171 lines 168–173 and is the deferred companion PR — not a blocker.
Local toolchain confirmed: YottaDB r2.02 at
/usr/local/lib/yottadb/r202, m-cli at ~/projects/m-cli/.venv/bin/m.
make check (fmt-check + lint + test) is green.
Phase 0 corrections folded in:
m lint --error-on=fatalwas an invalid value. Real options areerror|warning|style|info. Updated to--error-on=errorin the Makefile, pre-commit, CI, and §6.4 below.make checkno longer chainscoverage(probe stub coverage is 83.3%, below the 85% gate; coverage gating starts at v0.0.1 per §9). Coverage runs asmake coverageor viamake ci.setup-ydbextracted intotools/init-db.sh(m-tools-style:unset ydb_routinesbeforemumps -run GDE,mupip createafterwards).YDB_ENVin the Makefile uses bare exports (notydb_env_set) and proactively unsets stalegtm*vars from prior shell sessions.
Eight modules. Each merges as its own tag with the §9 acceptance gate
green. Each PR carries: source + *TST.m + docs/modules/<name>.md
CHANGELOG.mdentry. None of those are optional.
| Tag | Module(s) | Routine(s) | LoC est. | Tests est. | Status |
|---|---|---|---|---|---|
v0.0.1 |
Assertion library + UUID v4/v7 | STDASSERT.m, STDUUID.m |
~270 | ~70 | ✅ shipped 2026-04-30 — 166/166 assertions, 22/22 coverage |
v0.0.2 |
Base64 + Hex (RFC-4648) | STDB64.m, STDHEX.m |
~400 | ~80 | next |
v0.0.3 |
Printf-style formatter | STDFMT.m |
~300 | ~60 | |
v0.0.4 |
Structured logger (text-only) + IRIS CI re-add | STDLOG.m |
~200 | ~40 | |
v0.0.5 |
ISO-8601 datetime | STDDATE.m |
~400 | ~80 | ✅ green 2026-05-05 — 60/60 assertions, 19/20 labels (95.0%), 0 lint errors. Error-path raises tests deferred per STDASSERT.raises limitation. |
v0.0.6 |
RFC-4180 CSV | STDCSV.m |
~300 | ~50 | ✅ shipped 2026-05-05 — 59/59 assertions, 6/6 labels (100%), 0 lint errors. RFC-4180 §2 conformance corpus at tests/conformance/csv/. |
v0.0.7 |
argparse | STDARGS.m |
~400 | ~50 | ✅ shipped 2026-05-05 — 37/37 assertions, 14/14 labels (100%), 0 lint errors. |
v0.1.0 |
Phase 1 release: CHANGELOG roll-up, GitHub Release, source tarball, regenerated docs index | — | — | — |
Public API (sketch):
EQ(pass,fail,actual,expected,msg) ; equality
NE(pass,fail,actual,expected,msg) ; inequality
TRUE(pass,fail,cond,msg) ; truthy
FALSE(pass,fail,cond,msg) ; falsy
NEAR(pass,fail,a,b,eps,msg) ; float comparison
RAISES(pass,fail,code,errno,msg) ; XECUTE code, assert $ECODE matches
CONTAINS(pass,fail,haystack,needle,msg)
LEN(pass,fail,collection,n,msg)
Compatibility: all assertions update pass/fail counters via
the existing t<UpperCase>(pass,fail) discovery contract. No new
recogniser needed in m-cli for v0.0.1 — proven by §7.6 probe.
Tests: all assertion forms exercised in STDASSERTTST.m against
both passing and failing inputs. Verify counters increment correctly
in both branches; verify failure messages include msg when supplied.
Public API:
$$V4^STDUUID() ; random UUID v4
$$V7^STDUUID() ; time-ordered UUID v7
$$VALID^STDUUID(uuid) ; format validator
$$VARIANT^STDUUID(uuid) ; "rfc4122" | "ncs" | "microsoft" | "future"
$$VERSION^STDUUID(uuid) ; integer 1..7
Engine dispatch: v7 timestamps from $ZHOROLOG (YDB) /
$ZTIMESTAMP (IRIS).
Tests:
- 1000-roundtrip uniqueness check on V4 and V7.
- Bit-layout assertions: version nibble, variant bits.
- Monotonicity check on V7 (sorts in generation order).
- VALID/VARIANT/VERSION cover all 7 RFC-defined versions plus malformed.
Public API: ENCODE, DECODE, URLENCODE (-_, no padding),
URLDECODE, VALID.
Tests: RFC-4648 §10 vectors vendored to tests/conformance/b64/;
round-trip property test on random byte strings 0..1024 bytes; reject
malformed inputs (bad alphabet, bad padding, bad length).
Public API: ENCODE (lowercase default), ENCODEU (uppercase),
DECODE, VALID.
Tests: round-trip on random byte strings; case-insensitive decode; reject odd-length and non-hex inputs.
Public API:
$$F^STDFMT(template, a1, a2, ...) ; up to 9 positional
$$FN^STDFMT(template, .args) ; named substitution from local array
Format spec: subset of Python's str.format: {}, {0},
{name}, alignment (<, >, ^), width, precision, type
(s, d, f, x, X, o, b).
Tests: every spec field permutation against known outputs;
malformed templates raise documented $ECODE; precision rounding
uses $FNUMBER semantics.
Public API:
DEBUG^STDLOG(event, k1, v1, k2, v2, ...)
INFO^STDLOG(event, ...)
WARN^STDLOG(event, ...)
ERROR^STDLOG(event, ...)
FATAL^STDLOG(event, ...)
LEVEL^STDLOG(threshold) ; set runtime threshold
SINK^STDLOG(target) ; "stderr" | "stdout" | "global:^STDLOG"
Output format: key=value text in v0.0.4. JSON-line output added
in Phase 2 once STDJSON ships.
Tests: level filtering; key-value escaping (spaces, =, quotes);
sink dispatch; timestamp from STDDATE (deferred to v0.0.5 — until
then STDLOG ships with a minimal inline ISO timestamp helper which
is replaced when STDDATE lands).
v0.0.4 also: reintroduce IRIS iris-portability-check job in CI
(fail-soft).
Public API:
$$NOW^STDDATE() ; current ISO-8601 UTC
$$FROMH^STDDATE(horolog) ; $HOROLOG → ISO-8601
$$TOH^STDDATE(iso) ; ISO-8601 → $HOROLOG
$$STRFTIME^STDDATE(horolog, format) ; %Y-%m-%dT%H:%M:%S%z
$$STRPTIME^STDDATE(text, format)
$$ADD^STDDATE(horolog, duration) ; ISO-8601 duration P1DT2H30M
$$DIFF^STDDATE(h1, h2) ; → ISO-8601 duration
Coverage: timezone offsets +HH:MM/-HH:MM/Z; date-only
forms; sub-second precision (.SSS, .SSSSSS); proleptic Gregorian
leap-day arithmetic.
Tests: every documented format; timezone arithmetic across DST boundaries; leap years (1900 not, 2000 yes, 2400 yes); round-trip property test 0..36500 days.
Replaces: STDLOG's inline timestamp helper from v0.0.4 — bump
STDLOG to use $$NOW^STDDATE() and remove the inline helper.
Public API:
$$PARSE^STDCSV(text, .rows) ; → row count, populates rows(i,j)
$$WRITE^STDCSV(.rows) ; → RFC-clean CSV text
PARSEFILE^STDCSV(path, callback) ; streaming, calls callback per row
WRITEFILE^STDCSV(path, .rows)
Tests: quoted fields, embedded ,, embedded \n, "" escapes,
Windows (CRLF) and Unix (LF) line endings, BOM stripping. Conformance
corpus vendored to tests/conformance/csv/ covering RFC-4180 §2 every
clause and known broken-but-real-world inputs (excel-quirks).
Public API:
$$NEW^STDARGS(prog, description) ; → parser handle
ADDFLAG^STDARGS(p, long, short, action, dest)
ADDPOS^STDARGS(p, name, dest)
ADDSUB^STDARGS(p, name, subparser)
$$PARSE^STDARGS(p, argline) ; → namespace
$$HELP^STDARGS(p) ; → formatted help text
Args source: $ZCMDLINE on YDB; explicit string on IRIS.
Supports: long flags (--verbose), short flags (-v), grouped
short flags (-vvv), positional, sub-commands, -- terminator,
count/store/store_true/append actions.
Tests: every action × short/long form; error on unknown flag,
missing required positional, mutually-exclusive group violation;
--help output stable byte-for-byte against fixtures.
- All 8 modules tagged and shipped per §9 gate.
-
CHANGELOG.mdroll-up entry forv0.1.0. - GitHub Release created, source tarball attached.
-
docs/modules/index regenerated (table of all 8 modules with one-line descriptions). - STDLOG inline-timestamp helper removed (replaced by STDDATE).
- Real-project validation (§10) green for all 8 modules.
A module merges only when all boxes are checked:
-
m fmt --checkclean -
m lint --error-on=errorclean (default profile,--target-engine=any) -
m testis green on YottaDB -
m testis green on IRIS where reachable (fail-soft from v0.0.4) -
m coverage --min-percent=85is green for the new module (verified with--uncoveredshowing no uncovered public-API lines) -
m lspsurfaces hover docs for every public label (manual smoke or LSP Stage-4 test) -
docs/modules/<name>.mdwritten: synopsis, public API table, examples, edge cases, error codes -
CHANGELOG.mdentry added - Real-project validation (§10) added/updated for this module
If any gate fails because of a toolchain weakness, the weakness
becomes a P0 follow-up against m-cli or tree-sitter-m and is logged
to TOOLCHAIN-FINDINGS.md. m-stdlib is the regression suite for
the toolchain.
Unit tests prove a module works in isolation; real-project validation proves it works under the m-cli toolchain end-to-end and integrates with actual M code.
For every module, after unit tests pass, do all four:
- m-cli
make vista-canonicalsmoke. Confirm the new STD routine doesn't break m-cli's parser/lint output on the VistA corpus. Run from~/projects/m-cli:make vista-canonical M_STDLIB=~/projects/m-stdlib/src. - m-cli LSP smoke. Open the new
*.min VS Code with the tree-sitter-m extension; confirm hover, completion, formatting, code actions, definition, references, document symbols, code lens, folding, signature help, document highlight all behave on the public labels. - m-cli
m coveragesmoke. Runm coverageon the module's test suite; confirm lcov output is well-formed (genhtml renders it cleanly). - Adjacent-project consumption. Once the module has a clear
downstream consumer, integrate it there:
- STDASSERT → file P2 issues to migrate
^TESTRUN-using test suites in m-cli, tree-sitter-m, and m-standard onto STDASSERT. These migrations are the real-project validation for STDASSERT. - STDUUID, STDB64, STDHEX, STDFMT, STDLOG → consumed by
m-cli's runtime-Python side via the m-cli ydb runner — write
a small
examples/m-cli-integration.mthat uses each from M code, confirm it runs underm test. - STDDATE → STDLOG bumps to use it; that bump is the validation.
- STDCSV → vendor a real CSV from
~/data/(e.g. a VistA extract) intotests/conformance/csv/real/and round-trip parse/write it; assert byte-equivalent output. - STDARGS → write a tiny CLI demo in
examples/that takes long flags, short flags, sub-commands, and run it underm testwith several arglines.
- STDASSERT → file P2 issues to migrate
When STDASSERT lands in v0.0.1, file follow-up issues to migrate
existing ^TESTRUN-using suites onto STDASSERT:
- m-cli — verified no-op 2026-05-05. m-cli has no
*TST.mroutines outsidetests/fixtures/(which are SAC/parser fixtures, not test suites). m-cli's own tests are pure pytest in Python; M is invoked at runtime by them testrunner against consumer suites. The C1 fix (m-cli23241a2) made the runner protocol- aware so STDASSERT-driven suites in consumer projects work end- to-end — that is the actual TOOLCHAIN P1 closure. - tree-sitter-m — verified no-op 2026-05-05.
test/holds the tree-sitter grammar corpus only (corpus/*.txtparser cases +coverage/keywords.mtoken-coverage fixture). NoTESTRUNreferences anywhere in the tree. - m-standard — verified no-op 2026-05-05.
tests/is exclusively pytest (Python). M code insources/is the SAC / YDB / IRIS reference corpus being catalogued, not test suites. The loneTESTRUNhit indocs/m-libraries-remediation.mdis a reference to the legacy library — no source to migrate.
The actual STDASSERT real-project consumer turned out to be
m-tools, whose homegrown ^TESTRUN.m runner predated STDASSERT
by ~5 weeks. Migration shipped 2026-05-06 (m-tools commit 3eec0bf):
all 11 suites — CSVTST, GLOBALTST, GTREETST, HELLOTST,
IDXTST, JSONTST, SAFETST, STRFNSTST, TASKSTST, TXNTST,
VALIDATETST — renamed TESTRUN→STDASSERT (mechanical, API parity
exact); routines/tests/TESTRUN.m deleted. Tracked retroactively
as V4 in docs/parallel-tracks.md §3.6. The §10.1 item-4 gate
(adjacent-project consumption) is satisfied via this V4 migration.
Not started until v0.1.0 is tagged.
| Tag | Module | Routine | LoC est. | Status |
|---|---|---|---|---|
v0.1.x |
JSON parser/serialiser (RFC 8259) | STDJSON.m |
~1500 | |
v0.1.x |
Regex (Thompson-NFA, YDB; wraps $MATCH/$LOCATE on IRIS) |
STDREGEX.m |
~2000 | ✅ engine green 2026-05-05 (track L12) — 90/90 assertions, 0 lint errors. Passes A–E plus the raise-helper fix all landed (commits cfce923 3abf7e8 491eb38 c51a394 48da86e). Non-engine items per TODO §"In flight": coverage gate, real-project validation, IRIS dispatch (fail-soft), v0.2.0 sync. |
v0.1.x |
Collections (Set, Map, Stack, Queue, Deque, Heap, OrderedDict) | STDCOLL.m |
~600 | ✅ green 2026-05-05 (track L13) — 116/116 assertions, 51/51 labels (100%), 0 lint errors. |
v0.1.x |
URL parsing + percent-encoding (RFC 3986) | STDURL.m |
~250 | |
v0.2.0 |
Phase 2 release | — | — |
STDJSON stores JSON in M globals natively (^STDJSON($J,...));
streaming parse/serialise for multi-MB payloads. Conformance corpus:
JSONTestSuite vendored to tests/conformance/json/, plus property-
based round-trip checks.
STDLOG gains JSON-line output once STDJSON ships.
STDREGEX subset (no back-references, no lookaround, no Unicode
property classes); follow-on STDREGEX_PCRE (Phase 3-adjacent) for
full PCRE via $ZF to libpcre2.
STDCOLL API consistency across types is the work, not any individual data structure.
STDURL unblocks STDHTTP in Phase 3.
§9 acceptance gate applies. Real-project validation (§10) extends for each: STDJSON consumed by STDLOG; STDCOLL consumed by m-cli's existing M-side data structures (file P2 issue to migrate); STDURL consumed by STDHTTP integration tests in Phase 3.
Not started until v0.2.0 is tagged. Requires tools/build-callouts.sh
infrastructure (lands in a v0.2.x patch between Phase 2 and Phase 3).
| Tag | Module | Routine | Binding |
|---|---|---|---|
v0.2.x |
$ZF build harness (tools/build-callouts.sh) |
— | per-platform shared object pipeline |
v0.2.x |
HTTP/1.1 + HTTPS client | STDHTTP.m |
YDB: $ZF → libcurl; IRIS: $CLASSMETHOD → %Net.HttpRequest |
v0.2.x |
Crypto: SHA, HMAC, AES-GCM, Ed25519 | STDCRYPTO.m |
YDB: $ZF → libsodium (preferred) or OpenSSL; IRIS: %SYSTEM.Encryption |
v0.2.x |
Compression: gzip, zstd | STDCOMPRESS.m |
YDB: $ZF → libz, libzstd; IRIS: %Stream.Object compression |
v0.3.0 |
Phase 3 release | — | — |
§9 gate applies (with the addition that the build harness must
produce SOs for linux-x86_64, linux-aarch64, and macOS). Real-
project validation: STDHTTP and STDCRYPTO together exercised by an
examples/jwt-verify.m that fetches a JWKS over HTTPS, parses it
(STDJSON), verifies a JWT signature (STDCRYPTO), and decodes the
payload (STDB64).
Phase 3 release tarballs include the per-platform shared objects; IRIS users skip the SO download.
Tag v1.0.0 once the API surface has been stable for 3 months after
v0.3.0. Stability = no breaking changes to any public label
signature in any STD routine. Bug-fix patches and additive
non-breaking changes are fine.
Maintain docs/tracking/TOOLCHAIN-FINDINGS.md. For every
toolchain weakness (m-cli, tree-sitter-m, m-standard) that m-stdlib
development surfaces, add an entry: date, module, finding, link to
upstream issue.
The post-Phase-1 publication gate for m-cli and tree-sitter-m is:
no open P0/P1 entries in TOOLCHAIN-FINDINGS.md. m-stdlib's
job is to find these; the upstream projects' job is to fix them
before publishing public artifacts.
- m-standard schemas, TSVs, and
docs/spec.mdare unchanged by m-stdlib work. - m-cli's CLI surface is unchanged. The
m testdiscovery convention (t<UpperCase>(pass,fail)) is unchanged. Internal recognisers may add STDASSERT support but the CLI does not gain new flags for it. - tree-sitter-m grammar is unchanged. STDASSERT and the rest parse as ordinary M.
- m-tools is not modified. VistA's own
^TESTRUNusers continue to work — m-stdlib just doesn't depend on^TESTRUN.
Resolve in-session when they become live, not before:
- §6.0 — exact YottaDB Docker image (resolve at start of Phase 0).
- When m-cli drops
^TESTRUNrecognition (resolve when m-cli is actually adapting to STDASSERT, not before). - When IRIS portability becomes gating instead of fail-soft (resolve if/when an IRIS deployment commits to consuming m-stdlib).
- Per-module relicense from AGPL-3.0 (resolve only if a specific case demands it; default stays AGPL).
{ "name": "m-stdlib dev", "build": { "dockerfile": "Dockerfile" }, "remoteUser": "yottadb", "mounts": [ "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached" ], "containerEnv": { "ydb_dist": "/opt/yottadb", "ydb_routines": "/workspace/src /workspace/tests /workspace/.objects", "ydb_gbldir": "/workspace/.ydb/m-stdlib.gld", "PATH": "/opt/m-cli/.venv/bin:${containerEnv:PATH}" }, "customizations": { "vscode": { "extensions": [ "rafael5.tree-sitter-m-vscode", "github.vscode-github-actions", "redhat.vscode-yaml", "ms-azuretools.vscode-docker", "eamodio.gitlens" ], "settings": { "m-cli.enabled": true, "m-cli.path": "/opt/m-cli/.venv/bin/m", "editor.formatOnSave": true, "[m]": { "editor.tabSize": 1, "editor.insertSpaces": true, "editor.detectIndentation": false } } } }, "postCreateCommand": "make setup-ydb && make install-test-deps" }