testguard-cli 0.2.0__tar.gz → 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- testguard_cli-0.2.1/.codex/hooks.json +71 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/CHANGELOG.md +14 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/PKG-INFO +6 -3
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/README.md +5 -2
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/action.yml +1 -1
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/package-lock.json +2 -2
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/package.json +1 -1
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/packaging/homebrew/testguard.rb +1 -1
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/pyproject.toml +1 -1
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/GATE-SEMANTICS.md +5 -1
- testguard_cli-0.2.1/spec/conformance/examples/evidence-provisional.json +272 -0
- testguard_cli-0.2.1/spec/conformance/invalid/evidence.provisional-flag-on-confirmed-run.json +535 -0
- testguard_cli-0.2.1/spec/conformance/invalid/evidence.single-run-without-provisional.json +271 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/schemas.test.mjs +6 -4
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/lib/validate.mjs +2 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/schemas/evidence.schema.json +4 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/brief/brief.mjs +2 -1
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/cli.mjs +3 -1
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/commands/baseline.mjs +5 -1
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/commands/probe.mjs +10 -5
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/probe/probe.mjs +1 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/render.mjs +7 -5
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/test/brief.test.mjs +15 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/test/probe.fixture.test.mjs +21 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/.gitattributes +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/.github/dependabot.yml +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/.github/scripts/install-smoke.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/.github/scripts/sync-release-version.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/.github/workflows/auto-merge.yml +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/.github/workflows/ci.yml +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/.github/workflows/release.yml +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/.github/workflows/scheduled-release.yml +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/.github/workflows/supply-chain.yml +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/.gitignore +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/.npmignore +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/.npmrc +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/.pre-commit-hooks.yaml +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/AGENTS.md +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/CLAUDE.md +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/CODE_OF_CONDUCT.md +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/CONTRIBUTING.md +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/LICENSE +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/PRIVACY.md +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/SECURITY.md +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/SUPPORT.md +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/bench/README.md +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/cli/testguard.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/fixtures/known-answer/.gitignore +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/fixtures/known-answer/README.md +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/fixtures/known-answer/expected.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/fixtures/known-answer/package.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/fixtures/known-answer/src/export.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/fixtures/known-answer/src/redact.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/fixtures/known-answer/test/flaky.test.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/fixtures/known-answer/test/redact.test.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/fixtures/known-answer/testguard.claims.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/fixtures/known-answer/vitest.config.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/README.md +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/examples/baseline.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/examples/brief.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/examples/calibration.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/examples/claims.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/examples/evidence.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/examples/ignore.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/invalid/baseline.bad-fingerprint-key.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/invalid/baseline.zero-count.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/invalid/brief.text-without-heading.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/invalid/brief.unknown-verdict-key.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/invalid/calibration.p-outside-ci.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/invalid/calibration.positives-exceed-n.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/invalid/claims.absolute-path.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/invalid/claims.duplicate-fault-id.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/invalid/claims.missing-provenance.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/invalid/claims.noop-fault.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/invalid/claims.occurrence-exceeds-hits.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/invalid/claims.parent-traversal.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/invalid/evidence.flaky-defender-without-flakiness.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/invalid/evidence.killed-by-non-assertion.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/invalid/evidence.killed-on-red-baseline.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/invalid/evidence.killed-without-n-runs.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/invalid/evidence.rank-extra-property.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/invalid/evidence.undeclared-killers-without-reason.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/invalid/evidence.unknown-verdict.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/invalid/evidence.unverifiable-without-reason.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/invalid/evidence.wrong-fingerprint.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/invalid/ignore.missing-reason.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/conformance/invalid/ignore.short-reason.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/lib/fingerprint.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/schemas/baseline.schema.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/schemas/brief.schema.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/schemas/calibration.schema.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/schemas/claims.schema.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/schemas/common.schema.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/spec/schemas/ignore.schema.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/baseline/baseline.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/claims/annotations.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/claims/load.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/commands/brief.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/commands/claims.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/commands/scaffold.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/evidence/writer.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/git.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/probe/classify.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/probe/discover.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/probe/inject.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/probe/rank.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/probe/runner-vitest.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/probe/worktree.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/scaffold/producers.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/scaffold/scaffold.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/util/glob.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/src/util/hash.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/test/annotations.test.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/test/baseline.test.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/test/classify.test.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/test/discover.test.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/test/glob.test.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/test/inject.test.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/test/probe-preconditions.test.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/test/rank-aliases.test.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/test/runner-command.test.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/test/runner-vitest.test.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/test/scaffold.test.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/test/snapshot.test.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/test/worktree.test.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/test/writer.test.mjs +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/testguard.claims.json +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/testguard_cli/__init__.py +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/testguard_cli/wrapper.py +0 -0
- {testguard_cli-0.2.0 → testguard_cli-0.2.1}/vitest.config.mjs +0 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"PreToolUse": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "Read",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.wolf/hooks/pre-read.js\"",
|
|
10
|
+
"timeout": 5
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"matcher": "Write|Edit|MultiEdit",
|
|
16
|
+
"hooks": [
|
|
17
|
+
{
|
|
18
|
+
"type": "command",
|
|
19
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.wolf/hooks/pre-write.js\"",
|
|
20
|
+
"timeout": 5
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"PostToolUse": [
|
|
26
|
+
{
|
|
27
|
+
"matcher": "Read",
|
|
28
|
+
"hooks": [
|
|
29
|
+
{
|
|
30
|
+
"type": "command",
|
|
31
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.wolf/hooks/post-read.js\"",
|
|
32
|
+
"timeout": 5
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"matcher": "Write|Edit|MultiEdit",
|
|
38
|
+
"hooks": [
|
|
39
|
+
{
|
|
40
|
+
"type": "command",
|
|
41
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.wolf/hooks/post-write.js\"",
|
|
42
|
+
"timeout": 10
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
"SessionStart": [
|
|
48
|
+
{
|
|
49
|
+
"matcher": "",
|
|
50
|
+
"hooks": [
|
|
51
|
+
{
|
|
52
|
+
"type": "command",
|
|
53
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.wolf/hooks/session-start.js\"",
|
|
54
|
+
"timeout": 5
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
"Stop": [
|
|
60
|
+
{
|
|
61
|
+
"hooks": [
|
|
62
|
+
{
|
|
63
|
+
"type": "command",
|
|
64
|
+
"command": "node \"$CLAUDE_PROJECT_DIR/.wolf/hooks/stop.js\"",
|
|
65
|
+
"timeout": 10
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.1] - 2026-09-17
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Provisional verdicts** (#5). A run with `--confirm` below 3 declares
|
|
15
|
+
`run.provisional: true` — a spec field whose equivalence with
|
|
16
|
+
`confirmRuns < 3` the validator enforces both ways. Provisional verdicts
|
|
17
|
+
print with a `?`, the summary is prefixed `PROVISIONAL`, a warning is
|
|
18
|
+
printed on stderr, evidence is written to `.testguard/evidence-provisional.json`
|
|
19
|
+
so the canonical file only ever holds confirmed runs, `brief` warns at the
|
|
20
|
+
top, and `baseline` refuses provisional evidence unless
|
|
21
|
+
`--allow-provisional`. A confirmed prior verdict is never reused by a
|
|
22
|
+
provisional run, nor the reverse.
|
|
23
|
+
|
|
10
24
|
## [0.2.0] - 2026-09-17
|
|
11
25
|
|
|
12
26
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: testguard-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Proves a test suite actually defends the claims a project makes: injects the faults those claims forbid and reports every one the tests miss. Python wrapper for the Node.js CLI (requires Node.js 20+).
|
|
5
5
|
Project-URL: Homepage, https://github.com/raccioly/testguard
|
|
6
6
|
Project-URL: Documentation, https://github.com/raccioly/testguard#readme
|
|
@@ -76,7 +76,7 @@ tests were written against the survivors, 39/39 were killed.
|
|
|
76
76
|
| npm | `npm i -D testguard-cli` then `npx testguard probe` |
|
|
77
77
|
| pip | `pip install testguard-cli` then `testguard probe` (needs Node ≥ 20) |
|
|
78
78
|
| Homebrew | `brew tap raccioly/tap && brew install testguard` |
|
|
79
|
-
| GitHub Action | `uses: raccioly/testguard@v0.2.
|
|
79
|
+
| GitHub Action | `uses: raccioly/testguard@v0.2.1` — see [`action.yml`](./action.yml) |
|
|
80
80
|
| pre-commit | `repo: https://github.com/raccioly/testguard`, hooks `testguard-claims`, `testguard-probe` |
|
|
81
81
|
|
|
82
82
|
Projects that set `min-release-age` in `.npmrc` cannot see a version published
|
|
@@ -136,7 +136,10 @@ npx testguard-cli scaffold src/x.ts # propose faults for a file, as a draft to
|
|
|
136
136
|
Practical loop: first pass `--no-escalate` (escalation re-runs the whole
|
|
137
137
|
suite N times per survivor); iterate on one claim with `--claim <ID>` and
|
|
138
138
|
either `--include-dirty` or `--in-place` (only fault target files must be
|
|
139
|
-
clean there; test files may be dirty)
|
|
139
|
+
clean there; test files may be dirty), optionally `--confirm 1` for a fast
|
|
140
|
+
**provisional** signal — verdicts print with a `?`, evidence goes to
|
|
141
|
+
`evidence-provisional.json`, and `baseline` refuses it; final pass with
|
|
142
|
+
defaults. By default
|
|
140
143
|
the stream shows only unproven faults plus a killed count — `--verbose`
|
|
141
144
|
shows every fault. A custom
|
|
142
145
|
runner (`pnpm --filter`, a specific config) goes in
|
|
@@ -52,7 +52,7 @@ tests were written against the survivors, 39/39 were killed.
|
|
|
52
52
|
| npm | `npm i -D testguard-cli` then `npx testguard probe` |
|
|
53
53
|
| pip | `pip install testguard-cli` then `testguard probe` (needs Node ≥ 20) |
|
|
54
54
|
| Homebrew | `brew tap raccioly/tap && brew install testguard` |
|
|
55
|
-
| GitHub Action | `uses: raccioly/testguard@v0.2.
|
|
55
|
+
| GitHub Action | `uses: raccioly/testguard@v0.2.1` — see [`action.yml`](./action.yml) |
|
|
56
56
|
| pre-commit | `repo: https://github.com/raccioly/testguard`, hooks `testguard-claims`, `testguard-probe` |
|
|
57
57
|
|
|
58
58
|
Projects that set `min-release-age` in `.npmrc` cannot see a version published
|
|
@@ -112,7 +112,10 @@ npx testguard-cli scaffold src/x.ts # propose faults for a file, as a draft to
|
|
|
112
112
|
Practical loop: first pass `--no-escalate` (escalation re-runs the whole
|
|
113
113
|
suite N times per survivor); iterate on one claim with `--claim <ID>` and
|
|
114
114
|
either `--include-dirty` or `--in-place` (only fault target files must be
|
|
115
|
-
clean there; test files may be dirty)
|
|
115
|
+
clean there; test files may be dirty), optionally `--confirm 1` for a fast
|
|
116
|
+
**provisional** signal — verdicts print with a `?`, evidence goes to
|
|
117
|
+
`evidence-provisional.json`, and `baseline` refuses it; final pass with
|
|
118
|
+
defaults. By default
|
|
116
119
|
the stream shows only unproven faults plus a killed count — `--verbose`
|
|
117
120
|
shows every fault. A custom
|
|
118
121
|
runner (`pnpm --filter`, a specific config) goes in
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "testguard-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "testguard-cli",
|
|
9
|
-
"version": "0.2.
|
|
9
|
+
"version": "0.2.1",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"ajv": "8.20.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "testguard-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Proves a test suite defends the claims a project makes: injects the faults those claims forbid and reports every one the tests fail to detect.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
class Testguard < Formula
|
|
14
14
|
desc "Proves a test suite defends the claims a project makes"
|
|
15
15
|
homepage "https://github.com/raccioly/testguard"
|
|
16
|
-
url "https://registry.npmjs.org/testguard-cli/-/testguard-cli-0.2.
|
|
16
|
+
url "https://registry.npmjs.org/testguard-cli/-/testguard-cli-0.2.1.tgz"
|
|
17
17
|
sha256 "385d69f9d3c153b934d9c1cb6a2c754eb9b221b0a8c0ba8b805858384d2d4678"
|
|
18
18
|
license "MIT"
|
|
19
19
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "testguard-cli"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.1"
|
|
8
8
|
description = "Proves a test suite actually defends the claims a project makes: injects the faults those claims forbid and reports every one the tests miss. Python wrapper for the Node.js CLI (requires Node.js 20+)."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -22,7 +22,11 @@ Rules that follow from the table:
|
|
|
22
22
|
1. **Green baseline first.** Defenders run N times unmodified before any fault
|
|
23
23
|
is applied. Anything short of N/N pass is `flaky-defender` and stops there.
|
|
24
24
|
2. **Confirm over N runs.** `killed` and `survived` both require exactly N
|
|
25
|
-
probe runs, all agreeing. Default N is 3.
|
|
25
|
+
probe runs, all agreeing. Default N is 3. **Fewer than three runs is
|
|
26
|
+
provisional**: the evidence declares `run.provisional: true`, every
|
|
27
|
+
rendering marks the verdicts as unconfirmed, and a provisional run is
|
|
28
|
+
never frozen into a baseline. Provisional runs exist for the fix loop —
|
|
29
|
+
a fast signal while writing a test — not for a gate.
|
|
26
30
|
3. **Only a test body rejecting the behaviour kills.** A test that fails by
|
|
27
31
|
assertion — or by an exception the fault provoked inside it — counts. A
|
|
28
32
|
timeout does not, and a suite that fails to load does not: neither is
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"tool": {
|
|
4
|
+
"name": "testguard",
|
|
5
|
+
"version": "0.1.0"
|
|
6
|
+
},
|
|
7
|
+
"run": {
|
|
8
|
+
"id": "run-provisional",
|
|
9
|
+
"startedAt": "2026-09-17T02:00:00Z",
|
|
10
|
+
"finishedAt": "2026-09-17T02:00:41Z",
|
|
11
|
+
"repo": {
|
|
12
|
+
"head": "deadbeefcafe",
|
|
13
|
+
"dirty": false,
|
|
14
|
+
"snapshot": "c0ffeeaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
15
|
+
},
|
|
16
|
+
"runner": {
|
|
17
|
+
"name": "vitest",
|
|
18
|
+
"version": "5.0.1"
|
|
19
|
+
},
|
|
20
|
+
"confirmRuns": 1,
|
|
21
|
+
"mode": "worktree",
|
|
22
|
+
"provisional": true
|
|
23
|
+
},
|
|
24
|
+
"records": [
|
|
25
|
+
{
|
|
26
|
+
"fingerprint": "01876384493be6809da455cb1a1c4bc92e7564e9898506d790b9589200502163",
|
|
27
|
+
"claim": {
|
|
28
|
+
"id": "REDACT-001",
|
|
29
|
+
"statement": "The audit record written for a redacted message never contains the original secret.",
|
|
30
|
+
"severity": "critical",
|
|
31
|
+
"source": {
|
|
32
|
+
"kind": "spec",
|
|
33
|
+
"ref": "docs/spec.md#audit-records"
|
|
34
|
+
},
|
|
35
|
+
"producedBy": {
|
|
36
|
+
"producer": "human",
|
|
37
|
+
"by": "maintainer",
|
|
38
|
+
"at": "2026-09-17T02:00:00Z"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"subject": {
|
|
42
|
+
"kind": "fault",
|
|
43
|
+
"id": "F1",
|
|
44
|
+
"description": "Audit row is written with the raw input.",
|
|
45
|
+
"file": "src/redact.mjs",
|
|
46
|
+
"faultClass": "variable-swap",
|
|
47
|
+
"producedBy": {
|
|
48
|
+
"producer": "human",
|
|
49
|
+
"by": "maintainer",
|
|
50
|
+
"at": "2026-09-17T02:00:00Z"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"verdict": "survived",
|
|
54
|
+
"detail": {
|
|
55
|
+
"baselineRuns": [
|
|
56
|
+
{
|
|
57
|
+
"outcome": "pass",
|
|
58
|
+
"tests": {
|
|
59
|
+
"total": 4,
|
|
60
|
+
"passed": 4,
|
|
61
|
+
"failed": 0
|
|
62
|
+
},
|
|
63
|
+
"assertionFailures": 0,
|
|
64
|
+
"durationMs": 310
|
|
65
|
+
}
|
|
66
|
+
],
|
|
67
|
+
"probeRuns": [
|
|
68
|
+
{
|
|
69
|
+
"outcome": "pass",
|
|
70
|
+
"tests": {
|
|
71
|
+
"total": 4,
|
|
72
|
+
"passed": 4,
|
|
73
|
+
"failed": 0
|
|
74
|
+
},
|
|
75
|
+
"assertionFailures": 0,
|
|
76
|
+
"durationMs": 310
|
|
77
|
+
}
|
|
78
|
+
],
|
|
79
|
+
"escalated": true,
|
|
80
|
+
"escalationRuns": [
|
|
81
|
+
{
|
|
82
|
+
"outcome": "pass",
|
|
83
|
+
"tests": {
|
|
84
|
+
"total": 4,
|
|
85
|
+
"passed": 4,
|
|
86
|
+
"failed": 0
|
|
87
|
+
},
|
|
88
|
+
"assertionFailures": 0,
|
|
89
|
+
"durationMs": 310
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
},
|
|
93
|
+
"defenders": {
|
|
94
|
+
"requested": [
|
|
95
|
+
"test/redact.test.mjs"
|
|
96
|
+
],
|
|
97
|
+
"resolved": [
|
|
98
|
+
"test/redact.test.mjs"
|
|
99
|
+
],
|
|
100
|
+
"nocover": false,
|
|
101
|
+
"discovered": false
|
|
102
|
+
},
|
|
103
|
+
"inputs": {
|
|
104
|
+
"targetHash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
105
|
+
"defenderHashes": {
|
|
106
|
+
"test/redact.test.mjs": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"rank": {
|
|
110
|
+
"score": 9.5,
|
|
111
|
+
"blastRadius": 7,
|
|
112
|
+
"tier": "critical"
|
|
113
|
+
},
|
|
114
|
+
"annotations": [
|
|
115
|
+
{
|
|
116
|
+
"kind": "tracked",
|
|
117
|
+
"text": "Assertion uses objectContaining without the content key.",
|
|
118
|
+
"by": "maintainer",
|
|
119
|
+
"at": "2026-09-17T02:00:00Z",
|
|
120
|
+
"ref": "issue#12"
|
|
121
|
+
}
|
|
122
|
+
]
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"fingerprint": "10d526ffb9535c8d99c39dcea29a8d6fa86c3370a2a5061de5320e028ba79b1f",
|
|
126
|
+
"claim": {
|
|
127
|
+
"id": "REDACT-001",
|
|
128
|
+
"statement": "The audit record written for a redacted message never contains the original secret.",
|
|
129
|
+
"severity": "critical",
|
|
130
|
+
"source": {
|
|
131
|
+
"kind": "spec",
|
|
132
|
+
"ref": "docs/spec.md#audit-records"
|
|
133
|
+
},
|
|
134
|
+
"producedBy": {
|
|
135
|
+
"producer": "human",
|
|
136
|
+
"by": "maintainer",
|
|
137
|
+
"at": "2026-09-17T02:00:00Z"
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
"subject": {
|
|
141
|
+
"kind": "fault",
|
|
142
|
+
"id": "F2",
|
|
143
|
+
"description": "Redaction skipped.",
|
|
144
|
+
"file": "src/redact.mjs",
|
|
145
|
+
"faultClass": "statement-deleted"
|
|
146
|
+
},
|
|
147
|
+
"verdict": "killed",
|
|
148
|
+
"detail": {
|
|
149
|
+
"baselineRuns": [
|
|
150
|
+
{
|
|
151
|
+
"outcome": "pass",
|
|
152
|
+
"tests": {
|
|
153
|
+
"total": 4,
|
|
154
|
+
"passed": 4,
|
|
155
|
+
"failed": 0
|
|
156
|
+
},
|
|
157
|
+
"assertionFailures": 0,
|
|
158
|
+
"durationMs": 310
|
|
159
|
+
}
|
|
160
|
+
],
|
|
161
|
+
"probeRuns": [
|
|
162
|
+
{
|
|
163
|
+
"outcome": "fail",
|
|
164
|
+
"tests": {
|
|
165
|
+
"total": 4,
|
|
166
|
+
"passed": 3,
|
|
167
|
+
"failed": 1
|
|
168
|
+
},
|
|
169
|
+
"assertionFailures": 1,
|
|
170
|
+
"durationMs": 322
|
|
171
|
+
}
|
|
172
|
+
]
|
|
173
|
+
},
|
|
174
|
+
"defenders": {
|
|
175
|
+
"requested": [
|
|
176
|
+
"test/redact.test.mjs"
|
|
177
|
+
],
|
|
178
|
+
"resolved": [
|
|
179
|
+
"test/redact.test.mjs"
|
|
180
|
+
],
|
|
181
|
+
"nocover": false
|
|
182
|
+
},
|
|
183
|
+
"inputs": {
|
|
184
|
+
"targetHash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
185
|
+
"defenderHashes": {
|
|
186
|
+
"test/redact.test.mjs": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"fingerprint": "0a0767ff8b124883e0bc042094c8494027b3d6d45bb8f4e40eda0930214a8970",
|
|
192
|
+
"claim": {
|
|
193
|
+
"id": "REDACT-002",
|
|
194
|
+
"statement": "A rule with an invalid pattern is skipped; it never aborts the scan.",
|
|
195
|
+
"severity": "high",
|
|
196
|
+
"source": {
|
|
197
|
+
"kind": "comment",
|
|
198
|
+
"ref": "src/redact.mjs:41"
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
"subject": {
|
|
202
|
+
"kind": "fault",
|
|
203
|
+
"id": "F1",
|
|
204
|
+
"description": "Invalid pattern rethrows.",
|
|
205
|
+
"file": "src/redact.mjs",
|
|
206
|
+
"faultClass": "exception-swallowed"
|
|
207
|
+
},
|
|
208
|
+
"verdict": "unverifiable",
|
|
209
|
+
"detail": {
|
|
210
|
+
"reason": "anchor-missing",
|
|
211
|
+
"baselineRuns": [],
|
|
212
|
+
"probeRuns": [],
|
|
213
|
+
"anchor": {
|
|
214
|
+
"hits": 0,
|
|
215
|
+
"expected": 1
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
"defenders": {
|
|
219
|
+
"requested": [
|
|
220
|
+
"test/redact.test.mjs"
|
|
221
|
+
],
|
|
222
|
+
"resolved": [
|
|
223
|
+
"test/redact.test.mjs"
|
|
224
|
+
],
|
|
225
|
+
"nocover": false
|
|
226
|
+
},
|
|
227
|
+
"inputs": {
|
|
228
|
+
"targetHash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
229
|
+
"defenderHashes": {
|
|
230
|
+
"test/redact.test.mjs": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
"fingerprint": "81cb777d4cba8dd856ad3f0626fe58186906e5c18a01425d82957adaa963cb28",
|
|
236
|
+
"claim": {
|
|
237
|
+
"id": "REDACT-002",
|
|
238
|
+
"statement": "A rule with an invalid pattern is skipped; it never aborts the scan.",
|
|
239
|
+
"severity": "high",
|
|
240
|
+
"source": {
|
|
241
|
+
"kind": "comment",
|
|
242
|
+
"ref": "src/redact.mjs:41"
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
"subject": {
|
|
246
|
+
"kind": "fault",
|
|
247
|
+
"id": "F1",
|
|
248
|
+
"description": "Invalid pattern rethrows.",
|
|
249
|
+
"file": "src/redact.mjs",
|
|
250
|
+
"faultClass": "exception-swallowed"
|
|
251
|
+
},
|
|
252
|
+
"verdict": "nocover",
|
|
253
|
+
"detail": {
|
|
254
|
+
"baselineRuns": [],
|
|
255
|
+
"probeRuns": []
|
|
256
|
+
},
|
|
257
|
+
"defenders": {
|
|
258
|
+
"requested": [
|
|
259
|
+
"test/rules.test.mjs"
|
|
260
|
+
],
|
|
261
|
+
"resolved": [],
|
|
262
|
+
"nocover": true
|
|
263
|
+
},
|
|
264
|
+
"inputs": {
|
|
265
|
+
"targetHash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
266
|
+
"defenderHashes": {
|
|
267
|
+
"test/redact.test.mjs": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
]
|
|
272
|
+
}
|