Doctor
glut doctor analyses test files and returns lint issues, authoring hints,
and a job coverage summary. It is designed for use during test authoring and
for AI coding assistants that read structured feedback.
doctor does not run tests. It does not need Docker or gitlab-ci-local.
Usage
glut doctor ./tests
glut doctor -k release ./tests
glut doctor --format=json ./tests/release.yml
Flags
| Flag | Short | Meaning |
|---|---|---|
--run <pattern> |
-k |
Analyse only tests whose name contains the substring. |
--format <fmt> |
Output format: text (default) or json. |
Output Sections
Lint Issues
doctor runs the same checks as glut lint. Issues are marked ERROR or
WARNING. Parse errors go to stderr. All other output goes to stdout.
Hints
Hints point out authoring problems that are technically valid but produce
weak test coverage. Each hint has a path that names the relevant part of the
.glut: metadata document.
| Hint path | Trigger condition |
|---|---|
.glut.assert |
Assert block is entirely empty. |
.glut.assert |
More than half of job asserts check only exit status with no artifact, git, API, or binary asserts. |
.glut.assert |
setup.tag is set with no assert.binary, assert.api, or assert.git. |
.glut.assert.api |
setup.pipeline_source is merge_request_event but assert.api is missing. |
.glut.assert.api |
setup.api mock is configured but assert.api is missing. |
.glut.assert.api |
setup.api.seed has data but assert.api is missing. The hint names the seeded entity counts. |
.glut.assert.binary |
setup.mocks.binaries is configured but assert.binary is missing. The hint names the mock binaries. |
.glut.assert.git |
setup.git is configured but assert.git is missing. |
.glut.assert.job |
setup.upstream is configured but no job asserts exist. |
.glut.setup.schedule |
setup.schedule is configured. Reminder to cover scheduled-only behavior. |
Coverage
Coverage shows how many pipeline jobs have at least one entry in assert.job.
Text output adds a [COVERAGE] line per file:
[COVERAGE] tests/release.yml: 1/2 jobs asserted
JSON output adds a coverage object to each file entry:
"coverage": {
"jobs_total": 2,
"jobs_asserted": 1
}
Text Output Format
[ERROR] <file>: <message>
[WARNING] <file>: <message>
[HINT] <file>: <path>: <message>
[COVERAGE] <file>: <asserted>/<total> jobs asserted
Parse errors go to stderr. Everything else goes to stdout.
JSON Output Format
{
"files": [
{
"file": "tests/release.yml",
"issues": [
{
"file": "tests/release.yml",
"level": "warning",
"category": "semantic",
"path": ".glut.assert",
"message": ".glut.assert is empty"
}
],
"hints": [
{
"file": "tests/release.yml",
"path": ".glut.assert.binary",
"message": "Mock binaries are configured (release-cli), but no binary asserts exist. Add assert.binary checks for called tools and arguments."
}
],
"coverage": {
"jobs_total": 2,
"jobs_asserted": 1
}
}
],
"has_errors": false
}
Exit Codes
| Code | Meaning |
|---|---|
0 |
No errors found. |
1 |
At least one lint error found. |
2 |
Doctor could not run (invalid flag, unreadable path). |
Hints and coverage do not affect the exit code.
Example Output
Running glut doctor ./tests on a test suite with one release test and two
authoring gaps:
[WARNING] tests/release.yml: .glut.setup.pipeline_source: unknown value "push-tag"
[HINT] tests/release.yml: .glut.assert: More than half of job asserts check only exit-status. Add artifact, git, API, or binary asserts for stronger coverage.
[HINT] tests/release.yml: .glut.assert.binary: Mock binaries are configured (release-cli), but no binary asserts exist. Add assert.binary checks for called tools and arguments.
[COVERAGE] tests/release.yml: 1/2 jobs asserted
Exit code is 0 because there are no errors — only warnings and hints.
Acting on Hints
Hints do not block the pipeline and do not affect the exit code. Use this table to decide how much to act on each one.
| Hint path | Act on it when... | Safe to ignore when... |
|---|---|---|
.glut.assert (empty) |
Always. An empty assert block proves nothing. | Never. |
.glut.assert (exit-status only) |
Your pipeline has side effects: releases, pushes, API calls. | Your job only needs to pass — e.g. a compile-only job with no artifacts. |
.glut.assert (tag, no binary/api/git) |
Your tag pipeline creates a release or pushes a manifest. | Your tag pipeline only builds an image with no external effects. |
.glut.assert.api (MR, no api assert) |
Your pipeline calls the GitLab API (fetches MR labels, posts a comment). | Your pipeline reads CI_MERGE_REQUEST_* variables but makes no API calls. |
.glut.assert.api (mock configured, no assert) |
Always. You set up a mock but never checked whether it was called. | Never. |
.glut.assert.binary |
Always. You mocked a binary so you could assert on it. | Never. |
.glut.assert.git |
Your pipeline commits or pushes. | Your pipeline only reads git variables like CI_COMMIT_SHA. |
.glut.assert.job (upstream, no job asserts) |
Always. An upstream context is useful only if you verify the triggered job. | Never. |
.glut.setup.schedule |
You want a reminder to cover scheduled-only behavior. | You already have a separate test for scheduled behavior. |
Coverage below 100 % means some pipeline jobs have no asserts at all. Add at
least an exit-status check for any job that should run.
Use With AI Tools
Run glut doctor --format=json ./tests and pass the output to a coding
assistant. The JSON structure gives the assistant file paths, issue categories,
hint paths, and coverage numbers so it can suggest targeted improvements.
Use -k to focus on a single test by name when a large test suite produces
too much output.