NTNT v0.5.0 Release Notes
v0.5.0 is the verification release. The DD-063 language assessment is fully closed — every silent failure it identified is now loud, the agent repair loop reports everything the error infrastructure can express, and verification commands verify under strict semantics by default. Alongside it: the two most-requested stdlib modules (std/validate, std/email), a hardened multi-worker runtime, and the last web-app quick wins.
Highlights
-
Declarative validation (
std/validate)schema(map { field: [rules...] })+validate(schema, data)→Ok(cleaned)with coerced values (unknown keys dropped) orErr(field → message).- Rules compose validators (
required,optional,email,url,min_value/max_value,min_length/max_length,one_of,matches,default), the global conversion functionsint/float/bool/str(andstd/stringtrim) for coercion, and barefn(value)closures as custom predicates. - Fields are required by default;
optionalpermits absence,default(v)supplies a value that still runs the remaining rules.
-
Email sending (
std/email)configure_email(...)once at startup;send_email(...)→Ok(map { "message_id", "transport" })orErr(message)— bad addresses and SMTP failures are values, never crashes.send_email_batch([...])reuses one pooled connection with per-email results; one bad email never stops the rest.- A log transport (
"transport": "log", orNTNT_EMAIL_MODE=log) prints emails to stderr and reports them sent — development and CI run the full email path with no SMTP server. - TLS defaults from the port (465 implicit, others STARTTLS); rustls, no openssl.
-
The agent repair loop, completed (DD-063)
ntnt lint/validate/checkrecover from parse errors and report up to 5 per file in one pass; semantic checks are suppressed on partial ASTs.- Contract violations (E004) show the failing clause's source frame, the actual runtime values (
where: b = 0), and the call site. - Unknown method calls get did-you-mean plus a UFCS bridge hint (
try len(s)); new lint rulesunknown_method,block_binding, andstatic_contract_violation(calls with literal arguments that provably violate arequiresclause are flagged at lint time). - IAL unknown terms get near-miss suggestions; new
ntnt intent lintstatically validates glossaries and scenarios (unresolved terms, definition cycles, vacuous scenarios, orphan entries) with--jsonfor CI — no server startup. - Fixed a false-assurance bug: intent files declaring invariants before features silently lost their feature ids and scenario outcomes, letting scenarios pass while verifying nothing.
-
Runtime and workers
- Array/string out-of-bounds reads are loud by type mode:
[WARN]+Nonein warn, error E010 in strict, silent in forgiving. Map missing-key access stays silent-Noneby design;arr[i] ?? default,arr[i]?, andotherwisesuppress the diagnostics entirely. - Crashed HTTP workers are supervised and respawned with backoff;
ntnt run --workers NjoinsNTNT_WORKERS. - Verified under benchmark: 8 workers take the TechEmpower-style single-query workload from 8.3K to 39K req/s.
- Array/string out-of-bounds reads are loud by type mode:
-
Quick wins
paginate(total, page, per_page)(std/collections) — offset/limit/pages/flags with safe clamping.from_now(ts)/time_ago(ts)(std/time) — "3 hours ago", "in 2 days", "just now".
Behavior changes
- Verification defaults to strict type mode.
ntnt testandntnt intent checkrun withNTNT_TYPE_MODE=strictwhen the variable is unset — degradations that warn mode tolerates (out-of-bounds →None, implicit conversions) now fail verification. SetNTNT_TYPE_MODE=warnexplicitly to restore the old tolerance.ntnt runis unchanged. - Strict mode errors on out-of-bounds reads. Code run under
NTNT_TYPE_MODE=strictthat previously tolerated OOB-as-Nonenow stops with E010. Guarded access (??,?,otherwise) is exempt. is_some/is_none/is_ok/is_err/unwrap_orare arity-checked at lint time; wrong-arity calls that previously passed silently now report.- Lint JSON: a file with N parse errors contributes N to
summary.errors(previously 1); parse errors now includecolumn.ntnt parse --json: contract clauses serialize as{expression, line}objects. - Scheduled loops and multi-worker: no change — module-level
schedule()loops are capability-gated and run exactly once, on the primary interpreter; Worker-mode interpreters skip them (same aslisten()).
Docs
- The whitepaper now separates shipped capability from aspiration in a prominent Implementation Status section.
- IAL reference documents invariant expansion honestly (the never-implemented
Sql/InvariantCheckprimitives are removed). - Agent guide: indexing semantics, validation, email, worker parallelism,
intent lintworkflow.
Upgrade notes
If your CI runs ntnt test or ntnt intent check and relied on warn-mode tolerance, either fix the surfaced issues (recommended — they are real) or set NTNT_TYPE_MODE=warn for the affected jobs. Consumers of lint/parse JSON should adopt the new summary.errors counting and contract-clause shapes.