@descent-vtt/spec-graph 0.8.0 → 0.9.1
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 +483 -38
- package/README.md +134 -49
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +38 -19
- package/dist/cli.js.map +1 -1
- package/dist/directives.d.ts +9 -2
- package/dist/directives.js +15 -4
- package/dist/directives.js.map +1 -1
- package/dist/extract.d.ts +1 -1
- package/dist/extract.js +50 -16
- package/dist/extract.js.map +1 -1
- package/dist/glob.d.ts +44 -44
- package/dist/glob.js +152 -116
- package/dist/glob.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/lifecycle.js +10 -2
- package/dist/lifecycle.js.map +1 -1
- package/dist/markdown.d.ts +53 -161
- package/dist/markdown.js +42 -864
- package/dist/markdown.js.map +1 -1
- package/dist/report.d.ts +23 -0
- package/dist/report.js +80 -0
- package/dist/report.js.map +1 -1
- package/dist/rules.js +48 -14
- package/dist/rules.js.map +1 -1
- package/dist/sections.d.ts +1 -1
- package/dist/sections.js +7 -3
- package/dist/sections.js.map +1 -1
- package/dist/select.d.ts +2 -2
- package/dist/select.js +3 -3
- package/dist/select.js.map +1 -1
- package/dist/source.d.ts +6 -19
- package/dist/source.js +4 -70
- package/dist/source.js.map +1 -1
- package/dist/types.d.ts +23 -3
- package/dist/types.js +1 -1
- package/dist/types.js.map +1 -1
- package/dist/vendor/spec-core/markdown/frontmatter.d.ts +103 -0
- package/dist/vendor/spec-core/markdown/frontmatter.js +459 -0
- package/dist/vendor/spec-core/markdown/frontmatter.js.map +1 -0
- package/dist/vendor/spec-core/markdown/headings.d.ts +45 -0
- package/dist/vendor/spec-core/markdown/headings.js +199 -0
- package/dist/vendor/spec-core/markdown/headings.js.map +1 -0
- package/dist/vendor/spec-core/markdown/index.d.ts +5 -0
- package/dist/vendor/spec-core/markdown/index.js +4 -0
- package/dist/vendor/spec-core/markdown/index.js.map +1 -0
- package/dist/vendor/spec-core/markdown/layout.d.ts +39 -0
- package/dist/vendor/spec-core/markdown/layout.js +28 -0
- package/dist/vendor/spec-core/markdown/layout.js.map +1 -0
- package/dist/vendor/spec-core/markdown/links.d.ts +25 -0
- package/dist/vendor/spec-core/markdown/links.js +394 -0
- package/dist/vendor/spec-core/markdown/links.js.map +1 -0
- package/dist/vendor/spec-core/markdown/lists.d.ts +22 -0
- package/dist/vendor/spec-core/markdown/lists.js +127 -0
- package/dist/vendor/spec-core/markdown/lists.js.map +1 -0
- package/dist/vendor/spec-core/markdown/scan.d.ts +36 -0
- package/dist/vendor/spec-core/markdown/scan.js +463 -0
- package/dist/vendor/spec-core/markdown/scan.js.map +1 -0
- package/dist/vendor/spec-core/markdown/syntax.d.ts +75 -0
- package/dist/vendor/spec-core/markdown/syntax.js +181 -0
- package/dist/vendor/spec-core/markdown/syntax.js.map +1 -0
- package/dist/vendor/spec-core/markdown/tables.d.ts +18 -0
- package/dist/vendor/spec-core/markdown/tables.js +86 -0
- package/dist/vendor/spec-core/markdown/tables.js.map +1 -0
- package/dist/vendor/spec-core/markdown/types.d.ts +290 -0
- package/dist/vendor/spec-core/markdown/types.js +9 -0
- package/dist/vendor/spec-core/markdown/types.js.map +1 -0
- package/dist/vendor/spec-core/path/index.d.ts +1 -0
- package/dist/vendor/spec-core/path/index.js +2 -0
- package/dist/vendor/spec-core/path/index.js.map +1 -0
- package/dist/vendor/spec-core/path/posix.d.ts +83 -0
- package/dist/vendor/spec-core/path/posix.js +150 -0
- package/dist/vendor/spec-core/path/posix.js.map +1 -0
- package/dist/vendor/spec-core/pattern/automaton.d.ts +129 -0
- package/dist/vendor/spec-core/pattern/automaton.js +340 -0
- package/dist/vendor/spec-core/pattern/automaton.js.map +1 -0
- package/dist/vendor/spec-core/pattern/charset.d.ts +58 -0
- package/dist/vendor/spec-core/pattern/charset.js +116 -0
- package/dist/vendor/spec-core/pattern/charset.js.map +1 -0
- package/dist/vendor/spec-core/pattern/glob.d.ts +121 -0
- package/dist/vendor/spec-core/pattern/glob.js +481 -0
- package/dist/vendor/spec-core/pattern/glob.js.map +1 -0
- package/dist/vendor/spec-core/pattern/index.d.ts +6 -0
- package/dist/vendor/spec-core/pattern/index.js +4 -0
- package/dist/vendor/spec-core/pattern/index.js.map +1 -0
- package/dist/{regex.d.ts → vendor/spec-core/pattern/regex.d.ts} +20 -29
- package/dist/{regex.js → vendor/spec-core/pattern/regex.js} +40 -49
- package/dist/vendor/spec-core/pattern/regex.js.map +1 -0
- package/dist/vendor/spec-core/text/index.d.ts +2 -0
- package/dist/vendor/spec-core/text/index.js +2 -0
- package/dist/vendor/spec-core/text/index.js.map +1 -0
- package/dist/vendor/spec-core/text/lines.d.ts +72 -0
- package/dist/vendor/spec-core/text/lines.js +156 -0
- package/dist/vendor/spec-core/text/lines.js.map +1 -0
- package/dist/yaml.d.ts +44 -12
- package/dist/yaml.js +115 -206
- package/dist/yaml.js.map +1 -1
- package/package.json +4 -3
- package/src/vendor/spec-core/LICENSE +21 -0
- package/src/vendor/spec-core/README.md +8 -0
- package/dist/regex.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,451 @@
|
|
|
3
3
|
Notable changes, newest first. Versions follow [semver](https://semver.org):
|
|
4
4
|
a patch fixes behaviour without asking anything of a repository that upgrades.
|
|
5
5
|
|
|
6
|
+
## 0.9.1
|
|
7
|
+
|
|
8
|
+
Nothing to do on upgrading. The same documents give the same findings, in
|
|
9
|
+
every format, and the same graph exports as they did under 0.9.0; the one
|
|
10
|
+
difference a program that imports spec-graph can see is a badge wrapped in a
|
|
11
|
+
link, which `ScannedDocument.links` now lists. The scanner is spec-core
|
|
12
|
+
8840d36, the README's and this changelog's links to the ADRs work on
|
|
13
|
+
npmjs.com and in `node_modules`, and `npm publish` refuses to run from a
|
|
14
|
+
checkout.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- **spec-core 8840d36.** An image inside a link's text, a badge wrapped in a
|
|
19
|
+
link such as `[](actions)`, is listed in
|
|
20
|
+
`ScannedDocument.links` after the link around it, where CommonMark renders
|
|
21
|
+
it; the scan used to skip it. spec-graph reads no image as a reference but a
|
|
22
|
+
wiki embed, so no finding and no edge moves: run over the same documents,
|
|
23
|
+
this repository's, its fixtures' and the rest of the family's, every `check`
|
|
24
|
+
format and every graph export is byte for byte what 0.9.0 wrote. A program
|
|
25
|
+
that reads `links` for images sees the badges it missed. `links`,
|
|
26
|
+
`listItems` and `masks.directives` are made the first time they are read,
|
|
27
|
+
and kept, rather than for every document; they hold what they held.
|
|
28
|
+
- `npm publish` in a checkout refuses to run outside GitHub Actions, so a
|
|
29
|
+
version cannot reach npm from a workstation by mistake, without provenance;
|
|
30
|
+
spec-harness 0.1.0 did. The release never runs it: it stages a tarball it
|
|
31
|
+
packed.
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
|
|
35
|
+
- The README's and this changelog's links to the ADRs and to `CLAUDE.md` were
|
|
36
|
+
relative, and the package ships neither, so on npmjs.com and inside
|
|
37
|
+
`node_modules` they led nowhere. They are GitHub URLs now. A test holds
|
|
38
|
+
every link in a shipped document to a file the package ships or to an
|
|
39
|
+
absolute URL, and every URL into this repository to a file it holds.
|
|
40
|
+
|
|
41
|
+
## 0.9.0
|
|
42
|
+
|
|
43
|
+
Versions are staged by CI from a `v*` tag, through npm's trusted
|
|
44
|
+
publishing, and released by a maintainer with a second factor, no longer
|
|
45
|
+
published from a workstation
|
|
46
|
+
([ADR-0021](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0021-releases-are-published-by-ci.md)). There is no
|
|
47
|
+
publish token anywhere, and every version from here on carries a provenance
|
|
48
|
+
attestation naming the repository, the commit and the run that built the
|
|
49
|
+
tarball. `npm audit signatures` checks it without taking anyone's word for
|
|
50
|
+
anything. 0.2.0 to 0.8.0 have none and never will.
|
|
51
|
+
|
|
52
|
+
**What to expect on upgrading.** More findings rather than fewer, and nearly
|
|
53
|
+
all of them from one change: a code span ends with its paragraph. Over a large
|
|
54
|
+
repository of hand-written decisions and logs that 0.8.0 checked, almost every
|
|
55
|
+
difference was a `broken-reference`. Bare identifiers that a lone backtick
|
|
56
|
+
earlier in a paragraph or a table had hidden are read now, and many name
|
|
57
|
+
nothing; a few that 0.8.0 read out of real code spans, its backticks out of
|
|
58
|
+
step, are code again and go. Text read for the first time can hold a relation,
|
|
59
|
+
and bring a `stale-premise` or a `ghost-handover` with it, and a relation read
|
|
60
|
+
out of code can take an `unreciprocated-supersession` away with it. A
|
|
61
|
+
paragraph indented four columns past its list item's text after a blank line
|
|
62
|
+
is code now, as CommonMark reads it, and as GitHub renders it: eleven of this
|
|
63
|
+
repository's ADRs had answers written that way, and they are re-indented as
|
|
64
|
+
paragraphs of their items. The glob, `archived` and front-matter
|
|
65
|
+
changes are narrower, and each is described below; a pattern the dialect
|
|
66
|
+
refuses stops the run with exit `2` and says how to write it. Under
|
|
67
|
+
`--ratchet`, expect to record the baseline once; "What a baseline sees", under
|
|
68
|
+
Changed, lists the entries that go stale.
|
|
69
|
+
|
|
70
|
+
### Added
|
|
71
|
+
|
|
72
|
+
**`--format gitlab`**, the Code Quality report a GitLab merge request reads,
|
|
73
|
+
so the family is not GitHub's alone. `check` only, like SARIF. One issue per
|
|
74
|
+
finding: the rule as `check_name`, message and hint as `description`, the file
|
|
75
|
+
and line as `location`, and a `fingerprint` that is a SHA-256 of the rule,
|
|
76
|
+
the specification and what within it - the identity a baseline counts by. No
|
|
77
|
+
line, so moving a paragraph does not make a finding new, and no message, whose
|
|
78
|
+
counts move when one of three boxes is ticked; a second finding identical in
|
|
79
|
+
all three is told apart by its order.
|
|
80
|
+
`error` is `critical`, or `major` when only `--strict` made it an error;
|
|
81
|
+
`warn` is `minor` and `info` is `info`. The README has the job to add. See
|
|
82
|
+
[ADR-0015](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0015-feedback-goes-where-the-tools-already-look.md).
|
|
83
|
+
|
|
84
|
+
### Breaking (library API)
|
|
85
|
+
|
|
86
|
+
The command line changes only as the sections below describe. A program that
|
|
87
|
+
imports spec-graph sees these as well:
|
|
88
|
+
|
|
89
|
+
- **`ScannedDocument.masked` is gone.** `ScannedDocument` is spec-core's
|
|
90
|
+
`MarkdownScan`, and the masked copy is `masks.structure`, beside
|
|
91
|
+
`masks.prose` and `masks.directives`.
|
|
92
|
+
- **`ScannedDocument.lines` holds the front matter's lines**, flagged
|
|
93
|
+
`frontMatter`, where it began at the body. Code that numbers or reads body
|
|
94
|
+
lines from it skips those.
|
|
95
|
+
- **`ScannedDocument.links` holds images**, flagged `Link.image`. Code that
|
|
96
|
+
reads it for citations filters them out, as the analysis does but for a wiki
|
|
97
|
+
embed.
|
|
98
|
+
- **Required fields are new**, so an object built by hand needs them:
|
|
99
|
+
`ScannedLine` has `frontMatter`, `html` and `comment`; `FrontMatter` has
|
|
100
|
+
`kind` and `closeLine`; `Link` has `image` and `targetEnd`; `Heading` has
|
|
101
|
+
`form`, `anchor`, `textStart`, `textEnd` and `endLine`; `ListItem` has
|
|
102
|
+
`endLine` and `quoteDepth`; `HtmlComment` has `closed`; `DocumentNode` has
|
|
103
|
+
`history`.
|
|
104
|
+
- **An error from `compilePattern` is named `RegexError`.** `PatternError` is
|
|
105
|
+
the same class, so `instanceof` holds; a check of `error.name` against
|
|
106
|
+
`'PatternError'` does not.
|
|
107
|
+
- **`createReferenceFilter` throws on a blank pattern**, which it used to drop,
|
|
108
|
+
and `compileGlob`, `createGlobMatcher` and `walkFiles` throw on every
|
|
109
|
+
pattern the dialect refuses.
|
|
110
|
+
|
|
111
|
+
`ParseProblem` has `unread`, and it is optional.
|
|
112
|
+
|
|
113
|
+
### Changed
|
|
114
|
+
|
|
115
|
+
**The matcher behind `~=` is spec-core's.** It moved, unchanged, to spec-core -
|
|
116
|
+
the library the spec-* tools share - and is copied back into
|
|
117
|
+
`src/vendor/spec-core/`, byte for byte and checked against the SHA-256 it was
|
|
118
|
+
copied with, so spec-graph still installs nothing. The package carries the
|
|
119
|
+
copies compiled, and spec-core's MIT notice with them, as
|
|
120
|
+
`src/vendor/spec-core/LICENSE`. A selector reads exactly as
|
|
121
|
+
before. `compilePattern` and `PatternError` are still exported and are the same
|
|
122
|
+
function and class; a caught error's `name` is now `RegexError`. The tests that
|
|
123
|
+
hold the matcher to `RegExp` moved with it, and the copy is left out of this
|
|
124
|
+
repository's mutation sweep and coverage, which spec-core's measure instead.
|
|
125
|
+
See [ADR-0017](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0017-a-predicate-must-finish.md).
|
|
126
|
+
|
|
127
|
+
**Globs are the dialect every spec-* tool reads.** The patterns to check,
|
|
128
|
+
`--ignore`, `--history` and `historyPatterns` are compiled by spec-core's glob
|
|
129
|
+
engine, in the `path` dialect spec-brief and spec-guard read too, so a scope
|
|
130
|
+
means the same thing to each of them. Where that reading differs from
|
|
131
|
+
spec-graph's old one, a repository will see it:
|
|
132
|
+
|
|
133
|
+
- **Case is respected on every host.** `Docs/**` matched `docs/a.md` on Windows
|
|
134
|
+
and nowhere else, so one repository gave one answer on a Windows checkout and
|
|
135
|
+
another in CI. And a pattern with no glob syntax was compared lower-cased on
|
|
136
|
+
every host, Linux included: `README.md` also took `readme.md`. Neither folds
|
|
137
|
+
now, and `compileGlob`'s `ignoreCase` is off unless asked for on any host.
|
|
138
|
+
- **`**` inside a name is refused.** `docs/**.md`, `**.ts` and `a**b` crossed
|
|
139
|
+
directories wherever the `**` was written. `**` means any number of
|
|
140
|
+
directories only as a whole segment now, and the error says so: write
|
|
141
|
+
`docs/**/*.md` for any depth, as it always read, or `*.md` for one level.
|
|
142
|
+
- **An extended glob is refused.** `+(a|b)` was the literal text `+(a|b)`, a
|
|
143
|
+
scope that matched nothing; the error says to write `{a,b}`, and `[(]` for a
|
|
144
|
+
parenthesis. A group is an extended glob only when it holds a `|`, so
|
|
145
|
+
`C++(notes).md` and `books/*(2017).md` are names with parentheses in them,
|
|
146
|
+
as they were.
|
|
147
|
+
- **An unclosed `[` is an error**, like an unclosed `{` always was. It was a
|
|
148
|
+
literal `[`, which made the pattern a scope that matched nothing. The run
|
|
149
|
+
stops with exit `2` and names the pattern, from the command line or from the
|
|
150
|
+
configuration file.
|
|
151
|
+
- **A trailing `/` means the directory's contents.** It was normalised away, so
|
|
152
|
+
`drafts*/` named a file called `drafts`, and `docs/` took `docs` itself.
|
|
153
|
+
- **Braces expand to literals.** `{docs,specs}` was a glob matching two names
|
|
154
|
+
exactly; it is two literals now, each a directory and what it holds.
|
|
155
|
+
- **A class never matches `/`**, and **`[^a]` negates**, as `[!a]` does. `a[!b]c`
|
|
156
|
+
took `a/c`, and `[^a]` was the class of `^` and `a`.
|
|
157
|
+
- **A pattern must name a path under the root.** `.` and `./` are refused
|
|
158
|
+
rather than read as nothing, and so is a `..` anywhere in a pattern:
|
|
159
|
+
`docs/../specs` was resolved to `specs`, and `../other/**` walked outside
|
|
160
|
+
the root. A `.` segment inside a pattern is dropped, as it was. A `..` typed
|
|
161
|
+
below the root is resolved against where it was typed, so
|
|
162
|
+
`spec-graph "../*.md"` in `docs/deep` still means `docs/*.md`.
|
|
163
|
+
- **An empty pattern is refused**, in every list: the patterns to check,
|
|
164
|
+
`--ignore`, `--history`, `--ignore-ref` and their keys in the configuration
|
|
165
|
+
file. Each was read as nothing, or dropped - an unset variable in
|
|
166
|
+
`--history "$LOGS"` checked the logs as specifications, and nothing said
|
|
167
|
+
why. A pattern of spaces is empty to `--ignore-ref`, which trims what it
|
|
168
|
+
reads, and a name to the others.
|
|
169
|
+
- **The walk finds a directory only as it is spelled on disk.** It starts at a
|
|
170
|
+
pattern's literal prefix, and on a filesystem that ignores case `Docs/` found
|
|
171
|
+
`docs/` and reported its files as `Docs/...`. A pattern rooted at `/` is not
|
|
172
|
+
walked under the root either, where it reported paths like `/docs/a.md`.
|
|
173
|
+
|
|
174
|
+
`--ignore-ref` runs on the same engine and keeps its own reading, since a
|
|
175
|
+
reference target is not a path: a bare pattern matches one target exactly, case
|
|
176
|
+
is ignored on every host, `.` and `..` are the text of the link, and a `\`
|
|
177
|
+
escapes the next character rather than being matched as itself. The glob
|
|
178
|
+
changes above apply to it otherwise, and three more come with the syntax: a `\`
|
|
179
|
+
before a letter or digit, or at the end, is refused, as is a leading `!` - both
|
|
180
|
+
were literals, and `--ignore-ref` has no list to take a pattern back out of -
|
|
181
|
+
and `a//b` reads as `a/b`.
|
|
182
|
+
|
|
183
|
+
`globToRegExp` is deprecated, and stays as the old reading that the test of
|
|
184
|
+
every difference above runs against; it no longer folds case on Windows. See
|
|
185
|
+
[ADR-0022](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0022-globs-are-the-family-path-dialect.md).
|
|
186
|
+
|
|
187
|
+
**Documents are read by spec-core's scanner.** It moved to spec-core, built on
|
|
188
|
+
this repository's scanner as its model, and is copied back into
|
|
189
|
+
`src/vendor/spec-core/` and checked by hash, so spec-graph still installs
|
|
190
|
+
nothing. It follows CommonMark wherever CommonMark decides what is code or a
|
|
191
|
+
comment, and where that reads a document differently from before, spec-graph
|
|
192
|
+
follows it. Over this repository, its test corpora and spec-core's documents,
|
|
193
|
+
the graph and the findings are what they were. A repository sees a difference
|
|
194
|
+
where it wrote one of these:
|
|
195
|
+
|
|
196
|
+
- **A code span ends with its paragraph.** A lone backtick hid everything up to
|
|
197
|
+
the next run of its length, however many paragraphs on, citations included.
|
|
198
|
+
- **A heading reads as a renderer shows it.** A comment on its line is not part
|
|
199
|
+
of its text, and `# C#` is about `C#`: a closing run of `#` needs a space
|
|
200
|
+
before it. That text is a document's title, a section's name and the slug in
|
|
201
|
+
the id of every item under it, so an item under `## Notes <!-- x -->` moves
|
|
202
|
+
from `ADR-0001#notes----x---.1` to `ADR-0001#notes.1`, and
|
|
203
|
+
`## Open Questions <!-- short -->` holds obligations at last. A baseline does
|
|
204
|
+
not notice the move: an entry names the specification and what within it,
|
|
205
|
+
never an item.
|
|
206
|
+
- **A link to GitHub's anchor for a repeated heading resolves.** GitHub renders
|
|
207
|
+
the second `## Notes` as `#notes-1`, and a link to it was a
|
|
208
|
+
`broken-reference`. The slug still names the first heading, and `#notes-2`
|
|
209
|
+
beside two headings is still broken.
|
|
210
|
+
- **Nothing inside `<pre>`, `<script>`, `<style>` or `<textarea>` is
|
|
211
|
+
structure.** Their links were masked already; now no heading, list item, table
|
|
212
|
+
or `Status:` line is read from one either, so `- [ ] example` in a `<pre>`
|
|
213
|
+
block is not an open obligation, and a status section that opens with one
|
|
214
|
+
declares no status. A `@spec-item` above one does not reach an item below it,
|
|
215
|
+
as it never reached across a fence.
|
|
216
|
+
- **Nothing inside a comment opens a block.** A fence inside a comment opened
|
|
217
|
+
one, and with no closer everything after it was code; a list marker inside one
|
|
218
|
+
decided whether an indented block after it was code. Neither does now. A
|
|
219
|
+
comment that opens a line and never closes runs to the end of the document, as
|
|
220
|
+
it renders, and a parse problem says where it opened; no directive is read from
|
|
221
|
+
it, so a stray `<!-- @spec-ignore` does not drop the file.
|
|
222
|
+
- **Headings, rules and list items as CommonMark reads them.** A setext underline
|
|
223
|
+
is not used twice - `Title`, `===`, `---` is one heading and a rule, not a
|
|
224
|
+
second heading called `===` - and does not underline a line in a block quote.
|
|
225
|
+
`* * *` is a rule, not a list item. A list item ends at a fence or a block
|
|
226
|
+
quote no deeper than its marker, so a relation written after an unindented
|
|
227
|
+
fence is the document's and not the item's. And a heading closes every list,
|
|
228
|
+
so an item indented under a list a heading closed is at depth 0, and an
|
|
229
|
+
obligation when its section holds them.
|
|
230
|
+
- **Links as CommonMark reads them.** `[a](b c)` is text, not a link to `b`.
|
|
231
|
+
`[foo](not a link)` is the shortcut `[foo]` when `foo` is defined, not a link
|
|
232
|
+
to `not`. A footnote `[^1]: text` and a line `[Note]: prose` are not
|
|
233
|
+
definitions, so `[^1]` and `[Note]` are no longer links to the first word
|
|
234
|
+
after them, which were broken references. A link inside brackets that are not
|
|
235
|
+
one, `[see [ADR-7](0007.md) here]`, is read. Labels match with case and
|
|
236
|
+
whitespace folded, so `[Two Words][]` finds `[TWO WORDS]:`. A finding on
|
|
237
|
+
`[a](<b c.md>)` points inside the angle brackets, a column later than it did.
|
|
238
|
+
- **A table needs a delimiter row with as many cells as its header.** One
|
|
239
|
+
without was read as a table, and as a register when its columns said so.
|
|
240
|
+
- **A fence ends with its block quote.** One opened in a quote and never closed
|
|
241
|
+
made the rest of the document code.
|
|
242
|
+
- **Indented code is four columns past its container**: the margin, or the text
|
|
243
|
+
of the list item the line is in. Inside a list four columns were never code,
|
|
244
|
+
so a link or a checkbox in an example indented under an item was read as one.
|
|
245
|
+
Under `- item`, six columns after a blank line are code now, and four are
|
|
246
|
+
still the item's text. A fence line that deep opens no fence - after a blank
|
|
247
|
+
line it is indented code, and under a paragraph it is text - where it used to
|
|
248
|
+
open one at any depth and, unclosed, run to the end of the document.
|
|
249
|
+
- **Front matter opens on exactly `---` or `+++`, and closes on exactly
|
|
250
|
+
`---`, `...` or `+++`.** `----` is a rule. And `----` or `....` under an
|
|
251
|
+
opening `---` closed the block, and now leaves it open: a block that never
|
|
252
|
+
closes is read as a rule and Markdown, none of its keys are read, and a parse
|
|
253
|
+
problem says where it opened.
|
|
254
|
+
|
|
255
|
+
**What a baseline sees.** A finding the scan no longer produces leaves its
|
|
256
|
+
entry no longer occurring, which fails a run under `--ratchet`. These go: the
|
|
257
|
+
first word of a footnote `[^1]: See ...` or a line `[Note]: prose`, which was
|
|
258
|
+
a broken reference; the `b` of `[a](b c)` and the `not` of
|
|
259
|
+
`[foo](not a link)`; a link to GitHub's `#notes-1`, which was an unknown
|
|
260
|
+
anchor; an `orphaned-obligation` made of boxes held in `<pre>` or in a
|
|
261
|
+
comment; a link inside a code span that a lone backtick earlier in the document
|
|
262
|
+
had knocked out of step, so that it read as text; and a link in an example
|
|
263
|
+
indented under a list item. One `--record-baseline` settles them. What the scan
|
|
264
|
+
sees now and did not - a citation a lone backtick hid, an obligation under a
|
|
265
|
+
heading with a comment on its line, what followed a fence indented under a
|
|
266
|
+
paragraph, the shortcut `[foo]` - is a new finding, as any other is.
|
|
267
|
+
|
|
268
|
+
For the library API, the scanner's types are spec-core's, exported under the
|
|
269
|
+
names they had, and what that breaks is listed under
|
|
270
|
+
[Breaking (library API)](#breaking-library-api). Beside it, `blocks`,
|
|
271
|
+
`codeSpans` and `bom` are new on `ScannedDocument`, and
|
|
272
|
+
`isMasked(offset, mask?)` asks any of its three masks. The analysis leaves
|
|
273
|
+
images out but for wiki embeds. `parseDirectives` skips a comment whose
|
|
274
|
+
`closed` is `false`. `createLineIndex` is spec-core's, the same table. See
|
|
275
|
+
[ADR-0023](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0023-the-scanner-is-the-familys.md).
|
|
276
|
+
|
|
277
|
+
**Front matter is read by spec-core's reader, and what it does not read says
|
|
278
|
+
why.** Keys are compared in lower case and one level of nesting is read as
|
|
279
|
+
`parent.child`, as before. Where the reader and YAML part from the old one:
|
|
280
|
+
|
|
281
|
+
- **A value YAML does not say is not read.** A plain value holding `: ` -
|
|
282
|
+
`title: ADR-7: Sharding`, which YAML reads as an error - a value continued onto
|
|
283
|
+
the next line, which was read as its first line, a block scalar, an anchor and
|
|
284
|
+
a tag are left out rather than guessed at. Quote the value and it is read. An
|
|
285
|
+
inline list on the line under its key, `translators:` over an indented `[]`,
|
|
286
|
+
is left out too, with the advice to write it after the colon, since quoting it
|
|
287
|
+
would make it a string. Each is a parse problem at the value, under
|
|
288
|
+
`--verbose` and in `--format json`, naming the reason; so are a line that is
|
|
289
|
+
not `key: value`, a key written twice, of which the last still wins, and TOML
|
|
290
|
+
front matter, which was read as nothing in silence. A status left out this way
|
|
291
|
+
is looked for in a `## Status` section, as a missing one always was.
|
|
292
|
+
- **What the graph lost is counted without `--verbose`.** A status, an id, an
|
|
293
|
+
alias or a relation left out - or a block never closed, or a line that belongs
|
|
294
|
+
to no key - can turn a failing check into a passing one:
|
|
295
|
+
`status: Superseded by ADR-3: see notes` reads as unknown, and the
|
|
296
|
+
supersession finding 0.8.0 reported is gone. So a run without `--verbose` prints one
|
|
297
|
+
line above its verdict, `! 2 front-matter values not read - see --verbose`, in
|
|
298
|
+
the terminal and in `--format markdown`. It is not a finding and does not
|
|
299
|
+
change the exit code. A title or a description left out is not counted.
|
|
300
|
+
`ParseProblem` says which problems count, as `unread`.
|
|
301
|
+
- **A key indented under nothing is not read.** `status: accepted` indented on
|
|
302
|
+
the first line of front matter is valid YAML, and 0.8.0 read it. It is a line
|
|
303
|
+
that belongs to no key now, so the document reads as `unknown`, and the count
|
|
304
|
+
of values not read includes it. Write the key at the margin.
|
|
305
|
+
- **A list written at its key's own indentation is a list.** `deps:` over
|
|
306
|
+
`- ADR-1` was an empty value.
|
|
307
|
+
- **Quoted values are YAML's.** `'it''s'` is `it's`, and `"a\tb"` holds a tab.
|
|
308
|
+
|
|
309
|
+
`parseFrontMatter` keeps its signature and reads with spec-core's reader, so it
|
|
310
|
+
leaves out what the reader does not read. See
|
|
311
|
+
[ADR-0023](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0023-the-scanner-is-the-familys.md).
|
|
312
|
+
|
|
313
|
+
**`archived` is a record, not a retired decision.** spec-brief closes a round
|
|
314
|
+
of work by writing `status: archived` and moving the brief to an archive
|
|
315
|
+
directory, and every spec-* tool reads that word as a finished round which it
|
|
316
|
+
is normal to depend on. spec-graph read it as retired: a live brief that
|
|
317
|
+
depended on an archived one was reported as a `stale-premise`, and an archived
|
|
318
|
+
brief with a task left unticked as an `orphaned-obligation`. It is the `record`
|
|
319
|
+
phase now, as a file declared by `historyPatterns` is - its links are still
|
|
320
|
+
checked, its unticked boxes are nobody's work and leave the open count, and
|
|
321
|
+
live work handed to it is still a `ghost-handover`, which says it is archived.
|
|
322
|
+
So is the status word `archive`.
|
|
323
|
+
|
|
324
|
+
It is a closed round and not a log, so that is all that changes. The claims an
|
|
325
|
+
archived document makes are still checked as they were when it read as
|
|
326
|
+
retired: a supersession it declares (`live-supersession` on what it
|
|
327
|
+
supersedes), a cycle it closes (`circular-delegation`) and a link to itself
|
|
328
|
+
(`self-reference`). What it hands on and what it rests on are still not held
|
|
329
|
+
against it. An archived document that something supersedes and that never
|
|
330
|
+
says so is an `unreciprocated-supersession`, whose hint is now to make its
|
|
331
|
+
status `archived, superseded by X` - which retires it, so what depends on it
|
|
332
|
+
is a `stale-premise` again. A document declared by `historyPatterns` or
|
|
333
|
+
`<!-- @spec-history -->` is exempt from all of it, as before; `DocumentNode`
|
|
334
|
+
says which kind of record a document is, as `history`.
|
|
335
|
+
|
|
336
|
+
A document still retires by saying `superseded`, `deprecated` or `retired`,
|
|
337
|
+
and `archived, superseded by B-7` is retired, since a retirement word wins
|
|
338
|
+
wherever it is written. A document under an `archive/` directory that declares
|
|
339
|
+
no status is retired as before. A repository that wrote `archived` for a
|
|
340
|
+
retired decision loses the `stale-premise` findings on documents that depend
|
|
341
|
+
on it, and the `orphaned-obligation` findings on its open items, and a baseline
|
|
342
|
+
that accepted one reports that entry as no longer occurring, which fails a run
|
|
343
|
+
under `--ratchet`. See
|
|
344
|
+
[ADR-0011](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0011-a-record-is-not-a-specification.md).
|
|
345
|
+
|
|
346
|
+
### Fixed
|
|
347
|
+
|
|
348
|
+
**A code span that mentions a comment is code.** ``Use `<!--` to open one``
|
|
349
|
+
opened an HTML comment at the `<!--`, and it ran to the next `-->` anywhere in
|
|
350
|
+
the document: every heading, citation and link in between went into it, and a
|
|
351
|
+
link to a file that does not exist went unreported. Comments were found first
|
|
352
|
+
and code spans after, so the span never had a say. Both are now found in one
|
|
353
|
+
pass, left to right, and whichever opens first wins, which is how CommonMark
|
|
354
|
+
reads them: a `<!--` inside a span is text, and so is a backtick inside a
|
|
355
|
+
comment. A span still closes only on a run of its own length, and an escaped
|
|
356
|
+
backtick still opens none.
|
|
357
|
+
|
|
358
|
+
The same defect read a directive quoted in inline code as a directive. This
|
|
359
|
+
repository's README and ADR-0011 both write `` `<!-- @spec-history -->` `` in a
|
|
360
|
+
sentence, and both were being checked as historical records. They are a
|
|
361
|
+
document and an accepted decision again, and `selfcheck` counts one more open
|
|
362
|
+
obligation than it did, because ADR-0011's open question is no longer exempt. A document quoting `<!-- @spec-ignore -->` that way was skipped whole,
|
|
363
|
+
and is checked now.
|
|
364
|
+
|
|
365
|
+
**Unclosed backtick runs cost the document's length once, not once each.** Each
|
|
366
|
+
searched the rest of the document for its closer, so a line of runs of different
|
|
367
|
+
lengths made the scan grow as the length to the power 1.5: 2 MB took fifteen
|
|
368
|
+
seconds. The first search that fails now keeps what it saw, and the same 2 MB
|
|
369
|
+
takes about sixty milliseconds.
|
|
370
|
+
|
|
371
|
+
**What a comment holds is not structure.** Headings, list items and tables are
|
|
372
|
+
read from lines, and none of them asked whether the line was inside a comment.
|
|
373
|
+
`## Hidden` in `<!-- -->` was a heading and started a section, a checklist
|
|
374
|
+
commented out was a list of open obligations nobody could see, and
|
|
375
|
+
`<!-- note -->` over `---` was a heading called "<!-- note -->". A line whose
|
|
376
|
+
first character is inside a comment is now none of these, and cannot end a list
|
|
377
|
+
item either; `ScannedLine` says so as `comment`. Directives are read out of
|
|
378
|
+
comments exactly as before.
|
|
379
|
+
|
|
380
|
+
Nor is a status read out of one. Under `## Status`, a template's
|
|
381
|
+
`<!-- proposed | accepted -->` was taken as the status - which no vocabulary
|
|
382
|
+
knows, so the phase was `unknown` with `Accepted` on the next line - and a
|
|
383
|
+
commented-out `Status: proposed` gave a register's section the second signal it
|
|
384
|
+
needs to become a specification.
|
|
385
|
+
|
|
386
|
+
An obligation that was only ever inside a comment is gone on upgrade, with any
|
|
387
|
+
finding about it, so a baseline that accepted one reports that entry as no
|
|
388
|
+
longer occurring under `--ratchet`. An item under a heading that was only inside
|
|
389
|
+
a comment is numbered under the heading above it instead.
|
|
390
|
+
|
|
391
|
+
### Verified
|
|
392
|
+
|
|
393
|
+
`npm run lint`, 987 tests, `npm run build` and `npm run selfcheck`. Fifteen of
|
|
394
|
+
the 25 new tests fail against the unfixed source; the other ten hold the one pass
|
|
395
|
+
to what the two it replaced already got right - fences, escapes, runs that never
|
|
396
|
+
close, a `<` that is not `<!--`. Measured on their own with
|
|
397
|
+
`--coverageAnalysis all`, before and after: `markdown.ts` went from 69.30% to
|
|
398
|
+
72.97%, the status readers in `sections.ts` from 52.63% to 59.49%, and
|
|
399
|
+
`statusSectionBody` in `extract.ts` from 60.00% to 73.08%. The mutants left alive
|
|
400
|
+
on the new lines change how long an answer takes, or compare offsets that cannot
|
|
401
|
+
be equal. 600,000 generated documents read the same through the one pass as
|
|
402
|
+
through a naive left-to-right reading of the same rule, and this repository's
|
|
403
|
+
documents scan no slower than before.
|
|
404
|
+
|
|
405
|
+
Then spec-core, the record phase and GitLab: `npm run lint`, 1,010 tests,
|
|
406
|
+
`npm run build` and `npm run selfcheck`. The 30 tests of `tests/regex.test.ts`
|
|
407
|
+
went to spec-core with the matcher, where they run with only its names
|
|
408
|
+
changed. Every glob change listed above has a test that fails against the
|
|
409
|
+
0.8.0 matcher - the host-dependent ones on Windows, where the defect was - and
|
|
410
|
+
the differential in `tests/glob.test.ts` requires each of them to occur and
|
|
411
|
+
nothing else to; five of the eight tests for `archived` fail without its table
|
|
412
|
+
entry, and the other three hold what must not move. Measured on their own with
|
|
413
|
+
`--coverageAnalysis all`, before and after: `glob.ts` from 73.74% to 77.22%,
|
|
414
|
+
`cli.ts` from 81.11% to 83.45%, `report.ts` from 69.03% to 70.17% and
|
|
415
|
+
`lifecycle.ts` from 53.10% to 53.26%. `select.ts`, whose only change is an
|
|
416
|
+
import, read 74.01% and then 71.08%: sixteen selector-parsing mutants that no
|
|
417
|
+
assertion kills in either run timed out in the first and survived in the
|
|
418
|
+
second. Of the mutants left alive on new lines, seven are equivalent and say
|
|
419
|
+
so where they are; the rest are on the ignore filter, whose reading did not
|
|
420
|
+
change, and on the symlink branch of the walk, which no test reaches, as
|
|
421
|
+
before.
|
|
422
|
+
|
|
423
|
+
Then spec-core's scanner and front-matter reader: `npm run lint`, 1,041 tests,
|
|
424
|
+
`npm run build` and `npm run selfcheck`. Of the 27 new tests, 23 fail against
|
|
425
|
+
the source before the move; the other four hold what must not move - an embed's
|
|
426
|
+
edge, the last of a key written twice, no directive from a comment that never
|
|
427
|
+
closes, and no suffix for a heading that is not repeated. The binaries before
|
|
428
|
+
and after read this repository, its seven fixture corpora and spec-core's
|
|
429
|
+
documents into identical graph exports and identical findings. Over a corpus
|
|
430
|
+
written to hit each difference above, every difference in their output was one
|
|
431
|
+
of them. The scanner's own mutants, 72% to 77% here, are spec-core's sweep's
|
|
432
|
+
now, at 98% there; what the move left here is measured by CI's sweep.
|
|
433
|
+
|
|
434
|
+
Then the review of those rounds: `npm run lint`, 1,053 tests, `npm run build`
|
|
435
|
+
and `npm run selfcheck`, with spec-core copied again at cbe2223. Every new test
|
|
436
|
+
fails against the source the review read but one, which holds what an archived
|
|
437
|
+
document is still exempt from. They cover spec-core's licence in the package,
|
|
438
|
+
`**` inside a name and an extended glob, code past a list item's text, an empty
|
|
439
|
+
`--ignore` and `--ignore-ref`, what an archived document still answers for, the
|
|
440
|
+
count of front-matter values not read, front matter that never closes, and a
|
|
441
|
+
GitLab fingerprint across a ticked box. A baseline recorded by 0.8.0 over a
|
|
442
|
+
corpus holding each scanner difference, run under `--ratchet`, accepted the
|
|
443
|
+
finding on a moved item and went stale only on findings the scan no longer
|
|
444
|
+
produces. Against 0.8.0 over the review's corpora for `archived`, the difference
|
|
445
|
+
is the stale premise and the orphaned obligation the change is for. Over the
|
|
446
|
+
large repository above, this branch and the one reviewed report identical
|
|
447
|
+
findings. spec-core's documents and the seven fixture corpora read into the same
|
|
448
|
+
graph export as before the copy; this repository's lost the seven relations
|
|
449
|
+
above.
|
|
450
|
+
|
|
6
451
|
## 0.8.0
|
|
7
452
|
|
|
8
453
|
A register row took its identifier from the first thing its *title* said, not
|
|
@@ -107,7 +552,7 @@ the file - `--verbose` now says when it read nothing. Unreadable, as opposed to
|
|
|
107
552
|
absent, is an error wherever the path was written. A baseline that cannot be
|
|
108
553
|
*parsed* is still reported and ignored: it only ever suppresses, so a row that
|
|
109
554
|
is dropped is a finding reported. See
|
|
110
|
-
[ADR-0012](docs/adr/0012-a-baseline-is-a-ratchet.md).
|
|
555
|
+
[ADR-0012](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0012-a-baseline-is-a-ratchet.md).
|
|
111
556
|
|
|
112
557
|
### Fixed
|
|
113
558
|
|
|
@@ -117,7 +562,7 @@ selector under `query`, went to stdout above the report. With `--format json`
|
|
|
117
562
|
that made the output unparseable; with `--format sarif` it made a file the
|
|
118
563
|
code-scanning uploader rejects over a schema rather than over the command that
|
|
119
564
|
was run. Both now go to stderr, with everything else a run says about itself.
|
|
120
|
-
[ADR-0015](docs/adr/0015-feedback-goes-where-the-tools-already-look.md) already
|
|
565
|
+
[ADR-0015](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0015-feedback-goes-where-the-tools-already-look.md) already
|
|
121
566
|
had the rule - rows "cannot go on stdout beside a JSON document without
|
|
122
567
|
breaking the parse" - and these two lines were the places that did not follow
|
|
123
568
|
it.
|
|
@@ -179,7 +624,7 @@ matched against targets read out of documents, which nothing limits the length
|
|
|
179
624
|
of. Every glob - the patterns to check, `--ignore`, `--ignore-ref`, `--history` -
|
|
180
625
|
now runs on the same automaton as `~=`, verified against the `RegExp` it
|
|
181
626
|
replaces on every glob and path in a differential corpus. See
|
|
182
|
-
[ADR-0017](docs/adr/0017-a-predicate-must-finish.md).
|
|
627
|
+
[ADR-0017](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0017-a-predicate-must-finish.md).
|
|
183
628
|
|
|
184
629
|
- **An invalid glob names itself.** `docs/{a` used to report
|
|
185
630
|
`Invalid regular expression: /^docs\/(?:a$/i: Unterminated group`, about a
|
|
@@ -210,7 +655,7 @@ report a closed question as reopened when nobody touched it. An obligation is
|
|
|
210
655
|
paired only by a declared id, or by its document, section and title when nothing
|
|
211
656
|
else shares them; anything unpaired is reported as having appeared or
|
|
212
657
|
disappeared. Human, `--format json` or `--format markdown`, and exit 0 either
|
|
213
|
-
way. See [ADR-0020](docs/adr/0020-a-diff-names-what-it-can-tell-apart.md).
|
|
658
|
+
way. See [ADR-0020](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0020-a-diff-names-what-it-can-tell-apart.md).
|
|
214
659
|
|
|
215
660
|
- The JSON graph export names its `generator`, so a diff can warn when two
|
|
216
661
|
exports came from different versions, and each item says whether its id was
|
|
@@ -244,8 +689,8 @@ kills no assertion made: tests writing to fixed paths deleted each other's files
|
|
|
244
689
|
under Stryker's parallel workers. Race-free, the sweep read 73.42% before
|
|
245
690
|
`spec-graph diff` and 75.25% with this release: `diff.ts` at 98.35%, and
|
|
246
691
|
`directives.ts` from 66.88% to 78.01%. Lose every timeout and it reads 71.89%.
|
|
247
|
-
See [ADR-0007](docs/adr/0007-mutation-testing.md) and
|
|
248
|
-
[ADR-0019](docs/adr/0019-the-sweep-runs-in-shards.md).
|
|
692
|
+
See [ADR-0007](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0007-mutation-testing.md) and
|
|
693
|
+
[ADR-0019](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0019-the-sweep-runs-in-shards.md).
|
|
249
694
|
|
|
250
695
|
The sweep after the directive fix moved `extract.ts` down 0.18 points, among the
|
|
251
696
|
usual movement in files nobody touched, and this one was real. Four mutants
|
|
@@ -282,7 +727,7 @@ A region now carries its file's front matter minus two kinds of key. A
|
|
|
282
727
|
on behalf of the register, not of each decision in it. So does a key the region
|
|
283
728
|
**answers for itself** — its identifier, status, title and aliases, which are
|
|
284
729
|
precisely the things a register exists to vary row by row.
|
|
285
|
-
[ADR-0009](docs/adr/0009-a-specification-is-a-region.md) carried this as a
|
|
730
|
+
[ADR-0009](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0009-a-specification-is-a-region.md) carried this as a
|
|
286
731
|
narrowed open question and called it a gap. It was a defect, and it was found by
|
|
287
732
|
pointing the binary at a register rather than by reading the code.
|
|
288
733
|
|
|
@@ -295,7 +740,7 @@ that keeps registers and writes rules about front matter.
|
|
|
295
740
|
### Added
|
|
296
741
|
|
|
297
742
|
**`~=` is matched by an automaton that cannot backtrack.**
|
|
298
|
-
[ADR-0016](docs/adr/0016-a-query-needs-a-sentence.md) documented this hazard
|
|
743
|
+
[ADR-0016](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0016-a-query-needs-a-sentence.md) documented this hazard
|
|
299
744
|
with `(a+)+$`, which nobody writes, and priced the fix at "worth it only if a
|
|
300
745
|
real repository hangs". Both were wrong. `^([A-Za-z0-9_]+[ ]?)+$` is what
|
|
301
746
|
somebody writes to check that a title is words separated by single spaces:
|
|
@@ -326,8 +771,8 @@ over, on one clause of the language specification read backwards in two
|
|
|
326
771
|
different places - the word characters `\b` recognises, and whether a character
|
|
327
772
|
whose upper case is ASCII may match `[A-Z]`. The second was found by the
|
|
328
773
|
mutation score pointing at a corpus with a blind spot in it rather than at a
|
|
329
|
-
test. See [ADR-0017](docs/adr/0017-a-predicate-must-finish.md) and
|
|
330
|
-
[ADR-0007](docs/adr/0007-mutation-testing.md).
|
|
774
|
+
test. See [ADR-0017](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0017-a-predicate-must-finish.md) and
|
|
775
|
+
[ADR-0007](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0007-mutation-testing.md).
|
|
331
776
|
|
|
332
777
|
**Configuration is discovered upward, and the file holding it is the root.**
|
|
333
778
|
|
|
@@ -337,7 +782,7 @@ cd packages/auth && spec-graph check # the repository's rules, the
|
|
|
337
782
|
# repository's paths
|
|
338
783
|
```
|
|
339
784
|
|
|
340
|
-
[ADR-0010](docs/adr/0010-configuration-belongs-to-the-repository.md) worried
|
|
785
|
+
[ADR-0010](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0010-configuration-belongs-to-the-repository.md) worried
|
|
341
786
|
that discovery would make a run depend on where it started. Reading the working
|
|
342
787
|
directory already did, and silently: a check from a package directory found no
|
|
343
788
|
configuration, ran no project rules, used the default include patterns, and
|
|
@@ -348,7 +793,7 @@ to a run from the top. The walk stops at the repository — a directory holding
|
|
|
348
793
|
`.git` — so a stray file in a home directory cannot reach it. `--root` names the
|
|
349
794
|
root yourself and turns discovery off, and a path typed on the command line
|
|
350
795
|
stays relative to where you typed it. See
|
|
351
|
-
[ADR-0018](docs/adr/0018-the-configuration-file-is-the-root.md).
|
|
796
|
+
[ADR-0018](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0018-the-configuration-file-is-the-root.md).
|
|
352
797
|
|
|
353
798
|
**`spec-graph query project:<rule>` runs a registered rule by name.** The rule
|
|
354
799
|
is already compiled by the time the command runs, and the alternative was
|
|
@@ -453,7 +898,7 @@ re-litigated: a **relational diff** between two states of the graph, taken
|
|
|
453
898
|
between two `--graph-format json` exports rather than between two git revisions,
|
|
454
899
|
because revisions mean spawning a binary underneath a pipeline that is a pure
|
|
455
900
|
function of text. See
|
|
456
|
-
[ADR-0015](docs/adr/0015-feedback-goes-where-the-tools-already-look.md).
|
|
901
|
+
[ADR-0015](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0015-feedback-goes-where-the-tools-already-look.md).
|
|
457
902
|
|
|
458
903
|
### Verified
|
|
459
904
|
|
|
@@ -485,7 +930,7 @@ mostly the older formatters.
|
|
|
485
930
|
Between those two runs `rules.ts` moved from 79.42% to 76.02% and
|
|
486
931
|
`directives.ts` from 77.92% to 74.03%, with neither file touched: the tests added
|
|
487
932
|
in between changed which tests `perTest` believes cover which mutants.
|
|
488
|
-
[ADR-0007](docs/adr/0007-mutation-testing.md) has recorded that shape for two
|
|
933
|
+
[ADR-0007](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0007-mutation-testing.md) has recorded that shape for two
|
|
489
934
|
releases, and it is why a per-file drop is a question and not an answer.
|
|
490
935
|
|
|
491
936
|
The hosted number is the one that governs, because it is where the build fails:
|
|
@@ -495,12 +940,12 @@ points.
|
|
|
495
940
|
|
|
496
941
|
The incremental run on the same commit read 0.40 points low - the third
|
|
497
942
|
observation after 3.18 high at 0.3.0 and 1.29 low at 0.4.0, and the reason
|
|
498
|
-
[ADR-0007](docs/adr/0007-mutation-testing.md) calls it a signal rather than a
|
|
943
|
+
[ADR-0007](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0007-mutation-testing.md) calls it a signal rather than a
|
|
499
944
|
figure. The tag's run also logged a cache save, which this entry first read as
|
|
500
945
|
the cache-key fix from 0.4.0 doing its job. *Corrected 2026-09-13:* it saved a
|
|
501
946
|
copy of the stale report it had restored, because the full step never wrote one,
|
|
502
947
|
and an entry saved under a tag cannot be restored on `main` in any case. See
|
|
503
|
-
[ADR-0007](docs/adr/0007-mutation-testing.md).
|
|
948
|
+
[ADR-0007](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0007-mutation-testing.md).
|
|
504
949
|
|
|
505
950
|
**The rebuild took 168 of its 180 minutes.** 13% more mutants than 0.4.0, and 63%
|
|
506
951
|
longer on the hosted runner against 15% longer locally. At 0.4.0's old cap of
|
|
@@ -531,7 +976,7 @@ selector, a message, a hint and a severity, and runs it beside the built-ins:
|
|
|
531
976
|
}
|
|
532
977
|
```
|
|
533
978
|
|
|
534
|
-
[ADR-0005](docs/adr/0005-rules-are-queries.md) claimed for three releases that
|
|
979
|
+
[ADR-0005](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0005-rules-are-queries.md) claimed for three releases that
|
|
535
980
|
the selector language was expressive enough for a team to write the equivalent
|
|
536
981
|
of a built-in rule. It was only true at a prompt: `spec-graph query` could find
|
|
537
982
|
the thing, and nothing could make finding it fail. Three ADRs recorded the same
|
|
@@ -550,7 +995,7 @@ nothing answers to is reported when the file is read - a rule that cannot work
|
|
|
550
995
|
has to say so, because silence from a linter is indistinguishable from health.
|
|
551
996
|
`query` also takes a list, read as a union.
|
|
552
997
|
|
|
553
|
-
See [ADR-0016](docs/adr/0016-a-query-needs-a-sentence.md).
|
|
998
|
+
See [ADR-0016](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0016-a-query-needs-a-sentence.md).
|
|
554
999
|
|
|
555
1000
|
**A broken reference suggests the document it was probably meant to name.**
|
|
556
1001
|
`ARD-0015` gets `did you mean ADR-0015?`; `0002-cacheing.md` gets its sibling
|
|
@@ -558,7 +1003,7 @@ one letter away. `ADR-0003` in a repository of two ADRs gets nothing, and that
|
|
|
558
1003
|
restraint is the design rather than a limitation of it: a family name is a word
|
|
559
1004
|
people misremember, a number *is* the identity, and every number sits one edit
|
|
560
1005
|
from its neighbours. Each gate ends the same way - exactly one candidate, or
|
|
561
|
-
silence. See [ADR-0004](docs/adr/0004-reference-resolution.md).
|
|
1006
|
+
silence. See [ADR-0004](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0004-reference-resolution.md).
|
|
562
1007
|
|
|
563
1008
|
**A stale baseline entry says `paid` or `gone`.** `paid` is the ratchet working.
|
|
564
1009
|
`gone` means the document was not in this corpus at all, so nothing is known
|
|
@@ -587,7 +1032,7 @@ UTF-16 read as UTF-8 rather than anybody's keystroke.
|
|
|
587
1032
|
### Fixed
|
|
588
1033
|
|
|
589
1034
|
Nothing that a corpus had hit. Two findings came out of probing rather than out
|
|
590
|
-
of the suite, which is the practice [CLAUDE.md](CLAUDE.md) asks for:
|
|
1035
|
+
of the suite, which is the practice [CLAUDE.md](https://github.com/DescentVTT/spec-graph/blob/main/CLAUDE.md) asks for:
|
|
591
1036
|
|
|
592
1037
|
- A near-miss gate that suggested a file which had moved **never fired**.
|
|
593
1038
|
Resolution already binds a path by its basename, so the suggestion had nothing
|
|
@@ -625,7 +1070,7 @@ of the suite, which is the practice [CLAUDE.md](CLAUDE.md) asks for:
|
|
|
625
1070
|
first time anybody checked. Across 73 keys that Jekyll, Hugo, Docusaurus, Astro,
|
|
626
1071
|
MADR, KEP, the IETF datatracker and Obsidian actually write, one edit reads
|
|
627
1072
|
*none* of them as a near-miss and two edits reads exactly one: `rfc`, which it
|
|
628
|
-
would tell an author to spell `refs`. [ADR-0014](docs/adr/0014-a-relation-is-spelled-both-ways.md)
|
|
1073
|
+
would tell an author to spell `refs`. [ADR-0014](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0014-a-relation-is-spelled-both-ways.md)
|
|
629
1074
|
said two edits would catch `dependancies`; one edit already did, along with
|
|
630
1075
|
every other typo anybody produced to argue the case. Two buys nothing and costs
|
|
631
1076
|
a false positive on a key that carries citations in exactly the corpora this
|
|
@@ -658,7 +1103,7 @@ fails: **75.40%**, up from 75.14% at 0.3.0. Lose every timeout on a loaded runne
|
|
|
658
1103
|
and it reads 71.76%, which is the most margin `break: 70` has ever had.
|
|
659
1104
|
|
|
660
1105
|
That run also caught the other half of a claim
|
|
661
|
-
[ADR-0007](docs/adr/0007-mutation-testing.md) narrowed at 0.3.0. The `main` push
|
|
1106
|
+
[ADR-0007](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0007-mutation-testing.md) narrowed at 0.3.0. The `main` push
|
|
662
1107
|
and the `v0.4.0` tag were the same commit on the same runner, and the incremental
|
|
663
1108
|
read **1.29 points low** against the rebuild - having read 3.18 points *high* at
|
|
664
1109
|
0.3.0. Two observations, opposite signs. The direction is not a property, and the
|
|
@@ -667,7 +1112,7 @@ leaves it nothing to reuse.
|
|
|
667
1112
|
|
|
668
1113
|
### Withdrawn
|
|
669
1114
|
|
|
670
|
-
[ADR-0013](docs/adr/0013-the-scanner-hands-back-prose.md) said a lone `\r` was
|
|
1115
|
+
[ADR-0013](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0013-the-scanner-hands-back-prose.md) said a lone `\r` was
|
|
671
1116
|
not treated as a line ending. It always was - `createLineIndex` has recognised
|
|
672
1117
|
all three terminators since 0.1.0 and says so in its own doc comment. The claim
|
|
673
1118
|
came from reading the scanner and not the table underneath it, and nobody had
|
|
@@ -684,7 +1129,7 @@ built-ins needs a default arm. `BaselineOutcome.stale` carries `reason`, and
|
|
|
684
1129
|
## 0.3.0
|
|
685
1130
|
|
|
686
1131
|
Found by writing a corpus designed to break the scanner and reading the edges it
|
|
687
|
-
produced, which is the practice [CLAUDE.md](CLAUDE.md) asks for and the reason
|
|
1132
|
+
produced, which is the practice [CLAUDE.md](https://github.com/DescentVTT/spec-graph/blob/main/CLAUDE.md) asks for and the reason
|
|
688
1133
|
it is there. The mutation score could not have found any of it: a mutant is a
|
|
689
1134
|
change to code that exists, and a construct nobody parsed has no code to mutate.
|
|
690
1135
|
|
|
@@ -727,7 +1172,7 @@ GitHub's own copy-link all produce for a file with a space in its name. The
|
|
|
727
1172
|
escapes are read as a fallback, so a filename that genuinely contains one keeps
|
|
728
1173
|
resolving by the spelling it was written with, and a stray `100%` is left alone.
|
|
729
1174
|
|
|
730
|
-
See [ADR-0013](docs/adr/0013-the-scanner-hands-back-prose.md).
|
|
1175
|
+
See [ADR-0013](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0013-the-scanner-hands-back-prose.md).
|
|
731
1176
|
|
|
732
1177
|
**Front matter knew half of each relation.** `depends-on` was a key and
|
|
733
1178
|
`depended-on-by` was not, so a repository whose filing convention records
|
|
@@ -738,7 +1183,7 @@ now - twenty-five keys became fifty-six - and a test holds the invariant.
|
|
|
738
1183
|
|
|
739
1184
|
Keys also fold on separators and case, so `depends-on`, `depends_on` and
|
|
740
1185
|
`dependsOn` are one key rather than the two that happened to be written out.
|
|
741
|
-
See [ADR-0014](docs/adr/0014-a-relation-is-spelled-both-ways.md).
|
|
1186
|
+
See [ADR-0014](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0014-a-relation-is-spelled-both-ways.md).
|
|
742
1187
|
|
|
743
1188
|
**`--verbose --format json` printed human lines onto stdout beside the JSON.**
|
|
744
1189
|
|
|
@@ -749,11 +1194,11 @@ See [ADR-0014](docs/adr/0014-a-relation-is-spelled-both-ways.md).
|
|
|
749
1194
|
ignored. Both halves of that gate matter: `deprecated: true` is one edit from
|
|
750
1195
|
`deprecates` and a boolean is not a citation. It says what is true - *"the key
|
|
751
1196
|
declares no relation"* - and offers the near spellings rather than asserting
|
|
752
|
-
one. See [ADR-0014](docs/adr/0014-a-relation-is-spelled-both-ways.md).
|
|
1197
|
+
one. See [ADR-0014](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0014-a-relation-is-spelled-both-ways.md).
|
|
753
1198
|
- **`--ratchet`**, and `"ratchet": true` in the configuration. The other side of
|
|
754
1199
|
a baseline: with it, a declared finding that no longer occurs fails the build,
|
|
755
1200
|
named, with `--record-baseline` as the fix. Off by default, because
|
|
756
|
-
[ADR-0012](docs/adr/0012-a-baseline-is-a-ratchet.md) is right that failing a
|
|
1201
|
+
[ADR-0012](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0012-a-baseline-is-a-ratchet.md) is right that failing a
|
|
757
1202
|
build because somebody fixed something is a strange way to encourage them -
|
|
758
1203
|
and on for a team that has decided its debt only moves one way, because a note
|
|
759
1204
|
on a green build is a line that scrolls past.
|
|
@@ -763,7 +1208,7 @@ See [ADR-0014](docs/adr/0014-a-relation-is-spelled-both-ways.md).
|
|
|
763
1208
|
same rule/specification/citation identity a baseline is keyed on, so an
|
|
764
1209
|
annotation survives a reformat. Deterministic and timestamp-free like every
|
|
765
1210
|
other output here. See
|
|
766
|
-
[ADR-0015](docs/adr/0015-feedback-goes-where-the-tools-already-look.md).
|
|
1211
|
+
[ADR-0015](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0015-feedback-goes-where-the-tools-already-look.md).
|
|
767
1212
|
|
|
768
1213
|
### Not added
|
|
769
1214
|
|
|
@@ -773,14 +1218,14 @@ semantics that differ on all three platforms would be the one part of this
|
|
|
773
1218
|
program that could not honour byte-determinism, inside a codebase whose whole
|
|
774
1219
|
test strategy rests on everything between the edges being a pure function of
|
|
775
1220
|
text. Reasoning in
|
|
776
|
-
[ADR-0015](docs/adr/0015-feedback-goes-where-the-tools-already-look.md).
|
|
1221
|
+
[ADR-0015](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0015-feedback-goes-where-the-tools-already-look.md).
|
|
777
1222
|
|
|
778
1223
|
### Measured
|
|
779
1224
|
|
|
780
1225
|
684 tests, and a mutation score of **75.14% on the hosted runner** - the figure
|
|
781
1226
|
that governs, up from 73.32% at v0.2.0 - against 79.69% over 8,126 mutants on a
|
|
782
1227
|
developer machine. The guard stays at `break: 70`. See
|
|
783
|
-
[ADR-0007](docs/adr/0007-mutation-testing.md), which 0.3.0 also amended: an
|
|
1228
|
+
[ADR-0007](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0007-mutation-testing.md), which 0.3.0 also amended: an
|
|
784
1229
|
incremental run read 3.18 points *high* against a full rebuild of the same
|
|
785
1230
|
commit, so the claim that incremental errs low was wrong.
|
|
786
1231
|
|
|
@@ -795,7 +1240,7 @@ spellings held one id per key. A second claimant therefore did not make the link
|
|
|
795
1240
|
ambiguous; it overwrote the first, and the link went to whichever file was
|
|
796
1241
|
indexed last.
|
|
797
1242
|
|
|
798
|
-
[ADR-0004](docs/adr/0004-reference-resolution.md) has always said two candidates
|
|
1243
|
+
[ADR-0004](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0004-reference-resolution.md) has always said two candidates
|
|
799
1244
|
is worse than none, and a reference matching several documents is reported as
|
|
800
1245
|
ambiguous rather than bound to whichever was indexed first. That now holds for
|
|
801
1246
|
paths too.
|
|
@@ -820,7 +1265,7 @@ keeps no registers is unaffected, and one that does needs no change beyond the
|
|
|
820
1265
|
upgrade.
|
|
821
1266
|
|
|
822
1267
|
Since 0.1.3 a register has yielded one specification per row or per section
|
|
823
|
-
([ADR-0009](docs/adr/0009-a-specification-is-a-region.md)), and every one of
|
|
1268
|
+
([ADR-0009](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0009-a-specification-is-a-region.md)), and every one of
|
|
824
1269
|
those carried the file's path into the resolver's path index. That index keeps
|
|
825
1270
|
whichever entry was written last, so the file's own entry was overwritten by its
|
|
826
1271
|
final region, and:
|
|
@@ -866,12 +1311,12 @@ requirements table headed `Status` was enough to trigger it.
|
|
|
866
1311
|
`historyPatterns` in the configuration or by `<!-- @spec-history -->`, and
|
|
867
1312
|
never guessed from a filename. Its links are still checked and work handed
|
|
868
1313
|
*into* it is still a ghost handover; its own obligations and lifecycle are
|
|
869
|
-
not. See [ADR-0011](docs/adr/0011-a-record-is-not-a-specification.md).
|
|
1314
|
+
not. See [ADR-0011](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0011-a-record-is-not-a-specification.md).
|
|
870
1315
|
- **Baselines.** `--record-baseline` writes today's findings as accepted debt;
|
|
871
1316
|
`--baseline` reports only what is new since. Keyed on the specification and
|
|
872
1317
|
the citation rather than on a line number, so it survives edits, reordering
|
|
873
1318
|
and renames. Paid debt is reported, not failed. See
|
|
874
|
-
[ADR-0012](docs/adr/0012-a-baseline-is-a-ratchet.md).
|
|
1319
|
+
[ADR-0012](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0012-a-baseline-is-a-ratchet.md).
|
|
875
1320
|
|
|
876
1321
|
### Fixed
|
|
877
1322
|
|
|
@@ -886,10 +1331,10 @@ requirements table headed `Status` was enough to trigger it.
|
|
|
886
1331
|
- **A specification is a region of a file, not a file.** A register kept as
|
|
887
1332
|
headings or as a table yields one specification per decision, each with its
|
|
888
1333
|
own lifecycle, obligations and relations. See
|
|
889
|
-
[ADR-0009](docs/adr/0009-a-specification-is-a-region.md).
|
|
1334
|
+
[ADR-0009](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0009-a-specification-is-a-region.md).
|
|
890
1335
|
- **Repository configuration.** `.spec-graph.json`, `spec-graph.config.json`, or
|
|
891
1336
|
a `"spec-graph"` key in `package.json`, with family allow and deny rules. See
|
|
892
|
-
[ADR-0010](docs/adr/0010-configuration-belongs-to-the-repository.md).
|
|
1337
|
+
[ADR-0010](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0010-configuration-belongs-to-the-repository.md).
|
|
893
1338
|
|
|
894
1339
|
## 0.1.2
|
|
895
1340
|
|
|
@@ -897,7 +1342,7 @@ requirements table headed `Status` was enough to trigger it.
|
|
|
897
1342
|
|
|
898
1343
|
- `--ignore-ref`, for repositories where `[[...]]` tags a concept rather than
|
|
899
1344
|
naming a file. See
|
|
900
|
-
[ADR-0008](docs/adr/0008-wiki-links-carry-no-path.md).
|
|
1345
|
+
[ADR-0008](https://github.com/DescentVTT/spec-graph/blob/main/docs/adr/0008-wiki-links-carry-no-path.md).
|
|
901
1346
|
|
|
902
1347
|
## 0.1.1
|
|
903
1348
|
|