@rsaglobaltech/specgate 0.10.0 → 0.11.0
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/CHANGELOG.md +64 -0
- package/dist/packages/core/src/domain/DerivedMatrix.js +348 -0
- package/dist/packages/core/src/domain/DerivedMatrix.js.map +1 -0
- package/dist/packages/core/src/domain/RequirementReadiness.js +2 -2
- package/dist/packages/core/src/domain/RequirementReadiness.js.map +1 -1
- package/dist/packages/core/src/infrastructure/DerivedMatrixSources.js +157 -0
- package/dist/packages/core/src/infrastructure/DerivedMatrixSources.js.map +1 -0
- package/dist/packages/core/test/unit/derived-matrix.test.js +196 -0
- package/dist/packages/core/test/unit/derived-matrix.test.js.map +1 -0
- package/dist/scripts/cli/commands/change/ChangeCommand.js +4 -0
- package/dist/scripts/cli/commands/change/ChangeCommand.js.map +1 -1
- package/dist/scripts/cli/commands/harness/RunCommand.js +6 -0
- package/dist/scripts/cli/commands/harness/RunCommand.js.map +1 -1
- package/dist/scripts/cli/commands/pack/ExpandDomainPackCommand.js +9 -0
- package/dist/scripts/cli/commands/pack/ExpandDomainPackCommand.js.map +1 -1
- package/dist/scripts/cli/commands/project/AdoptCommand.js +11 -1
- package/dist/scripts/cli/commands/project/AdoptCommand.js.map +1 -1
- package/dist/scripts/cli/commands/project/InitProjectCommand.js +9 -0
- package/dist/scripts/cli/commands/project/InitProjectCommand.js.map +1 -1
- package/dist/scripts/cli/commands/quality/CheckCommand.js +8 -0
- package/dist/scripts/cli/commands/quality/CheckCommand.js.map +1 -1
- package/dist/scripts/cli/commands/quality/FixCommand.js +20 -0
- package/dist/scripts/cli/commands/quality/FixCommand.js.map +1 -1
- package/dist/scripts/cli/commands/quality/ValidateSpecsCommand.js +17 -0
- package/dist/scripts/cli/commands/quality/ValidateSpecsCommand.js.map +1 -1
- package/dist/scripts/cli/commands/spec/DoneCommand.js +21 -3
- package/dist/scripts/cli/commands/spec/DoneCommand.js.map +1 -1
- package/dist/scripts/cli/commands/spec/MatrixCommand.js +305 -0
- package/dist/scripts/cli/commands/spec/MatrixCommand.js.map +1 -0
- package/dist/scripts/cli/commands/spec/NewCommand.js +6 -1
- package/dist/scripts/cli/commands/spec/NewCommand.js.map +1 -1
- package/dist/scripts/cli/commands/spec/PlanCommand.js +5 -0
- package/dist/scripts/cli/commands/spec/PlanCommand.js.map +1 -1
- package/dist/scripts/cli/commands/spec/ReqCommand.js +24 -3
- package/dist/scripts/cli/commands/spec/ReqCommand.js.map +1 -1
- package/dist/scripts/cli/commands/spec/StatusCommand.js +12 -3
- package/dist/scripts/cli/commands/spec/StatusCommand.js.map +1 -1
- package/dist/scripts/lib/derived-writes.js +91 -0
- package/dist/scripts/lib/derived-writes.js.map +1 -0
- package/dist/scripts/lib/surface.js +14 -6
- package/dist/scripts/lib/surface.js.map +1 -1
- package/dist/scripts/matrix.js +11 -0
- package/dist/scripts/matrix.js.map +1 -0
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,70 @@ The release process is in [`docs/release-process.md`](docs/release-process.md).
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [0.11.0] — 2026-10-07
|
|
12
|
+
|
|
13
|
+
**A matrix nobody edits.** The traceability matrix is now generated for every
|
|
14
|
+
new project: requirements from `spec.md`, scenarios from their tags, tests and
|
|
15
|
+
code from the files that mention the requirement, status from `done`. The daily
|
|
16
|
+
loop is five verbs — `init`, `status`, `new`, `check`, `done` — and no step edits
|
|
17
|
+
the matrix or runs `req link`. Existing projects are untouched until they run
|
|
18
|
+
`specgate matrix --migrate`, which changes nothing unless the result is
|
|
19
|
+
identical row for row. This is the first release published only after an
|
|
20
|
+
end-to-end run of the installed package on Linux, macOS and Windows.
|
|
21
|
+
|
|
22
|
+
**Known limit:** a domain pack writes its own matrix, so `specops add` / `expand`
|
|
23
|
+
turns a project back to a hand-kept matrix and says so.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- **New projects start with a generated matrix.** `init` and `adopt` write the
|
|
28
|
+
matrix and immediately switch it to generated, so nobody maintains it:
|
|
29
|
+
a test that names its requirement is the link. `--keep-matrix` keeps it
|
|
30
|
+
hand-maintained. `req` leaves the short help, which is now the five verbs —
|
|
31
|
+
`init`, `status`, `new`, `check`, `done` — and `new` and `status` stop
|
|
32
|
+
recommending `req link` on a generated project.
|
|
33
|
+
|
|
34
|
+
- **Code is linked the way tests are.** On a generated matrix, a source file
|
|
35
|
+
that mentions `REQ-NNN` is that requirement's technical artifact, so `req link`
|
|
36
|
+
is not needed for either column. `plan` and `harness run` stop warning that a
|
|
37
|
+
row "declares no test/production artifact" there — the mention is the link.
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
|
|
41
|
+
- **`done --check` and the harness gate refresh a generated matrix first.**
|
|
42
|
+
A test written since the last regeneration made the matrix stale, so the
|
|
43
|
+
gate refused the very test that made the requirement deliverable.
|
|
44
|
+
|
|
45
|
+
### Added
|
|
46
|
+
|
|
47
|
+
- **An end-to-end run of the installed package.** `npm run e2e` packs the
|
|
48
|
+
checkout, installs the tarball into an empty directory and drives the binary
|
|
49
|
+
through the journeys a team takes — adopt, `new` → test → `done --strict`, a
|
|
50
|
+
stale matrix, a hand-kept matrix migrated, `ci init`, the harness, an upgrade
|
|
51
|
+
from the last published version. It runs as the `E2E` workflow on every pull
|
|
52
|
+
request on Linux, macOS and Windows, and `publish-npm.yml` publishes a tag
|
|
53
|
+
only if it passes.
|
|
54
|
+
|
|
55
|
+
- **`specgate matrix` — a traceability matrix nobody edits.** The matrix can be
|
|
56
|
+
generated instead of maintained: requirements and titles from `spec.md`,
|
|
57
|
+
scenarios from `@REQ-NNN @SCN-NNN` tags, tests from files that mention the
|
|
58
|
+
requirement, status from `status=` in the section's `csda:trace` comment —
|
|
59
|
+
which also holds any link derivation cannot see. `--migrate` switches an
|
|
60
|
+
existing project over and refuses, changing nothing, unless the generated
|
|
61
|
+
matrix is identical row for row. Once generated, `check` refreshes it and
|
|
62
|
+
`validate` fails with `matrix_stale` when it no longer matches its sources.
|
|
63
|
+
Opt-in: a project that does not migrate is untouched. First part of phase 3
|
|
64
|
+
of the team-simplification plan.
|
|
65
|
+
- **On a generated matrix, the commands write its sources.** `done` sets
|
|
66
|
+
`status=` and `req link` / `req add --feature …` record links in the
|
|
67
|
+
requirement's `csda:trace` comment in `spec.md` — an edit to the row would
|
|
68
|
+
be undone by the next regeneration. `new`, `req rm` and `change archive`
|
|
69
|
+
regenerate the matrix; `status`, `plan` and `check` read it fresh;
|
|
70
|
+
requirements archived into capability specs are derived too. `fix` reports
|
|
71
|
+
there is nothing to repair, and the MCP add-row tool refuses with a pointer
|
|
72
|
+
to `specgate new`. `expand` writes the pack's own matrix, which makes the
|
|
73
|
+
project hand-kept again — it says so, and `matrix --migrate` switches back.
|
|
74
|
+
|
|
11
75
|
## [0.10.0] — 2026-10-06
|
|
12
76
|
|
|
13
77
|
**Five verbs.** A team said the tool was hard to absorb; this release is the
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The traceability matrix as a projection, not a document (phase 3 of
|
|
4
|
+
* mejoras/plan-simplificacion-equipo.md).
|
|
5
|
+
*
|
|
6
|
+
* ## Why
|
|
7
|
+
*
|
|
8
|
+
* The team found the tool hard to absorb, and the matrix was the heaviest part
|
|
9
|
+
* of it: ten columns kept in step by `req add`, `req link`, `done` and a
|
|
10
|
+
* custom merge driver, so that every behaviour change was also a table edit.
|
|
11
|
+
* Everything in a row is already said somewhere else — the requirement in
|
|
12
|
+
* `spec.md`, its scenario by an `@REQ-NNN @SCN-NNN` tag, its test by naming the
|
|
13
|
+
* requirement. This module computes the rows from those sources.
|
|
14
|
+
*
|
|
15
|
+
* ## Where each column comes from
|
|
16
|
+
*
|
|
17
|
+
* | Column | Source |
|
|
18
|
+
* |---|---|
|
|
19
|
+
* | Requirement, Use Case | the `## REQ-NNN — title` section in `spec.md` |
|
|
20
|
+
* | Scenario ID, Feature file | scenarios tagged `@REQ-NNN` (their `@SCN-…`), one row each |
|
|
21
|
+
* | Test artifact | test files that mention `REQ-NNN` |
|
|
22
|
+
* | Technical artifact | other source files that mention `REQ-NNN` |
|
|
23
|
+
* | Status | `status=` in the section's `csda:trace` comment — the one owner |
|
|
24
|
+
* | anything | an explicit key in that comment wins over what is derived |
|
|
25
|
+
*
|
|
26
|
+
* The comment is the grammar capability specs already use
|
|
27
|
+
* (`<!-- csda:trace status=Implemented test=test/totals.test.js -->`), so
|
|
28
|
+
* `TraceabilityMatrix.traceRow` turns it into a row exactly as it does there.
|
|
29
|
+
*
|
|
30
|
+
* ## Why the file is still written
|
|
31
|
+
*
|
|
32
|
+
* Twenty readers open `docs/specs/traceability.md` directly. Keeping it on disk
|
|
33
|
+
* as generated output leaves every one of them working, and keeps the table a
|
|
34
|
+
* reviewer reads in a pull request. What changes is ownership: nobody edits it,
|
|
35
|
+
* and `validate` fails when it no longer matches its sources.
|
|
36
|
+
*/
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.DERIVED_MARKER = void 0;
|
|
39
|
+
exports.isDerivedMatrix = isDerivedMatrix;
|
|
40
|
+
exports.requirementsIn = requirementsIn;
|
|
41
|
+
exports.deriveRows = deriveRows;
|
|
42
|
+
exports.renderDerivedMatrix = renderDerivedMatrix;
|
|
43
|
+
exports.setTraceFields = setTraceFields;
|
|
44
|
+
exports.rowKey = rowKey;
|
|
45
|
+
exports.diffRows = diffRows;
|
|
46
|
+
exports.rowsOf = rowsOf;
|
|
47
|
+
exports.traceValueWritable = traceValueWritable;
|
|
48
|
+
exports.fieldsToReproduce = fieldsToReproduce;
|
|
49
|
+
const TraceabilityMatrix_1 = require("./TraceabilityMatrix");
|
|
50
|
+
const TraceabilityFormat_1 = require("./TraceabilityFormat");
|
|
51
|
+
const SpecParser_1 = require("./SpecParser");
|
|
52
|
+
const GherkinTags_1 = require("./GherkinTags");
|
|
53
|
+
/** First line of a derived matrix. Its presence is what makes a project derived. */
|
|
54
|
+
exports.DERIVED_MARKER = "<!-- specgate:derived — generated from spec.md, features/ and tests. " +
|
|
55
|
+
"Do not edit by hand: run `specgate matrix`. -->";
|
|
56
|
+
function isDerivedMatrix(content) {
|
|
57
|
+
return String(content || "").includes("<!-- specgate:derived");
|
|
58
|
+
}
|
|
59
|
+
const SECTION_HEADING = /^(#{2,4})\s+(REQ-[A-Za-z0-9.]+)\b\s*[—–:-]?\s*(.*)$/;
|
|
60
|
+
const TRACE_LINE = /^\s*<!--\s*csda:trace\b/;
|
|
61
|
+
/** Every `## REQ-NNN — title` section in `spec.md`, in document order. */
|
|
62
|
+
function requirementsIn(spec) {
|
|
63
|
+
const lines = String(spec || "")
|
|
64
|
+
.replace(/\r\n/g, "\n")
|
|
65
|
+
.split("\n");
|
|
66
|
+
const found = [];
|
|
67
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
68
|
+
const m = SECTION_HEADING.exec(lines[i].trim());
|
|
69
|
+
if (!m || found.some((r) => r.id === m[2]))
|
|
70
|
+
continue;
|
|
71
|
+
const level = m[1].length;
|
|
72
|
+
let trace = {};
|
|
73
|
+
for (let j = i + 1; j < lines.length; j += 1) {
|
|
74
|
+
if (new RegExp(`^#{1,${level}}\\s+\\S`).test(lines[j]))
|
|
75
|
+
break;
|
|
76
|
+
if (TRACE_LINE.test(lines[j])) {
|
|
77
|
+
trace = (0, SpecParser_1.parseTraceComment)(lines[j]);
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
found.push({ id: m[2], title: m[3].trim(), trace });
|
|
82
|
+
}
|
|
83
|
+
return found;
|
|
84
|
+
}
|
|
85
|
+
/** `REQ-002` as a whole token: not `REQ-0021`, not `XREQ-002`. */
|
|
86
|
+
function mentions(source, id) {
|
|
87
|
+
const escaped = id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
88
|
+
return new RegExp(`(^|[^A-Za-z0-9])${escaped}(?![A-Za-z0-9])`).test(source);
|
|
89
|
+
}
|
|
90
|
+
/** The scenarios tagged with a requirement: `[{ scn, feature }]`, in file order. */
|
|
91
|
+
function taggedScenarios(features, id) {
|
|
92
|
+
const out = [];
|
|
93
|
+
for (const f of [...features].sort((a, b) => a.path.localeCompare(b.path))) {
|
|
94
|
+
for (const tags of Object.values((0, GherkinTags_1.csdaTagsByScenario)(f.source))) {
|
|
95
|
+
if (!tags.includes(`@${id}`))
|
|
96
|
+
continue;
|
|
97
|
+
const scn = tags.find((t) => t.startsWith("@SCN-"));
|
|
98
|
+
out.push({ scn: scn ? scn.slice(1) : "-", feature: f.path });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return out;
|
|
102
|
+
}
|
|
103
|
+
/** The matrix rows the sources imply. */
|
|
104
|
+
function deriveRows(sources) {
|
|
105
|
+
const rows = [];
|
|
106
|
+
for (const req of requirementsIn(sources.spec)) {
|
|
107
|
+
const trace = { ...req.trace };
|
|
108
|
+
if (!trace.uc && req.title)
|
|
109
|
+
trace.uc = req.title;
|
|
110
|
+
if (!trace.test) {
|
|
111
|
+
const tests = sources.tests
|
|
112
|
+
.filter((t) => mentions(t.source, req.id))
|
|
113
|
+
.map((t) => t.path)
|
|
114
|
+
.sort();
|
|
115
|
+
if (tests.length > 0)
|
|
116
|
+
trace.test = tests.join(", ");
|
|
117
|
+
}
|
|
118
|
+
if (!trace.artifact) {
|
|
119
|
+
const code = (sources.code || [])
|
|
120
|
+
.filter((t) => mentions(t.source, req.id))
|
|
121
|
+
.map((t) => t.path)
|
|
122
|
+
.sort();
|
|
123
|
+
if (code.length > 0)
|
|
124
|
+
trace.artifact = code.join(", ");
|
|
125
|
+
}
|
|
126
|
+
const scenarios = trace.scn || trace.feature ? [] : taggedScenarios(sources.features, req.id);
|
|
127
|
+
const variants = scenarios.length > 0
|
|
128
|
+
? scenarios.map((s) => ({ ...trace, scn: s.scn, feature: s.feature }))
|
|
129
|
+
: [trace];
|
|
130
|
+
for (const t of variants) {
|
|
131
|
+
const row = TraceabilityMatrix_1.TraceabilityMatrix.traceRow({ id: req.id, trace: t });
|
|
132
|
+
if (t.depends)
|
|
133
|
+
row.dependsOn = String(t.depends).split(",").filter(Boolean);
|
|
134
|
+
if (t.context)
|
|
135
|
+
row.context = t.context;
|
|
136
|
+
rows.push(row);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const fromSpec = new Set(rows.map((r) => r.requirement));
|
|
140
|
+
for (const cap of [...(sources.capabilities || [])].sort((a, b) => a.path.localeCompare(b.path))) {
|
|
141
|
+
let parsed;
|
|
142
|
+
try {
|
|
143
|
+
parsed = (0, SpecParser_1.parseSpec)(cap.source);
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
for (const req of parsed.requirements || []) {
|
|
149
|
+
if (!req.id || fromSpec.has(req.id))
|
|
150
|
+
continue;
|
|
151
|
+
const row = TraceabilityMatrix_1.TraceabilityMatrix.traceRow(req);
|
|
152
|
+
const trace = req.trace || {};
|
|
153
|
+
if (trace.depends)
|
|
154
|
+
row.dependsOn = String(trace.depends).split(",").filter(Boolean);
|
|
155
|
+
if (trace.context)
|
|
156
|
+
row.context = trace.context;
|
|
157
|
+
rows.push(row);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return rows;
|
|
161
|
+
}
|
|
162
|
+
/** The generated `traceability.md`. */
|
|
163
|
+
function renderDerivedMatrix(rows, projectName) {
|
|
164
|
+
const body = (0, TraceabilityFormat_1.buildTraceabilityMarkdown)(rows, "rich").replace("# Traceability Matrix", `# Traceability Matrix${projectName ? ` — ${projectName}` : ""}`);
|
|
165
|
+
return `${exports.DERIVED_MARKER}\n${body}`;
|
|
166
|
+
}
|
|
167
|
+
// ── Writing the one owner ────────────────────────────────────────────────────
|
|
168
|
+
/**
|
|
169
|
+
* `spec.md` with `fields` set in `reqId`'s `csda:trace` comment.
|
|
170
|
+
*
|
|
171
|
+
* The comment is created right under the heading when the section has none.
|
|
172
|
+
* A value of `""` removes the key. Returns `null` when the section is absent.
|
|
173
|
+
*/
|
|
174
|
+
function setTraceFields(spec, reqId, fields) {
|
|
175
|
+
const lines = String(spec || "")
|
|
176
|
+
.replace(/\r\n/g, "\n")
|
|
177
|
+
.split("\n");
|
|
178
|
+
let heading = -1;
|
|
179
|
+
let level = 2;
|
|
180
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
181
|
+
const m = SECTION_HEADING.exec(lines[i].trim());
|
|
182
|
+
if (m && m[2] === reqId) {
|
|
183
|
+
heading = i;
|
|
184
|
+
level = m[1].length;
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (heading === -1)
|
|
189
|
+
return null;
|
|
190
|
+
let at = -1;
|
|
191
|
+
for (let j = heading + 1; j < lines.length; j += 1) {
|
|
192
|
+
if (new RegExp(`^#{1,${level}}\\s+\\S`).test(lines[j]))
|
|
193
|
+
break;
|
|
194
|
+
if (TRACE_LINE.test(lines[j])) {
|
|
195
|
+
at = j;
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
const current = at === -1 ? {} : (0, SpecParser_1.parseTraceComment)(lines[at]);
|
|
200
|
+
const merged = { ...current };
|
|
201
|
+
for (const [k, v] of Object.entries(fields)) {
|
|
202
|
+
if (v === "")
|
|
203
|
+
delete merged[k];
|
|
204
|
+
else
|
|
205
|
+
merged[k] = v;
|
|
206
|
+
}
|
|
207
|
+
const rendered = renderTraceComment(merged);
|
|
208
|
+
if (at !== -1) {
|
|
209
|
+
if (rendered === null)
|
|
210
|
+
lines.splice(at, 1);
|
|
211
|
+
else
|
|
212
|
+
lines[at] = rendered;
|
|
213
|
+
}
|
|
214
|
+
else if (rendered !== null) {
|
|
215
|
+
lines.splice(heading + 1, 0, "", rendered);
|
|
216
|
+
}
|
|
217
|
+
return lines.join("\n");
|
|
218
|
+
}
|
|
219
|
+
/** Keys in a stable order, so a status change is a one-line diff. */
|
|
220
|
+
const KEY_ORDER = [
|
|
221
|
+
"status",
|
|
222
|
+
"scn",
|
|
223
|
+
"feature",
|
|
224
|
+
"test",
|
|
225
|
+
"artifact",
|
|
226
|
+
"uc",
|
|
227
|
+
"cmd",
|
|
228
|
+
"qry",
|
|
229
|
+
"agg",
|
|
230
|
+
"evt",
|
|
231
|
+
];
|
|
232
|
+
function renderTraceComment(trace) {
|
|
233
|
+
const keys = Object.keys(trace).sort((a, b) => {
|
|
234
|
+
const ia = KEY_ORDER.indexOf(a);
|
|
235
|
+
const ib = KEY_ORDER.indexOf(b);
|
|
236
|
+
return (ia === -1 ? 99 : ia) - (ib === -1 ? 99 : ib) || a.localeCompare(b);
|
|
237
|
+
});
|
|
238
|
+
if (keys.length === 0)
|
|
239
|
+
return null;
|
|
240
|
+
const parts = keys.map((k) => {
|
|
241
|
+
// The grammar has quotes and no escapes: a value with spaces is wrapped in
|
|
242
|
+
// whichever quote it does not contain. One with both cannot be written,
|
|
243
|
+
// and `traceValueWritable` keeps migration from trying.
|
|
244
|
+
const v = String(trace[k]);
|
|
245
|
+
if (!/[\s"']/.test(v))
|
|
246
|
+
return `${k}=${v}`;
|
|
247
|
+
return v.includes("'") ? `${k}="${v}"` : `${k}='${v}'`;
|
|
248
|
+
});
|
|
249
|
+
return `<!-- csda:trace ${parts.join(" ")} -->`;
|
|
250
|
+
}
|
|
251
|
+
// ── Comparing, for --check and for migration ─────────────────────────────────
|
|
252
|
+
const COLUMNS = [
|
|
253
|
+
"requirement",
|
|
254
|
+
"scenarioId",
|
|
255
|
+
"featureFile",
|
|
256
|
+
"useCase",
|
|
257
|
+
"commandOrQuery",
|
|
258
|
+
"aggregate",
|
|
259
|
+
"event",
|
|
260
|
+
"technicalArtifact",
|
|
261
|
+
"testArtifact",
|
|
262
|
+
"status",
|
|
263
|
+
];
|
|
264
|
+
function norm(v) {
|
|
265
|
+
const s = String(v ?? "-")
|
|
266
|
+
.replace(/`/g, "")
|
|
267
|
+
.replace(/\s*,\s*/g, ", ")
|
|
268
|
+
.trim() || "-";
|
|
269
|
+
// `-` and `TBD` both mean "no test declared"; the gate reads them alike.
|
|
270
|
+
return s.toUpperCase() === "TBD" ? "-" : s;
|
|
271
|
+
}
|
|
272
|
+
/** A row as a comparable key, backticks and spacing ignored. */
|
|
273
|
+
function rowKey(row) {
|
|
274
|
+
return COLUMNS.map((c) => norm(row[c])).join(" | ");
|
|
275
|
+
}
|
|
276
|
+
/** Rows present on one side and not the other. Empty both ways means equal. */
|
|
277
|
+
function diffRows(expected, actual) {
|
|
278
|
+
const a = expected.map(rowKey);
|
|
279
|
+
const b = actual.map(rowKey);
|
|
280
|
+
const missing = a.filter((k) => !b.includes(k));
|
|
281
|
+
const extra = b.filter((k) => !a.includes(k));
|
|
282
|
+
return { missing, extra };
|
|
283
|
+
}
|
|
284
|
+
/** The rows a matrix file holds, in the shape `deriveRows` returns. */
|
|
285
|
+
function rowsOf(matrixContent) {
|
|
286
|
+
const parsed = (0, TraceabilityFormat_1.parseTraceabilityRows)(matrixContent);
|
|
287
|
+
return parsed.mode === "rich" ? parsed.rows : [];
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* The `csda:trace` fields a requirement needs so that derivation reproduces
|
|
291
|
+
* `rows` — or the reason it cannot.
|
|
292
|
+
*
|
|
293
|
+
* Only what derivation would get wrong is written: a matrix whose tags and
|
|
294
|
+
* test names already carry the links migrates to nothing but status lines.
|
|
295
|
+
*/
|
|
296
|
+
/** Can this value be stored in a `csda:trace` comment and read back intact? */
|
|
297
|
+
function traceValueWritable(v) {
|
|
298
|
+
return !(v.includes("'") && v.includes('"')) && !v.includes("-->");
|
|
299
|
+
}
|
|
300
|
+
function fieldsToReproduce(req, rows, sources) {
|
|
301
|
+
const derived = deriveRows({
|
|
302
|
+
...sources,
|
|
303
|
+
spec: `## ${req.id} — ${req.title}\n`,
|
|
304
|
+
});
|
|
305
|
+
if (rows.length > 1) {
|
|
306
|
+
// Several rows for one requirement: only tags can say which scenario is
|
|
307
|
+
// which, and every other column has to agree across them.
|
|
308
|
+
const shared = COLUMNS.filter((c) => !["scenarioId", "featureFile"].includes(c));
|
|
309
|
+
const disagree = shared.filter((c) => new Set(rows.map((r) => norm(r[c]))).size > 1);
|
|
310
|
+
if (disagree.length > 0) {
|
|
311
|
+
return {
|
|
312
|
+
reason: `${rows.length} rows that differ in ${disagree.join(", ")} — one requirement, one value per column`,
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
const wanted = rows.map((r) => `${norm(r.scenarioId)}@${norm(r.featureFile)}`).sort();
|
|
316
|
+
const got = derived.map((r) => `${norm(r.scenarioId)}@${norm(r.featureFile)}`).sort();
|
|
317
|
+
if (wanted.join() !== got.join()) {
|
|
318
|
+
return {
|
|
319
|
+
reason: `${rows.length} scenarios that are not tagged @${req.id} @SCN-… in their feature files`,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
const row = rows[0];
|
|
324
|
+
const first = derived[0] || {};
|
|
325
|
+
const fields = {};
|
|
326
|
+
const set = (key, column, value) => {
|
|
327
|
+
if (norm(row[column]) !== norm(first[column]))
|
|
328
|
+
fields[key] = value ?? norm(row[column]);
|
|
329
|
+
};
|
|
330
|
+
if (rows.length === 1) {
|
|
331
|
+
set("scn", "scenarioId");
|
|
332
|
+
set("feature", "featureFile");
|
|
333
|
+
}
|
|
334
|
+
set("uc", "useCase");
|
|
335
|
+
set("cmd", "commandOrQuery");
|
|
336
|
+
set("agg", "aggregate");
|
|
337
|
+
set("evt", "event");
|
|
338
|
+
set("artifact", "technicalArtifact");
|
|
339
|
+
set("test", "testArtifact");
|
|
340
|
+
if (norm(row.status) !== "Draft")
|
|
341
|
+
fields.status = norm(row.status);
|
|
342
|
+
const unwritable = Object.entries(fields).find(([, v]) => !traceValueWritable(v));
|
|
343
|
+
if (unwritable) {
|
|
344
|
+
return { reason: `its ${unwritable[0]} cell mixes both quote characters: ${unwritable[1]}` };
|
|
345
|
+
}
|
|
346
|
+
return { fields };
|
|
347
|
+
}
|
|
348
|
+
//# sourceMappingURL=DerivedMatrix.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DerivedMatrix.js","sourceRoot":"","sources":["../../../../../packages/core/src/domain/DerivedMatrix.ts"],"names":[],"mappings":"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"}
|
|
@@ -102,11 +102,11 @@ function requirementReadiness(input) {
|
|
|
102
102
|
// These are not the noise trap A2 had to avoid. `TBD` in the test column is
|
|
103
103
|
// not a false positive; it is an accurate statement about an incomplete row,
|
|
104
104
|
// and TDD says that column is what should be filled in first.
|
|
105
|
-
if (!input.testDeclared) {
|
|
105
|
+
if (!input.testDeclared && !input.derived) {
|
|
106
106
|
blockers.push((0, Diagnostic_1.warning)(exports.READINESS_CODES.NO_TEST_ARTIFACT, "the row declares no test artifact, so the agent chooses where the test " +
|
|
107
107
|
"goes and the matrix will point somewhere else.", { target, fix: `specgate req link ${target} --test <path>` }));
|
|
108
108
|
}
|
|
109
|
-
if (!input.technicalDeclared) {
|
|
109
|
+
if (!input.technicalDeclared && !input.derived) {
|
|
110
110
|
blockers.push((0, Diagnostic_1.warning)(exports.READINESS_CODES.NO_TECHNICAL_ARTIFACT, "the row declares no production artifact, so the agent chooses where the " +
|
|
111
111
|
"implementation goes and the matrix will point somewhere else.", { target, fix: `specgate req link ${target} --code <path>` }));
|
|
112
112
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RequirementReadiness.js","sourceRoot":"","sources":["../../../../../packages/core/src/domain/RequirementReadiness.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;;;
|
|
1
|
+
{"version":3,"file":"RequirementReadiness.js","sourceRoot":"","sources":["../../../../../packages/core/src/domain/RequirementReadiness.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;;;AAiDH,oDAoGC;AAlJD,6CAA8C;AAEjC,QAAA,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC;IAC3C,UAAU,EAAE,4BAA4B;IACxC,mBAAmB,EAAE,iCAAiC;IACtD,UAAU,EAAE,mCAAmC;IAC/C,UAAU,EAAE,wBAAwB;IACpC,mBAAmB,EAAE,iCAAiC;IACtD,gBAAgB,EAAE,uCAAuC;IACzD,qBAAqB,EAAE,4CAA4C;CACpE,CAAC,CAAC;AAEH,qEAAqE;AACxD,QAAA,kBAAkB,GAAqC,MAAM,CAAC,MAAM,CAAC;IAChF,UAAU,EAAE,uBAAe,CAAC,UAAU;IACtC,qBAAqB,EAAE,uBAAe,CAAC,mBAAmB;CAC3D,CAAC,CAAC;AA8BH,SAAgB,oBAAoB,CAAC,KAAqB;IACxD,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC;IACjC,MAAM,QAAQ,GAAiB,EAAE,CAAC;IAElC,MAAM,WAAW,GAAG,0BAAkB,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC;IACnE,IAAI,WAAW,EAAE,CAAC;QAChB,QAAQ,CAAC,IAAI,CACX,IAAA,kBAAK,EACH,WAAW,EACX,WAAW,KAAK,uBAAe,CAAC,UAAU;YACxC,CAAC,CAAC,aAAa,KAAK,CAAC,MAAM,6BAA6B;YACxD,CAAC,CAAC,aAAa,KAAK,CAAC,MAAM,iDAAiD;gBACxE,4DAA4D,EAClE;YACE,MAAM;YACN,GAAG,EACD,WAAW,KAAK,uBAAe,CAAC,UAAU;gBACxC,CAAC,CAAC,0DAA0D;gBAC5D,CAAC,CAAC,yEAAyE;SAChF,CACF,CACF,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;QACzB,QAAQ,CAAC,IAAI,CACX,IAAA,kBAAK,EACH,uBAAe,CAAC,UAAU,EAC1B,KAAK,CAAC,WAAW;YACf,CAAC,CAAC,oBAAoB,KAAK,CAAC,WAAW,kCAAkC;gBACrE,kCAAkC;YACtC,CAAC,CAAC,mFAAmF,EACvF;YACE,MAAM;YACN,GAAG,EAAE,iDAAiD,MAAM,sBAAsB;SACnF,CACF,CACF,CAAC;IACJ,CAAC;IAED,wEAAwE;IACxE,4DAA4D;IAC5D,MAAM,UAAU,GAAG,CAAC,KAAK,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC;IACxF,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,QAAQ,CAAC,IAAI,CACX,IAAA,kBAAK,EACH,uBAAe,CAAC,mBAAmB,EACnC,qDAAqD,UAAU,CAAC,MAAM,cAAc;YAClF,kDAAkD,EACpD;YACE,MAAM;YACN,GAAG,EAAE,mFAAmF;SACzF,CACF,CACF,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC;IACtC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,QAAQ,CAAC,IAAI,CACX,IAAA,kBAAK,EACH,uBAAe,CAAC,UAAU,EAC1B,iBAAiB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,YAAY,EAC7F;YACE,MAAM;YACN,GAAG,EAAE,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,wDAAwD;SACvF,CACF,CACF,CAAC;IACJ,CAAC;IAED,6EAA6E;IAC7E,wEAAwE;IACxE,uCAAuC;IACvC,EAAE;IACF,4EAA4E;IAC5E,6EAA6E;IAC7E,8DAA8D;IAC9D,IAAI,CAAC,KAAK,CAAC,YAAY,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QAC1C,QAAQ,CAAC,IAAI,CACX,IAAA,oBAAO,EACL,uBAAe,CAAC,gBAAgB,EAChC,yEAAyE;YACvE,gDAAgD,EAClD,EAAE,MAAM,EAAE,GAAG,EAAE,qBAAqB,MAAM,gBAAgB,EAAE,CAC7D,CACF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,iBAAiB,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QAC/C,QAAQ,CAAC,IAAI,CACX,IAAA,oBAAO,EACL,uBAAe,CAAC,qBAAqB,EACrC,0EAA0E;YACxE,+DAA+D,EACjE,EAAE,MAAM,EAAE,GAAG,EAAE,qBAAqB,MAAM,gBAAgB,EAAE,CAC7D,CACF,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,EAAE,QAAQ,EAAE,CAAC;AAC5E,CAAC"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.isTestFile = isTestFile;
|
|
37
|
+
exports.readDerivationSources = readDerivationSources;
|
|
38
|
+
const fs = __importStar(require("node:fs"));
|
|
39
|
+
const path = __importStar(require("node:path"));
|
|
40
|
+
/**
|
|
41
|
+
* Reading what a derived matrix is computed from: `spec.md`, every
|
|
42
|
+
* `.feature` under `features/`, and the project's test files.
|
|
43
|
+
*
|
|
44
|
+
* Test files are found by convention, not configuration — the conventions of
|
|
45
|
+
* the stacks `adopt` detects. A team whose tests live elsewhere states the
|
|
46
|
+
* link explicitly (`test=` in the requirement's `csda:trace`), which is what
|
|
47
|
+
* the gate already accepts.
|
|
48
|
+
*/
|
|
49
|
+
/** Never descended into: dependencies, build output, and the spec tree itself. */
|
|
50
|
+
const SKIP_DIRS = new Set([
|
|
51
|
+
".git",
|
|
52
|
+
"node_modules",
|
|
53
|
+
"dist",
|
|
54
|
+
"build",
|
|
55
|
+
"target",
|
|
56
|
+
"out",
|
|
57
|
+
"coverage",
|
|
58
|
+
"vendor",
|
|
59
|
+
".venv",
|
|
60
|
+
"venv",
|
|
61
|
+
"__pycache__",
|
|
62
|
+
".gradle",
|
|
63
|
+
".idea",
|
|
64
|
+
".vscode",
|
|
65
|
+
".csda",
|
|
66
|
+
".specgate",
|
|
67
|
+
".harness",
|
|
68
|
+
"features",
|
|
69
|
+
"docs",
|
|
70
|
+
"changes",
|
|
71
|
+
"bin",
|
|
72
|
+
"obj",
|
|
73
|
+
]);
|
|
74
|
+
const TEST_DIR = /^(test|tests|__tests__|spec|specs|testing|integration-tests|e2e)$/i;
|
|
75
|
+
const TEST_NAME = /([._-](test|spec|it)\.[a-z0-9]+$)|(^test_.*\.py$)|(_test\.(go|py|rb|exs|rs|cc|cpp)$)|((Test|Tests|IT|Spec)\.(java|kt|kts|scala|groovy|cs|swift)$)/;
|
|
76
|
+
const CODE_EXT = /\.(js|jsx|mjs|cjs|ts|tsx|mts|cts|py|go|rb|java|kt|kts|scala|groovy|cs|fs|swift|rs|php|ex|exs|c|cc|cpp|h|hpp|feature|sh)$/i;
|
|
77
|
+
const MAX_BYTES = 1_000_000;
|
|
78
|
+
const MAX_FILES = 20_000;
|
|
79
|
+
/** Is this a test file by the conventions of the common stacks? */
|
|
80
|
+
function isTestFile(rel) {
|
|
81
|
+
const parts = rel.split("/");
|
|
82
|
+
const name = parts[parts.length - 1];
|
|
83
|
+
if (!CODE_EXT.test(name))
|
|
84
|
+
return false;
|
|
85
|
+
if (TEST_NAME.test(name))
|
|
86
|
+
return true;
|
|
87
|
+
// `src/test/java/...` (Maven/Gradle) and plain `test/` or `tests/` trees.
|
|
88
|
+
return parts.slice(0, -1).some((p) => TEST_DIR.test(p));
|
|
89
|
+
}
|
|
90
|
+
function walk(root, rel, pick, out) {
|
|
91
|
+
if (out.length >= MAX_FILES)
|
|
92
|
+
return;
|
|
93
|
+
let entries;
|
|
94
|
+
try {
|
|
95
|
+
entries = fs.readdirSync(path.join(root, rel), { withFileTypes: true });
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
for (const e of entries) {
|
|
101
|
+
const childRel = rel ? `${rel}/${e.name}` : e.name;
|
|
102
|
+
if (e.isDirectory()) {
|
|
103
|
+
if (!SKIP_DIRS.has(e.name) && !e.name.startsWith("."))
|
|
104
|
+
walk(root, childRel, pick, out);
|
|
105
|
+
}
|
|
106
|
+
else if (e.isFile() && pick(childRel)) {
|
|
107
|
+
out.push(childRel);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function read(root, rel) {
|
|
112
|
+
try {
|
|
113
|
+
const abs = path.join(root, rel);
|
|
114
|
+
if (fs.statSync(abs).size > MAX_BYTES)
|
|
115
|
+
return null;
|
|
116
|
+
return { path: rel, source: fs.readFileSync(abs, "utf8") };
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function readDerivationSources(projectDir) {
|
|
123
|
+
const spec = fs.existsSync(path.join(projectDir, "spec.md"))
|
|
124
|
+
? fs.readFileSync(path.join(projectDir, "spec.md"), "utf8")
|
|
125
|
+
: "";
|
|
126
|
+
const featurePaths = [];
|
|
127
|
+
walk(path.join(projectDir, "features"), "", (r) => r.endsWith(".feature"), featurePaths);
|
|
128
|
+
const features = featurePaths
|
|
129
|
+
.map((r) => read(projectDir, `features/${r}`))
|
|
130
|
+
.filter((f) => f !== null);
|
|
131
|
+
// One walk for both: every source file, split by the test convention.
|
|
132
|
+
const sourcePaths = [];
|
|
133
|
+
walk(projectDir, "", (r) => CODE_EXT.test(r) && !r.endsWith(".feature"), sourcePaths);
|
|
134
|
+
const tests = [];
|
|
135
|
+
const code = [];
|
|
136
|
+
for (const rel of sourcePaths) {
|
|
137
|
+
const f = read(projectDir, rel);
|
|
138
|
+
if (f)
|
|
139
|
+
(isTestFile(rel) ? tests : code).push(f);
|
|
140
|
+
}
|
|
141
|
+
const capDir = path.join(projectDir, "docs", "specs", "capabilities");
|
|
142
|
+
const capabilities = [];
|
|
143
|
+
try {
|
|
144
|
+
for (const e of fs.readdirSync(capDir, { withFileTypes: true })) {
|
|
145
|
+
if (!e.isDirectory())
|
|
146
|
+
continue;
|
|
147
|
+
const f = read(projectDir, `docs/specs/capabilities/${e.name}/spec.md`);
|
|
148
|
+
if (f)
|
|
149
|
+
capabilities.push(f);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
/* no capability specs: a spec.md-only project */
|
|
154
|
+
}
|
|
155
|
+
return { spec, features, tests, capabilities, code };
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=DerivedMatrixSources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DerivedMatrixSources.js","sourceRoot":"","sources":["../../../../../packages/core/src/infrastructure/DerivedMatrixSources.ts"],"names":[],"mappings":"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"}
|