spec-controller 0.1.14 → 0.1.16
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.
- package/README.md +44 -40
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# spec-controller
|
|
2
2
|
|
|
3
|
-
**One command, `balance`, that
|
|
3
|
+
**One command, `balance`, that checks the behaviour your scenarios name against the evidence that actually ran.**
|
|
4
4
|
|
|
5
|
-
You
|
|
5
|
+
You give it your Gherkin scenarios and the reports your tools already write: a Vitest report, a Cucumber report, and your CI run's own record of what its steps did. It prints one table that shows which scenarios have living evidence, which do not, and which evidence ran that no scenario asked for.
|
|
6
6
|
|
|
7
|
-
It runs nothing itself. It reads what your pipeline already wrote.
|
|
7
|
+
It runs nothing itself. It only reads what your pipeline already wrote.
|
|
8
8
|
|
|
9
9
|
Requires Node ≥ 22. ESM only.
|
|
10
10
|
|
|
@@ -14,7 +14,7 @@ Requires Node ≥ 22. ESM only.
|
|
|
14
14
|
npm install -g spec-controller
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
Or without installing anything:
|
|
17
|
+
Or run it without installing anything:
|
|
18
18
|
|
|
19
19
|
```
|
|
20
20
|
npx spec-controller balance --help
|
|
@@ -22,29 +22,32 @@ npx spec-controller balance --help
|
|
|
22
22
|
|
|
23
23
|
## Your first run
|
|
24
24
|
|
|
25
|
-
Point it at your scenarios and
|
|
25
|
+
Point it at your scenarios and nothing else:
|
|
26
26
|
|
|
27
27
|
```
|
|
28
28
|
spec-controller balance --features ./features
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
Every scenario
|
|
31
|
+
Every scenario gets a row, whether or not any evidence exists for it. On this first run you have supplied no reports, so every scenario that names evidence reads **missing** and the run is out-of-balance. That is how the tool works, not a fault in your repository: it starts from what you specified, not from what a tool happened to find, and no input makes silence the right answer.
|
|
32
32
|
|
|
33
|
-
**`balance` fails your build
|
|
33
|
+
**`balance` fails your build by default.** An out-of-balance run exits `1`, so the run above reds any pipeline you put it in. Two tools it sits beside do the opposite: Stryker's `thresholds.break` defaults to `null` (*"never let your build fail"*), and the Sonar scanner exits `0` whatever its quality gate says unless you set `sonar.qualitygate.wait`. Both make you opt in to gating. `balance` makes you opt out.
|
|
34
34
|
|
|
35
35
|
### Report first, gate later
|
|
36
36
|
|
|
37
|
-
To
|
|
37
|
+
To add it to an existing pipeline without redding it on day one, add `--exit-zero`:
|
|
38
38
|
|
|
39
39
|
```
|
|
40
40
|
spec-controller balance --features ./features --vitest ./vitest-report.json --exit-zero
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
The report is byte for byte the one the gate prints: the same rows, the same out-of-balance count, and the same headline naming the code the gate would give. Only the exit status
|
|
43
|
+
The report is byte for byte the one the gate prints: the same rows, the same out-of-balance count, and the same headline naming the code the gate would give. Only the exit status changes:
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
- Out-of-balance and scenario code errors (`1`), and pending under `--strict` (`3`), exit `0`.
|
|
46
|
+
- Usage (`2`), unsound (`4`) and nothing to reconcile (`5`) still fail. Each means the run could not reach a verdict at all, and a flag that suppresses verdicts does not suppress that.
|
|
46
47
|
|
|
47
|
-
|
|
48
|
+
Work the out-of-balance rows down, then delete `--exit-zero`, and the gate is on. Do not wrap the step in `continue-on-error` or `|| true` instead. Those swallow the codes that mean the run could not be trusted, and they leave nothing in the command to show the gate is off.
|
|
49
|
+
|
|
50
|
+
### Give it the evidence
|
|
48
51
|
|
|
49
52
|
```
|
|
50
53
|
spec-controller balance \
|
|
@@ -53,9 +56,9 @@ spec-controller balance \
|
|
|
53
56
|
--cucumber ./cucumber-report.json
|
|
54
57
|
```
|
|
55
58
|
|
|
56
|
-
A scenario tagged `@unit` names an obligation
|
|
59
|
+
A scenario tagged `@unit` names an obligation: a unit test must exist and pass. The evidence answers it by citing the scenario's `@SCN` code in its test name. Where the two agree, the row is **balanced**. Where they do not, the row says how: evidence missing, evidence failing, or evidence that cites a scenario nobody wrote.
|
|
57
60
|
|
|
58
|
-
##
|
|
61
|
+
## Exit codes
|
|
59
62
|
|
|
60
63
|
| Exit | What it says |
|
|
61
64
|
| --- | --- |
|
|
@@ -66,32 +69,33 @@ A scenario tagged `@unit` names an obligation — a unit test must exist and pas
|
|
|
66
69
|
| `4` | unsound — a proving suite failed to collect, so the ledger could not be trusted to disagree |
|
|
67
70
|
| `5` | nothing to reconcile — no scenario was carried and no evidence was produced, so the run had no basis for a verdict |
|
|
68
71
|
|
|
69
|
-
The whole report is written before the code is set, so a failing run still tells you why.
|
|
72
|
+
The whole report is written before the exit code is set, so a failing run still tells you why.
|
|
73
|
+
|
|
74
|
+
**Design your pipeline for new codes.** The list is open at the top. A state that is none of the above gets a **new** code rather than being folded into the nearest one; the highest is `5`. So **treat an unrecognised non-zero code as a failure you have not seen before**, not as a synonym for `1`. Matching `1` exactly is not affected when a code is added. Treating any non-zero code as a red build is already correct, only less precise about why.
|
|
75
|
+
|
|
76
|
+
**Node's default exit code is never one of these.** A run that cannot reconcile ends on one of its own codes, never by falling out of the process: a crash that exits `1` would look, by status, exactly like an honest disagreement.
|
|
77
|
+
|
|
78
|
+
**An input it cannot read is a usage error (`2`)**, never a verdict about your code. This covers:
|
|
79
|
+
|
|
80
|
+
- a mistyped path, or a path it is not permitted to read;
|
|
81
|
+
- a file where a directory belongs, or the reverse;
|
|
82
|
+
- an unparseable report, or a report that parses but is not in the shape its runner writes;
|
|
83
|
+
- a saved reconciliation it cannot render;
|
|
84
|
+
- a corpus the Gherkin parser rejects.
|
|
85
|
+
|
|
86
|
+
The refusal names the input, the path, and what was wrong with it. A well-formed report that holds nothing, such as a Vitest run that matched no test file, is read, not refused.
|
|
87
|
+
|
|
88
|
+
**An output location it cannot write is also `2`**: a `--format` path that is read-only, a directory, under a regular file or in a directory that does not exist, or a `--store` root the run directory cannot be created under. It is refused before any report is printed, naming the location and the operating system's reason.
|
|
70
89
|
|
|
71
|
-
`
|
|
90
|
+
`--exit-zero` changes `1` and `3` to `0` and leaves every other code alone (see *Report first, gate later*).
|
|
72
91
|
|
|
73
|
-
|
|
92
|
+
### Re-rendering a saved report
|
|
74
93
|
|
|
75
|
-
`balance --render-from-json <saved.json>` re-renders a saved report and exits the code its verdict names,
|
|
94
|
+
`balance --render-from-json <saved.json>` re-renders a saved report from the same table and exits with the code its verdict names, so a saved run that failed fails again when read back. A report saved under `--strict` records that, so its re-render exits `3` too. `--strict` and `--exit-zero` work beside the re-render as they do on a live run. Any other flag beside it is refused with `2`, because a re-render reads no live input and writes only to stdout.
|
|
76
95
|
|
|
77
|
-
|
|
78
|
-
its own rather than falling out of the process — a crash that exits `1` would be indistinguishable,
|
|
79
|
-
by status, from an honest disagreement. **An input the tool cannot read is part of `2`**: a mistyped
|
|
80
|
-
path, a path it is not permitted to read, a file where a directory belongs or the reverse, an
|
|
81
|
-
unparseable report, a report that parses but is not in the shape its runner writes, a saved
|
|
82
|
-
reconciliation it cannot render, or a corpus the Gherkin parser rejects are all the invocation
|
|
83
|
-
being wrong, never a verdict about your code. The refusal names the input, the path, and what was
|
|
84
|
-
wrong with it. A well-formed report that holds nothing, such as a Vitest run that matched no test
|
|
85
|
-
file, is read, not refused. **So is an output location it cannot write**: a `--format` path that is
|
|
86
|
-
read-only, a directory, under a regular file or in a directory that does not exist, and a
|
|
87
|
-
`--store` root the run directory cannot be created under, are refused at `2`, naming the location and the operating system's reason, before any report is printed.
|
|
96
|
+
### `allocate`
|
|
88
97
|
|
|
89
|
-
|
|
90
|
-
state that is genuinely none of the above gets a **new** code rather than being folded into the
|
|
91
|
-
nearest one — `5` is the most recent, added when a run over a target that carried no scenario and
|
|
92
|
-
produced nothing was found reporting `0`. So **treat an unrecognised non-zero code as a failure you
|
|
93
|
-
have not seen before**, not as a synonym for `1`. Matching `1` exactly is unaffected by a code being
|
|
94
|
-
added; treating *non-zero* as a red build is already correct, and only imprecise about why.
|
|
98
|
+
`spec-controller allocate` prints the next scenario code for a feature part. It reaches no verdict: it exits `0` when it answers, and `2` for a usage error or an unknown part. A file or directory it cannot read, directly or through git, is a usage error: it is refused, naming the path and the reason, and no code is given.
|
|
95
99
|
|
|
96
100
|
## On CI
|
|
97
101
|
|
|
@@ -102,18 +106,18 @@ spec-controller balance --features ./features \
|
|
|
102
106
|
--format json:reconciliation.json
|
|
103
107
|
```
|
|
104
108
|
|
|
105
|
-
`--format`
|
|
109
|
+
`--format` can be repeated and takes an optional `:<path>`. On GitHub Actions, writing Markdown to `$GITHUB_STEP_SUMMARY` puts the reconciliation on the run's summary page. The report is a table, and that is the channel GitHub provides for one. No action, no plugin, no permission.
|
|
106
110
|
|
|
107
|
-
`spec-controller balance --help` lists every flag
|
|
111
|
+
`spec-controller balance --help` lists every flag, one line each.
|
|
108
112
|
|
|
109
113
|
## Where to go next
|
|
110
114
|
|
|
111
|
-
- **Full flags, worked examples and CI wiring
|
|
112
|
-
- **Why `0.x` promises nothing, and what changes at `1.0
|
|
113
|
-
- **Building your own tooling on the engine instead of running a command
|
|
115
|
+
- **Full flags, worked examples and CI wiring**: [`doc/how_to_use.md`](https://github.com/3f-consulting/spec-controller/blob/main/doc/how_to_use.md)
|
|
116
|
+
- **Why `0.x` promises nothing, and what changes at `1.0`**: [`doc/compatibility.md`](https://github.com/3f-consulting/spec-controller/blob/main/doc/compatibility.md)
|
|
117
|
+
- **Building your own tooling on the engine instead of running a command**: [`@3f-consulting/spec-controller-core`](https://www.npmjs.com/package/@3f-consulting/spec-controller-core), the same reconciliation logic as a pure library with no CLI and no I/O.
|
|
114
118
|
|
|
115
119
|
Source, issues and history: [github.com/3f-consulting/spec-controller](https://github.com/3f-consulting/spec-controller).
|
|
116
120
|
|
|
117
121
|
## Licence
|
|
118
122
|
|
|
119
|
-
MIT — see `LICENSE
|
|
123
|
+
MIT — see `LICENSE` in the repository. © 2026 3F Consulting Ltd.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spec-controller",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"description": "Reconcile the behaviour your scenarios name against the evidence that actually ran — the deterministic `balance` CLI.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"reconciliation",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"@cucumber/messages": "^34.0.1",
|
|
27
27
|
"fast-xml-parser": "^5.11.2",
|
|
28
28
|
"yaml": "^2.9.0",
|
|
29
|
-
"@3f-consulting/spec-controller-core": "0.1.
|
|
29
|
+
"@3f-consulting/spec-controller-core": "0.1.16"
|
|
30
30
|
},
|
|
31
31
|
"publishConfig": {
|
|
32
32
|
"access": "public"
|