check --json reports Vale findings one or two lines above where the text actually is. The offset is consistent, and it differs by the rule's scope, so a consumer cannot correct for it with a single constant either.
Found on 0.11.1 while wiring check into an editor hook that filters findings to the lines an edit touched. The filter matched nothing, because every finding pointed at the wrong line.
Measured
Three real documents, six rules, comparing the reported line against the line the matched text is actually on:
| scope |
reported |
true |
matched text |
| default |
48 |
49 |
isn't that people use carets carel… |
| default |
64 |
65 |
to be honest |
| default |
74 |
75 |
, not a |
| default |
18 |
19 |
a correction into a rule |
| default |
54 |
55 |
Here's the part |
| default |
89 |
90 |
@taskless/cli@latest |
| default |
66 |
67 |
bite |
raw |
25 |
27 |
**The base is a promise about the … |
raw |
27 |
29 |
**The timestamp orders builds.** I… |
raw |
33 |
35 |
**Every rule is now one directory.… |
raw |
41 |
43 |
**His team already had a list of b… |
Default-scope rules are off by one. raw-scope rules are off by two. Every document tested has YAML front matter delimited by --- on lines 1 and 7.
Independently corroborated by a human: the two raw findings above were also flagged by hand in a GitHub PR review, where the reviewer's line anchors were 35 and 43, matching the true column rather than the reported one.
Why it matters
Line numbers are the part of a finding a machine consumes. An editor integration, a CI annotation, a --fix applier, or any hook that filters findings by region gets pointed at the wrong line, and silently: the finding is real, the message is right, the location is off, and nothing about the payload says so.
The two-tier offset is the sharper half. A consumer that discovers the off-by-one and subtracts 1 gets raw rules wrong in the opposite direction, and scope is a property of the rule rather than of the finding, so the payload does not carry enough information to correct it.
Guesses at the cause
Both smell like line accounting around a preamble rather than a Vale defect:
- The one-line offset looks like a 0-based Vale line index emitted as though 1-based, or a front-matter boundary line dropped on the way in.
- The extra line on
raw fits the raw matcher itself: my patterns are anchored with a leading \n, so the match starts on the newline that ends the previous line. If the reported position is the start of the regex match rather than the start of the matched content, raw rules will always read one line early on top of whatever the base offset is. That half may be arguably correct behavior, but it should then be documented, because it means the reported line for a raw rule is not where the flagged text is.
Repro
- A markdown file with YAML front matter and a line containing
to be honest
- A default-scope
existence rule with that token
npx @taskless/cli check <file> --json
- Compare
results[].range.start.line against the real line
Suggested fix
Report the line of the matched content, for both scopes, and add a test asserting range.start.line on a fixture with front matter for one default-scope and one raw-scope rule. The two scopes need separate coverage, since a single-scope test passes while the other tier stays wrong.
check --jsonreports Vale findings one or two lines above where the text actually is. The offset is consistent, and it differs by the rule'sscope, so a consumer cannot correct for it with a single constant either.Found on 0.11.1 while wiring
checkinto an editor hook that filters findings to the lines an edit touched. The filter matched nothing, because every finding pointed at the wrong line.Measured
Three real documents, six rules, comparing the reported line against the line the matched text is actually on:
isn't that people use carets carel…to be honest, not aa correction into a ruleHere's the part@taskless/cli@latestbiteraw**The base is a promise about the …raw**The timestamp orders builds.** I…raw**Every rule is now one directory.…raw**His team already had a list of b…Default-scope rules are off by one.
raw-scope rules are off by two. Every document tested has YAML front matter delimited by---on lines 1 and 7.Independently corroborated by a human: the two
rawfindings above were also flagged by hand in a GitHub PR review, where the reviewer's line anchors were 35 and 43, matching the true column rather than the reported one.Why it matters
Line numbers are the part of a finding a machine consumes. An editor integration, a CI annotation, a
--fixapplier, or any hook that filters findings by region gets pointed at the wrong line, and silently: the finding is real, the message is right, the location is off, and nothing about the payload says so.The two-tier offset is the sharper half. A consumer that discovers the off-by-one and subtracts 1 gets
rawrules wrong in the opposite direction, andscopeis a property of the rule rather than of the finding, so the payload does not carry enough information to correct it.Guesses at the cause
Both smell like line accounting around a preamble rather than a Vale defect:
rawfits therawmatcher itself: my patterns are anchored with a leading\n, so the match starts on the newline that ends the previous line. If the reported position is the start of the regex match rather than the start of the matched content,rawrules will always read one line early on top of whatever the base offset is. That half may be arguably correct behavior, but it should then be documented, because it means the reported line for arawrule is not where the flagged text is.Repro
to be honestexistencerule with that tokennpx @taskless/cli check <file> --jsonresults[].range.start.lineagainst the real lineSuggested fix
Report the line of the matched content, for both scopes, and add a test asserting
range.start.lineon a fixture with front matter for one default-scope and oneraw-scope rule. The two scopes need separate coverage, since a single-scope test passes while the other tier stays wrong.