Testing
DocSlime is verified behavior-first: the things a user actually does — scaffold a tree, add a document, create an ADR, list templates — are exercised end-to-end by running the real compiled binary against throwaway directories and asserting on the files it produces. Small, fiddly logic (slug normalization, ADR numbering) is covered by fast unit tests. The bar for shippable is simple: the full suite is green, impeccable can discover docs context, and the binary’s observable behavior matches the experiences and requirements.
Strategy
| Layer | What it verifies | Tools |
|---|---|---|
| Unit | Pure logic in isolation — slug normalization, next-ADR-number computation, filename prefix parsing. | Rust #[test] in src/ |
| End-to-end / behavior | User-visible CLI behavior from ../experience/README.md — running the actual binary and asserting on exit codes, output, and files written. |
assert_cmd, predicates, tempfile |
There is no separate integration layer: the codebase is small and the components are best verified together through the CLI, so the black-box tests double as integration coverage.
Behavior coverage
| Experience / Requirement | Scenario (Given/When/Then) | Test |
|---|---|---|
| Scaffold the docs tree / FR-1, FR-11, FR-15, FR-18, FR-19 | Given an empty dir, When init, Then the full 12-file lifecycle tree exists, including product/design context, requirements, publishing, and observability |
tests/cli.rs::init_creates_full_tree |
| Self-explaining templates | Given a scaffolded tree, When inspected, Then every template carries <!-- LLM: --> guidance |
tests/cli.rs::every_template_carries_llm_guidance |
| Mermaid flowcharts / FR-20 | Given a scaffolded tree, When diagram guidance and examples are inspected, Then flowcharts use Mermaid and reject ASCII-art guidance | tests/cli.rs::flowcharts_use_mermaid_in_generated_docs |
| Adaptable scaffold / FR-21 | Given a scaffolded tree and bundled skills, When scope guidance is inspected, Then it treats the tree as a starting template and names backend API developer and agent experience as a valid tailored use | tests/cli.rs::scaffold_and_skills_explain_project_specific_scope |
| Optional release conventions / FR-22 | Given a scaffolded tree and publishing skill guidance, When release conventions are inspected, Then Semantic Versioning and Conventional Commits are suggestions and enforcement requires explicit agreement | tests/cli.rs::suggested_release_conventions_are_optional |
| Non-destructive by default / FR-2 | Given an edited file, When init re-runs, Then the file is left untouched |
tests/cli.rs::init_skips_existing_files |
| Force overwrite / FR-2 | Given an edited file, When init --force, Then the template is restored |
tests/cli.rs::init_force_overwrites |
| Legacy path safety / FR-17 | Given a filled legacy numbered file, When current init or list runs, Then the new counterpart is treated as satisfied without duplicating or moving user work |
tests/cli.rs::init_recognizes_legacy_paths, list_recognizes_legacy_paths |
| Add a single document / FR-3 | Given an empty dir, When add <shorthand>, Then the matching template is created |
tests/cli.rs::add_resolves_shorthand_name |
| Unknown name errors / FR-8 | Given an unknown name, When add, Then it fails with a helpful error |
tests/cli.rs::add_unknown_template_fails |
| Record an architecture decision / FR-4 | Given existing ADRs, When add adr <slug>, Then the next number is used |
tests/cli.rs::add_adr_numbers_sequentially |
| ADR numbering from scratch / FR-4 | Given no ADR dir, When add adr <slug>, Then it starts at 0001 |
tests/cli.rs::add_adr_starts_at_one_without_init |
| ADR slug required / FR-5 | Given no slug, When add adr, Then it fails |
tests/cli.rs::add_adr_requires_slug |
| List templates / FR-6 | When list, Then every template is shown |
tests/cli.rs::list_shows_every_template |
| List reflects disk state / FR-6 | Given some files exist, When list, Then status reflects what’s on disk |
tests/cli.rs::list_reflects_on_disk_status |
| Agent skill structure / FR-9, FR-10 | Given the bundled docslime skills, When validated, Then their frontmatter and metadata are well-formed | skill-creator/scripts/quick_validate.py .agents/skills/<skill> |
| KISS stays a skill / FR-12 | Given the CLI help, When inspected, Then there is no kiss CLI subcommand |
tests/cli.rs::kiss_is_not_a_cli_subcommand |
| Skill robustness / FR-16 | Given the bundled skill folders, When inspected, Then each SKILL.md has frontmatter, guardrails, verification, and failure handling |
tests/cli.rs::agent_skills_have_required_sections |
| Slug normalization / FR-5 | Mixed-case/spaced input normalizes to [a-z0-9-]; empty rejected |
src/commands/add.rs::normalize_slug_lowercases_and_hyphenates |
| ADR numbering helper / FR-4 | Missing dir → 1; filename prefix parsed correctly |
src/commands/add.rs::next_adr_number_is_one_when_dir_missing, leading_number_parses_prefix |
Traceability contract
DocSlime’s TDD+BDD bar is that every important behavior can be followed from intent to proof:
| Link | Evidence |
|---|---|
| Product goal -> experience | ../PRODUCT.md explains why the docs tree exists; ../experience/README.md captures the evidence and journeys. |
| Experience -> requirement | ../REQUIREMENTS.md gives each behavior a stable FR/NFR ID and names the evidence it serves. |
| Requirement -> BDD scenario | This file records Given/When/Then coverage for the visible behavior. |
| Scenario -> test | tests/cli.rs runs the compiled binary against throwaway directories and asserts on output files, exit codes, and help text. |
| Requirement -> architecture/ADR | ARCHITECTURE.md names the domain boundary; durable choices link to adrs/. |
| Release -> production evidence | PUBLISHING.md defines verification; OBSERVABILITY.md links production signals back to outcomes and discovery. |
The DDD evidence is intentionally lightweight: docs should name the domain concepts and boundaries that affect behavior, then use ADRs for hard-to-reverse decisions. If a project has no meaningful domain split, the architecture doc should say that instead of inventing bounded contexts.
Evaluation against product goals
Tests prove correctness; they don’t prove the product is working. The product-level signals from ../PRODUCT.md are evaluated qualitatively:
- Docs get filled — judged by whether scaffolded docs in real repos end up complete (no leftover
<!-- LLM: -->guidance), rather than abandoned as templates. DocSlime dogfoods this by filling in its owndocs/tree. - Low friction — judged by the time and number of steps from
docslime initto a first useful, filled-in document. - Agent context quality — judged by whether agents working in a DocSlime-backed repo give less speculative answers because product context, requirements, and ADRs are present.
- Impeccable context quality — judged by whether
impeccableresolvesdocs/PRODUCT.mdanddocs/DESIGN.mdwithout duplicate root files. - Delivery quality — judged by whether each CLI, skill, and site artifact is verified through its user-facing distribution path rather than inferred from workflow completion.
- Production learning — judged by whether release failures, feedback, and adoption signals update discovery evidence or requirements when they reveal a material gap.
- Skill robustness — judged by whether skill files validate structurally and give agents enough setup, guardrails, verification, and failure handling to act without guessing.
- Adoption — tracked via Homebrew and
npx skillsinstalls and repos using the tree.
Running the tests
cargo test # unit + integration suite (expected: all green)
cargo clippy --all-targets # lint (expected: no warnings)
npm run build # docmd site build (expected: site/ output updates cleanly)
Continuous integration
DocSlime is now a monorepo with three CI-owned surfaces:
| Workflow job | Surface | Gate |
|---|---|---|
Branch policy |
Release flow | Fails pull requests to main unless the source branch is staging; all feature work targets staging. |
CLI |
Rust binary and embedded templates | cargo fmt --check, cargo test, and cargo clippy --all-targets -- -D warnings. |
Site |
docmd.io documentation site |
npm ci followed by npm run build. |
Agent skills |
Bundled .agents/skills/docslime-* package |
Frontmatter, OpenAI metadata, guardrail, verification, and failure-handling checks. |
The daily CI workflow lives in .github/workflows/ci.yml and runs on pull requests to staging or main, pushes to those branches, and manual dispatches. The release workflow (.github/workflows/release.yml, generated by cargo-dist) remains tag-driven: it builds and packages the CLI for all target platforms, creates the GitHub Release, and publishes the Homebrew formula.
GitHub also has an active repository ruleset named “Protect main and staging from deletion”. It targets refs/heads/main and refs/heads/staging with the deletion rule so the two release branches cannot be removed accidentally.
Test data & environments
End-to-end tests run the real binary inside a fresh tempfile::TempDir per test, so each one gets an isolated throwaway directory that is cleaned up automatically — no shared state, no fixtures to seed, and no risk of touching the working repo.