# Batch 8 — Validators (Misc) — Findings

**Date:** 2026-03-26
**Files reviewed:** `validators/hashModeValidator.js`, `validators/robodocValidator.js`, `validators/todoValidator.js`
**Status:** Complete

---

## Summary

All three files carry the systemic `require('vscode')` violation, bringing the running total in
`core/` to **fifteen**. Beyond that, this is the cleanest batch so far — no Major findings and
only two Minors across all three files.

`robodocValidator.js` has a correctness defect: the ACU-RBD-001 diagnostic (missing doc block)
is emitted with a zero-width range because `buildLineRange` is called with an empty string
token, which resolves to column 0 → 0. The squiggle is invisible in the editor.
`hashModeValidator.js` makes three full-document passes where one would suffice, but this is a
maintainability note rather than a correctness issue.

No security issues found.

---

## Findings

### `hashModeValidator.js`

#### [CRITICAL] `require('vscode')` in core/ — line 10

**Issue:** `const vscode = require("vscode")` at line 10; used to construct `vscode.Range` at
lines 36, 63, and 86. This is the **thirteenth** violation.

**Recommendation:** Remove the `vscode` import. Replace `new vscode.Range(l, s, l, e)` with
plain position objects at all three call sites.

---

#### [MINOR] Three separate full-document loops for three checks — lines 25, 53, 71

**Issue:** `validateHashMode` makes three independent `for` loops over `document.lineCount`.
All three checks could be merged into a single loop, reading each line once. The current
structure is safe but reads every line three times, which is wasteful on large files and makes
the control flow harder to follow as a unit.

**Recommendation:** Merge into a single loop. The ACU-SYN-001 state machine (hash mode
tracking) can run alongside the ACU-SYN-002 and ACU-SYN-003 checks since all three use
`lineIndex` as their primary key.

---

### `robodocValidator.js`

#### [CRITICAL] `require('vscode')` in core/ — line 1

**Issue:** `const vscode = require("vscode")` at line 1; used inside `buildLineRange` at lines
25 and 30. This is the **fourteenth** violation.

**Recommendation:** Remove the `vscode` import. `buildLineRange` is a pure helper that returns
a position object — replace `new vscode.Range(...)` with plain `{ start: { line, character }, end: { line, character } }` objects.

---

#### [MINOR] Zero-width diagnostic range for ACU-RBD-001 — line 67

**Issue:** When the document has no `@docStart` and `config.requireDocBlock` is true, the
diagnostic is emitted via:

```js
buildLineRange(0, firstLineText, "")
```

Inside `buildLineRange`, `lineText.indexOf("")` always returns `0`, so `tokenIndex >= 0` is
true, and the function returns:

```js
new vscode.Range(0, 0, 0, 0 + "".length)  // → Range(0, 0, 0, 0)
```

This is a zero-width range at the very start of the file. VS Code renders a zero-width
diagnostic as an invisible squiggle; the user sees nothing underlined for ACU-RBD-001.

The fallback branch in `buildLineRange` (first-non-whitespace to end-of-line) is correct and
should have been used here, but is unreachable when an empty string is passed.

**Recommendation:** Pass `null` instead of `""` when there is no specific token to target
(i.e., `buildLineRange(0, firstLineText, null)`). The existing `if (tokenIndex >= 0)` guard
already handles `null` correctly since `lineText.indexOf(null)` is `-1` in Node.js, routing
to the fallback.

---

### `todoValidator.js`

#### [CRITICAL] `require('vscode')` in core/ — line 11

**Issue:** `const vscode = require("vscode")` at line 11; used to construct `vscode.Range` at
line 83. This is the **fifteenth** violation.

**Recommendation:** Remove the `vscode` import; replace with a plain position object.

---

## Observations

### `todoValidator.js` — colon-required tag format

`TODO_TAGS` patterns all require a colon (`TODO:`, `FIXME:`, `HACK:`). A common variant —
`// TODO fix this` (no colon) — is silently ignored. This is a deliberate format choice but is
not documented. Users who omit the colon get no diagnostic and may wonder why their TODOs are
not appearing in the Problems panel.

**Recommendation:** Add a comment to `TODO_TAGS` noting that the colon is required. Optionally
extend the patterns to also match the colon-free form under the same rule ID.

---

### `robodocValidator.js` — only the first `@docStart`/`@docEnd` pair is validated

The scan loop stops at the first `@docStart` and the first `@docEnd`. If a file contains
multiple robodoc blocks (unusual but possible in template files), only the first block is
validated. Subsequent blocks are silently skipped.

This is a known limitation of the single-pass design. It warrants a comment in the source to
make the intent clear.

---

### `hashModeValidator.js` — ACU-SYN-003 fires on `# NOTE` even in valid hash-mode output

ACU-SYN-003 flags any line matching `^\s*#\s*NOTE\b` when `hashMode === "HASH-ON"`. In HASH-ON
mode, `NOTE` is a valid executable keyword and `#NOTE` is the comment syntax — so the rule
is correct. However, if the executionClassificationMap marks the line differently from the
hash-mode state tracked in the ACU-SYN-001 loop (e.g., due to include-file hash-mode
inheritance), the two sources of truth could disagree and produce spurious diagnostics.

This is an edge case; the hash mode tracking in the ACU-SYN-001 loop and the
`executionClassificationMap.hashMode` used in ACU-SYN-003 should be kept in sync.

---

## Summary table

| Severity | Count | Items |
|---|---|---|
| Critical | 3 | `require('vscode')` in all 3 files |
| Major | 0 | — |
| Minor | 2 | Three-loop structure in hashModeValidator; zero-width range for ACU-RBD-001 |
| Observation | 3 | Colon-required TODO format undocumented; single robodoc block only; hash-mode state-source divergence edge case |
