Testing Traps
SkillDev toolsUse when writing or debugging a test that drives the ryl binary, exercises config discovery, or checks a committed generated artifact (the JSON config schemas, the SchemaStore snapshot, the docs config examples). Covers the environment-dependent traps that make such a test pass vacuously, fail only in CI, or churn under prek.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Testing Traps skill
What this skill tells your AI
The instructions your AI receives, as published by owenlamont/ryl in .agents/skills/testing-traps/SKILL.md and read by ahel’s review.
Config-discovery isolation
ryl's project-config discovery climbs from each input through its ancestors up to HOME,
so a test whose inputs live under the system temp dir can walk into that shared dir and
discover a stray ryl.toml/.ryl.toml/pyproject.toml/.yamllint* left by another
test, a concurrent process, or a manual smoke run — silently overriding the test's setup
(and a TOML candidate outranks a tempdir's .yamllint, so an adjacent YAML config does
not shield it).
Any test that exercises discovery (does not pass -c/-d, and has no adjacent TOML
config in its input's directory) must build its command via common::cli::ryl(<its tempdir>), which sets HOME to bound the walk at the tempdir. Tests that pass -c/-d
bypass discovery and need no isolation; tests that write an adjacent .ryl.toml are
already shielded. Correspondingly, manual/agent smoke runs must keep scratch configs in
a dedicated subdirectory and never drop a config-candidate-named file at the temp root.
Assert format-agnostically
CLI/system tests that drive env!("CARGO_BIN_EXE_ryl") run under CI's environment, where
GITHUB_ACTIONS makes ryl auto-select the GitHub output format
(::error file=…,line=L,col=C::L:C [rule] message) rather than the standard format
( L:C level message (rule)).
Match the bare line:col (present verbatim in both formats) and the bare rule id
(colons, never (colons) — the GitHub format renders it [colons]). Do not force
--format to dodge this and do not assert a specific format's (rule) parens or ANSI.
The cli_*_rule tests follow this; only tests that exercise formatting itself
(cli_format_options, yamllint_compat_*) pin or scrub the format via
--format/env_remove.
Unicode fixtures
For Unicode-heavy fixtures, assert with multibyte characters (e.g. "café"/"å") and
reuse crate::rules::span_utils rather than reinventing byte/char conversions, to cover
character-vs-byte offset logic.
Committed JSON config schemas
ryl.toml.schema.json / ryl.yaml.schema.json are generated by
ryl --print-toml-config-schema / --print-yaml-config-schema. Always run prek after
regenerating: --print emits schemars insertion order, but the pretty-format-json
hook rewrites JSON with recursively sorted keys, so the committed form is sorted
(committing raw --print output causes the recurring "prek reordered the schema" churn).
Because the canonical form is sorted, regeneration only changes lines when schema
content changes — a structural change that doesn't alter content yields a zero diff
after sorting, so don't commit a reordered file (leave it at HEAD).
tests/config_schema.rs compares order-insensitively, but the files must still be
committed sorted to keep prek idempotent; when an options type is renamed, update the
RuleEntryFor…/RuleOptionsFor… names asserted there too.
SchemaStore
The vendored SchemaStore yamllint snapshot lives at
tests/fixtures/schemastore-yamllint.json; refresh it with uv run scripts/update_yamllint_schemastore_snapshot.py instead of fetching from the network in
normal tests.
The SchemaStore TOML projection comes from uv run scripts/print_ryl_schemastore_schema.py; it targets only ryl.toml / .ryl.toml
because SchemaStore cannot attach directly to [tool.ryl] inside pyproject.toml.
Docs config examples
Config examples in the docs/ Markdown sources are validated through ryl's finalized
config path (the discover_config -c path the CLI uses) by
tests/docs_config_examples.rs, so misspelled rule names and options are caught, not just
bad values (docs/llms*.txt are generated from those sources and drift-guarded, so they
are covered transitively).
A block is recognised as ryl config structurally from its content (a toml block with a
[tool.ryl] table or a table named in the TOML config schema; a yaml block with a
top-level key in the YAML config schema), so other tools' TOML and rule-input YAML are
skipped, and a malformed config example is caught. Put <!-- ryl-config-check: skip -->
on the line before a fence to exempt an intentional counter-example (e.g. the YAML-1.1
config in yaml-version.md shown as failing).
Signals
- GitHub stars
- 72
- Forks
- 3
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
testing-traps- Source
- github.com/owenlamont/ryl