Changelog¶
All notable changes to this project are documented in this file.
The format is based on Keep a Changelog,
and as of 1.0.0 this project adheres to
Semantic Versioning 2.0.0.
[Unreleased]¶
Changed¶
- Adopted the nerima-lisp package standard: the test system is now
cl-weave/testwith its sources undert/, the composite CI action is.github/actions/nix-setup, andrun-tests.lispat the repository root is the Lisp-level test entry point. - The
nix flake checksuite exposeschecks.default,checks.formatting(treefmt) andchecks.docs.nix fmtis driven by treefmt. - The
ci.ymljob is namedcheck, and the advertisedcontinuousIntegration.jobNamemetadata follows it. - nixpkgs now tracks
nixos-unstable. - Adopted the nerima-lisp coding standard. Test files are named after the
source file they cover (
t/journal-test.lispforsrc/journal.lisp, and<source>-<aspect>-test.lispwhere several files cover one source); shared fixtures and assertion helpers carry thehelpers-prefix. Every source line now fits in 100 columns, no source file exceeds 500 lines, and each of the three packages documents what it owns. src/model.lispwas split intomodel.lisp(records and conditions),model-registry.lisp(the global suite tree) andmodel-registration.lisp(registration argument handling); the shrink-candidate equality classifier moved fromsrc/property-generators.lisptosrc/property-generators-equality.lisp. No behaviour changed.flake.nixdeclares only the two verified systems,x86_64-linuxandaarch64-darwin(ADR-0078).
Added¶
defmatcherandexpect-extendaccept a leading(:description "a" "b")form in place of a description string, joining the parts at macroexpansion time. Common Lisp has no string continuation, so this is the only way to write a description longer than one line without changing its value.
[1.0.0] - 2026-07-25¶
Changed¶
- Declared the project stable: adopted Semantic Versioning 2.0.0 and moved the
lifecycle and release-stage metadata from
pre-1.0tostable, with paired contract tests and rewritten versioning, maintenance and release docs. - Canonicalized the moved repository references from
takeokunn/cl-weavetonerima-lisp/cl-weaveacross docs, metadata and packaging. The oldtakeokunn.github.io/cl-weavePages URL 404s after the org move, so the badges and links now point at the livenerima-lisp.github.io/cl-weavesite. --seedadvertises its machine-readable value kind as:positive-integerrather than:integer, which is what its parser has always enforced.- Bumped the pinned GitHub Actions:
actions/checkout4.3.1 to 7.0.1,actions/upload-artifact4.6.2 to 7.0.1,actions/configure-pages5.0.0 to 6.0.0,actions/upload-pages-artifact4.0.0 to 5.0.0, andactions/deploy-pages4.0.5 to 5.0.0.
Fixed¶
- Concurrent workers now run with the same condition-propagation semantics as
sequential execution.
*runner-propagate-conditions*is bound tonilduring collection but was missing from the captured dynamic environment, so worker threads (which start with a fresh dynamic environment) reverted to the global default oft. - A timeout that fires inside a
before-eachorafter-eachhook is reported as a test timeout instead of a spurious hook failure carrying a leaked internal condition. The hook collector caught everyserious-condition, including SBCL'ssb-ext:timeoutinterrupt. --flag=VALUEaccepts a value that begins with dashes again, for example--filter=--foo. The separated form still rejects a following option token.doctorreturns a failing exit status when a health check fails; it previously always exited 0, so CI could not gate oncl-weave doctor SYSTEM.- Ordered comparison matchers (
:to-be-greater-than,:to-be-less-thanand friends, and:to-be-close-to) treat NaN as a clean non-match. A NaN isrealp, so it reached the ordered predicates where SBCL's default:invalidfloating-point trap turned a should-fail assertion into an errored test. - Integer shrinking moves toward the in-range value closest to zero. For a
negative range the raw
minbound is the most extreme value, so a greedy shrink could accept a larger magnitude than the input it started from. Sequence generators now also reject a negative:min-lengthinstead of silently clamping it. - The JSON and JSONL reporters serialize a list of plists as an array of
objects instead of collapsing it into a single object with duplicate keys.
json-alist-ptreated the default smart-assertion operand report as an alist, dropping data on the frozen artifact contract. The S-expression reporter also binds*print-circle*so a circular journaled value cannot hang it.
[0.11.0] - 2026-07-25¶
Added¶
- Time-travel debugging. An opt-in execution journal records each attempt's
assertion, mock, hook, note and shrink timeline with zero overhead when
disabled; the JSON and S-expression reporters emit a
timelinefield. - Offline journal tooling:
explain-journal,journal-diff,explain-journal-diff,journal-wherelogic queries, and a serialize/deserialize round trip betweenjournal-frameand a plist. - CLOS-extensible frame kinds through
journal-frame-line-for-kind, plus a publicrecord-journal-frameso custom kinds do not require patching cl-weave. - Interactive breakpoints through
*journal-breakpoint*, which signals at a frame index or predicate and falls through to the debugger with the live dynamic extent intact. - Deterministic replay.
*test-random-seed*seeds the random state per test path so runs reproduce regardless of ordering or sharding, with single-testreplay-testand a shrink-step timeline for property tests. - Soft assertions:
with-soft-assertionsaggregates failures through a condition sink instead of aborting on the first one. --journaland--random-seedonrunandwatch, advertised through the framework metadata so usage and contract tests follow automatically.release.yml: av*.*.*tag push verifies the tag againstcl-weave.asd:version, builds the check artifacts, and publishes a GitHub Release.dependabot.ymlcovering both the workflows and the composite action, so the pinned action SHAs and their version comments stay current.
Changed¶
- Documentation migrated from mdBook to MkDocs Material.
book.tomlandSUMMARY.mdare replaced bydocs/mkdocs.yml, with theme assets and admonition-based formatting across the guide pages. - Nix installation and Cachix pull/push gating extracted into a reusable
composite action that the CI and docs workflows both delegate to, so the
token logic has one source of truth. The push token stays gated on
non-
pull_requestat the workflow boundary, because a local./action is resolved from the pull request head. ci.ymlis matrix-ready: a single-entrystrategy.matrixtemplates the system, so adding a platform is a one-line change.- Reduced consing and stack pressure on the runner hot paths.
results-statuswalks the run-result tree iteratively with explicit work and cycle detection rather than normalizing and then callingevery, so a status check no longer allocates a full normalized copy. Comparable non-consing and iterative rewrites landed acrossmodel,runner-attempts,runner-selection,runner-collection,runner-planning,runner-concurrencyandmatcher-runtime.
[0.10.0] - 2026-07-24¶
Added¶
benchmarks/, a performance harness for the runner's collection, selection and hook machinery.
Changed¶
- Fast paths and reduced allocation in the machinery that runs for every test.
runner-collectiongained a strict-empty-batch fast path so a suite with no hooks, filters, focus/skip/todo markers or special execution modes emits its events directly.runner-selectionhashes each child's kind and name incrementally onto a precomputed suite prefix hash instead of allocating a label string per child.runner-hookscomputes suite lineage once per test. - Split the largest source and test files into single-responsibility modules
without changing behavior:
property-generatorsinto-primitivesand-shrinking,watchintowatch-discovery,watch-scopeandwatch-suite-diff,runner-coverageout ofrunner-api, and the monolithicasdf-integration,expect-coreandmockingsuites into focused files. - The S-expression reporter emits its single form on one line, because it binds
*print-pretty*tonil. The AI contract now states this explicitly.
Fixed¶
- Cleanup hooks always run.
after-eachruns underunwind-protectand suiteafter-allhooks run through an idempotentrun-after-hooks, and the collectors catchserious-condition, so an SBCL platform timeout (signalled as a bareserious-condition, not anerror) still reaches cleanup. --bailonly consumes a following token when that token parses as a valid bail value; otherwise it is treated as flag-only.--bail=Nis accepted.- Isolated runs read files with
uiop:read-file-string, becausefile-lengthis a byte count rather than a character count for multibyte content. Temporary file and directory creation is deferred into theunwind-protectbody. gen-such-thatvalidates that its predicate is a function.watchreuses a single read buffer across file signatures.
[0.9.0] - 2026-07-23¶
Added¶
it-fuzz, a fuzz-testing driver built onit-property. It reuses the generator and shrinking machinery but treats the body as a fuzz probe rather than a boolean predicate: a trial passes by running without signalling anerror, and each trial runs under a per-trial timeout budget that is skipped rather than failed on expiry, since a slow trial is not evidence of a bug. A crashing trial's inputs are minimized the same way a failing property's are.
Fixed¶
- Nine documented inaccuracies, found by auditing the docs against the 0.8.0
source: a corrupted and quadruplicated JSON example plus a fictitious merged
artifactSchemasentry in the AI contract, the missingtagsfield in the Test Plan Contract examples, an Isolated Process Contract section that described the deferred hardening rewrite as if it had shipped, the undocumentedruntimedoctor check, and invented--test-name-patternand--output-fileflags corrected to the real--filterand--output.
[0.8.0] - 2026-07-19¶
Changed¶
- Runtime hardening against pathological input: bounded caps on retry, timeout, worker count, candidate count and precision.
- Recursive algorithms rewritten as iterative, cycle-safe ones across the logic engine, run-result normalization, shrinking, and the tag and dependency normalizers.
- Quadratic algorithms rewritten as linear or hash-based ones for mock call recording, snapshot diffing, watch change detection, and test selection and collection.
- Thread and process concurrency safety: registry locks, a worker pool with a bounded default, and atomic snapshot writes.
Fixed¶
- A large test expansion covering all of the above.
Removed¶
- The rewritten subprocess-isolation subsystem was reverted before release and
deferred to its own change. Under
sb-coverinstrumentation onx86_64-linuxit corrupted the SBCL image with a cascade of recursive lock errors, although it passed on darwin.src/isolation.lispand its tests are the 0.7.0 versions; every other hardening change is retained.
[0.7.0] - 2026-07-19¶
Added¶
- Top-level
CHANGELOG.md,CODE_OF_CONDUCT.md,CONTRIBUTING.md,SECURITY.mdandSUPPORT.mdthat link to the canonicaldocs/src/policies rather than duplicating them, plus a documentation badge and a Contributing section in the README.
Changed¶
- The release, versioning and maintenance docs point at GitHub Releases and
CHANGELOG.md. - Clarified that the timeout prefix on the documented commands is an optional outer guard.
tmp/and.worktrees/are ignored.
Fixed¶
- JUnit XML output no longer emits characters that are invalid in XML 1.0.
xml-escaped-stringreplaced only C0 control characters and passed everything else through, so surrogate code points (#xD800-#xDFFF) and the non-characters#xFFFEand#xFFFFleaked into the report and made it unparseable. Output is now restricted to the XML 1.0Charproduction and anything outside it is substituted with?.
Security¶
- Every GitHub Action is pinned to a full-length commit SHA instead of a
mutable tag:
checkout,install-nix-action,cachix-action,upload-artifact,configure-pages,upload-pages-artifactanddeploy-pages.
[0.6.0] - 2026-07-13¶
Added¶
- Configurable coverage gates.
--fail-with-no-testson the filtered CI smoke gates, in the workflow, the flake checks and the quality-gate metadata, so a filter that matches zero tests fails instead of passing silently.
Changed¶
- The Perl
alarmtimeout shim was replaced with GNUtimeoutacross the CI workflow, the flake checks and every documented command. The devShell and check environments now carrycoreutilsinstead ofperl. - The runtime-support platforms, CI integration systems, artifact bundle and
the README and installation wording advertise
x86_64-linuxonly, matching the CI reality.
Removed¶
- The darwin runner from GitHub Actions. CI runs on
ubuntu-latestonly.
[0.5.0] - 2026-07-12¶
Added¶
- Native test tag filtering.
- Dependency-aware watch selection, so a file change reruns only the affected suites.
- Coverage artifacts uploaded from CI.
root-suiteis exported.
Changed¶
- The README was reduced from roughly 1400 lines: its DSL, matcher and CLI
reference content moved into
docs/src/and is published as a GitHub Pages site, with adocsflake package and a publish workflow. The CLI's machine-readable documentation contract follows the new paths. - Memory-intensive flake checks are serialized in CI.
Fixed¶
- CLI coverage compilation.
[0.4.0] - 2026-07-12¶
Added¶
- Canonical ASDF test integration, so
asdf:test-systemis the supported entry point andclear-testsruns as part ofrun-system.
Changed¶
- Shared helpers extracted behind data-driven macro families, deduplicating
repeated patterns in
model(registration macros and record initarg helpers),registration(define-registration-familyfor thedescribe/itvariants),cli-options(generated spec accessors),cli-metadata-coreandcli-metadata-json-schema(plist accessor and JSON writer generators),logic(define-logic-query-family), andproperty-generators(shared bounded-sequence construction). - Vulnerability reports route to private GitHub security advisories across the
README, the docs, the issue chooser and
securityContacts. - The metadata
schemaVersionmoved to 23 after the citation block and its JSON schema writers were dropped.
Removed¶
- The script-based test runners.
- The in-repository governance documents (
CHANGELOG.md,CITATION.cff,CODE_OF_CONDUCT.md,CONTRIBUTING.md,SECURITY.md) and their entries inpolicyDocumentsandreferenceDocuments. - The unused
describe-concurrent-eachanddescribe-sequential-eachmacros and thecall-hooks/khelper.
[0.2.0] - 2026-07-12¶
Added¶
- Direct tests for the public
run,list-testsand suite-designator APIs, for designator caching and rejection, for every run and list reporter, forexplain!, for result normalization and for the matcher argument validation error paths. The coverage ratchet baseline rises to 87%. - The
coverage-gate-unitquality gate and a matching CI step covering the coverage gate's own unit tests. paredit-cliin the devShell and a repository-wideparedit-lintflake check for structural S-expression validation.- A
formatterflake output (nixfmt), sonix fmtformatsflake.nix. - An
overlays.defaultflake output, so a downstream flake can consumecl-weaveaspkgs.cl-weavewithout re-deriving the package. - Package
meta(description, homepage, license, platforms) on the flake'scl-weavederivation. - A
.envrc, sodirenv allowloads the devShell automatically. docs/README.mdas a documentation index.
Changed¶
- Suites and test cases print readably, showing the record name plus child count or focus flag, so failure output and the REPL identify model objects without inspecting slots.
Removed¶
- The legacy
assert-*andis-*compatibility aliases, in favour of the canonicalexpect,expect-not,signalsandfinishessurface. Replace any legacy alias with the corresponding canonical expectation macro.
Fixed¶
- The runner's failure path. A failing or erroring test previously crashed the
whole run with an unbound-variable error instead of being recorded as a
:failor:errorevent: the escape continuation macro bound the continuation withfletwhile every caller invoked it throughfuncall. after-eachcleanup also runs when a test attempt times out.- Interactive
retry-testrecords an exhausted retry budget as an:errorevent instead of aborting an enclosing runner. - Coverage instrumentation.
sb-coveronly records coverage for code compiled withcompile-file, and loading sources under the:compileevaluator mode produced an empty report that made the 100% gate unfalsifiable. Coverage runs now compile each product source to a temporary fasl, and the threshold is the measured 85% ratchet baseline. - Registration syntax errors involving circular literals. Simple-error
formatting is deferred to print time, so binding
*print-circle*arounderrordid not help; the message is now rendered eagerly. - Coverage cleanup notifications no longer replace the primary unwind: the
failure is signalled as a plain condition while a control transfer is in
flight, rather than as an
errorsubtype that enclosing handlers capture. - The test runner registers the project systems with ASDF again, so ASDF-backed
tests (system file collection, watch reloads,
cl-weave version) work without an externalCL_SOURCE_REGISTRY. - Sequence shrinkers guard against foreign values, because
gen-one-ofoffers every alternative's shrinker each candidate value. - The metadata and CLI package split. The CLI package referenced metadata data
through
declaim specialplaceholders, leaving*metadata-commands*and friends permanently unbound at runtime. docs/runtime-support.mddescribed an ASDF-loading timeout as an open blocker after it had already been fixed.
[0.1.0] - 2026-07-11¶
First tagged release. cl-weave is a Vitest-inspired Common Lisp testing
framework with a dependency-free core, structured machine-readable reporters,
and AI-agent-oriented runtime metadata. The public surface for this release is
the documented DSL, matcher set, runner API, CLI commands, reporter shapes and
machine-readable metadata.
Added¶
- The Vitest-style test DSL:
describeandit/testsuites and cases,expectmatcher assertions, smart S-expression assertions, table tests, focus, skip, todo, retry, timeout, bail, sharding, sequence ordering, filtering, concurrent execution modes, and expected failures. - Property-based testing with deterministic shrinking, form-level mutation testing with CI score gates, subprocess isolation for FFI and crash boundaries, inline and external snapshot matchers, mock functions with call-history matchers, and CPS continuation helpers.
- Spec, S-expression, JSON, JSONL/NDJSON, TAP, GitHub Actions and JUnit XML reporters with stable, versioned artifact schemas.
- The
cl-weaveCLI withrun,list,watch,doctor,metadata,versionandhelpcommands, Vitest-shaped option aliases, and environment-variable equivalents for CI automation. - AI-friendly runtime metadata: typed CLI options with finite choices, artifact schemas with field maps, a capability matrix, package exports, matchers, mutation operators, MOP architecture assertions, distribution channels and lifecycle contracts.
- ASDF system definitions, an ASDF-aware system runner, and watch mode with dependency-aware rerun narrowing.
- Nix flake packaging with reproducible CI entry points.