docs: tag bare BrightScript code fences + add brightscript-fence-required lint rule#54
Draft
bblietz wants to merge 1 commit into
Draft
docs: tag bare BrightScript code fences + add brightscript-fence-required lint rule#54bblietz wants to merge 1 commit into
bblietz wants to merge 1 commit into
Conversation
…ired lint rule
Audit step 2 of dev-doc-review-report-2026-05-16.md. Tags every bare ```
fence whose body is confidently BrightScript so the renderer can apply
syntax highlighting, and ships a docs-lint rule to prevent regression.
Sweep results (across docs/DEVELOPER, docs/REFERENCES, docs/SPECIFICATIONS,
docs/THE ROKU CHANNEL):
- Total bare fences identified: 644 (regex+mdast aware of 0-3 space and
blockquote indent)
- Auto-tagged 568 fences in 154 files:
- brightscript: 499 (315 strong-signal, 143 directory-context, 8 hand-patched
for deep-indented or blockquote fences the regex sweep missed)
- c: 25 (debugger protocol struct/enum in socket-based-debugger.md;
tagging as `brightscript` would have actively miscolored them)
- text: 22 (Roku channel manifest snippets, BRS debug dumps like
`<Component: roAssociativeArray> = { ... }`, URL templates)
- json: 7
- http: 6
- xml: 1
- Left bare: 76 fences with truly ambiguous content (Robot Framework test
files, single-line `pkg:/...` paths, RAF API schema descriptions, math
notation, release-notes literal dumps)
New tooling:
- `.github/scripts/docs-lint/lib/code-fence-classifier.mjs` - shared
classifier returning {lang, confidence, signals}. Conservative; prefers
'unknown' over guessing. Used by the one-shot sweep tool AND the new
lint rule below.
- `.github/scripts/docs-lint/rules/code-fences.mjs` - new
`brightscript-fence-required` rule: any bare fence whose body classifies
as BrightScript with confidence >= 0.7 is reported as an error.
- `.github/scripts/docs-lint/index.mjs` - wired the new rule into the
RULES array.
Classifier signals (BrightScript): `sub`/`function`/`end sub`/`end function`/
`endif`/`endwhile`/`endfor` keywords; `as Type` annotations (String, Integer,
Boolean, Object, Dynamic, Float, etc.); `CreateObject("ro...")`; `m.top`/
`m.global`/`m.video`/`m.field` references; ro-prefixed object names
(roSGNode, roMessagePort, roByteArray, ...); BRS REPL prompt
(`BrightScript> `); BRS line comments (`'`); hex literals (`&h...`);
`Library "...brs"` statement; `Roku_Ads()` framework call;
`observeFieldScoped` / `callFunc` methods. Two or more signals -> 0.95
confidence; one high-specificity signal -> 0.85; one weak signal alone
stays below the 0.7 act-threshold.
Classifier signals (non-BRS): XML opener (`<?xml`, SceneGraph component
tags); C struct/enum declarations (the debugger-protocol pages);
shebang/shell prompts; HTTP request lines (`GET /path`, `POST https://...`);
Roku channel manifest key=value lines; HLS m3u8 directives (`#EXT-X-...`);
list of single CamelCase identifiers (ECP button names). The classifier
deliberately routes `<Component: ...>` BRS debug-dump format to `text`
not `xml` -- audit caught those as false-positives during dry-run.
Directory-context pass (sweep tool only, NOT the lint rule):
In confirmed BRS directories (REFERENCES/brightscript/, REFERENCES/scenegraph/,
DEVELOPER/core-concepts/, DEVELOPER/advertising/, DEVELOPER/media-playback/,
DEVELOPER/getting-started/, DEVELOPER/dev-tools/, DEVELOPER/discovery/,
DEVELOPER/voice/, DEVELOPER/performance-guide/), fences that don't hit
strong classifier signals AND don't contain explicit non-BRS content are
promoted to brightscript with `directory-context` justification. Catches
1-line BRS method calls like `adIface.setAdUrl(myAdUrl)` that have no
distinctive BRS keywords on their own but live in unambiguously-BRS docs.
Lint baseline preserved: docs-lint shows the same 3 findings as before
(all in `REFERENCES/brightscript/interfaces/ifscreen.md`, unchanged) and
ZERO `brightscript-fence-required` errors after the sweep.
Out of scope (separate follow-up):
- Audit's `roku-pay-best_practices` underscore mismatch claim - already
fixed upstream before this PR; not visible.
- One pre-existing malformed fence with code in the info string
(`createobject("roprogramguide")```` not properly closed) - flagged
for manual review; not in scope here.
- The remaining 76 truly-ambiguous fences (Robot Framework, schema
descriptions, paths, release-notes literals) - intentionally left
bare so the renderer treats them as plain text rather than try to
syntax-highlight them as BRS or another language.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Audit step 2 from
dev-doc-review-report-2026-05-16.md§16. Tags every bare ``` fence whose body is confidently BrightScript so the renderer can apply syntax highlighting, AND ships adocs-lintrule (`brightscript-fence-required`) to prevent regression.The new classifier is the same module used by both the one-shot sweep tool and the new lint rule, so the rule's notion of "looks like BrightScript" is exactly what produced this PR's tags.
Tag breakdown
568 fences auto-tagged across 154 files:
brightscriptcsocket-based-debugger.md. Tagging asbrightscriptwould actively miscolor them.text<Component: roAssociativeArray> = { ... }), URL templatesjsonhttpxml76 fences intentionally left bare. They're Robot Framework test files (
*** Settings ***), single-linepkg:/...paths, RAF API schema descriptions (adPods : [{viewed : Boolean, ...}]), math notation (M = C(-1) S R C T), release-notes literal dumps (a from ' {...}). Leaving them bare prevents the renderer from trying to highlight them as something they aren't.New files
.github/scripts/docs-lint/lib/code-fence-classifier.mjs-- shared classifier returning{lang, confidence, signals}. Conservative; prefersunknownover guessing. Used by both the one-shot sweep tool AND the lint rule below..github/scripts/docs-lint/rules/code-fences.mjs-- newbrightscript-fence-requiredlint rule: any bare fence whose body classifies as BrightScript with confidence >= 0.7 is reported as an error. Wired intoindex.mjsRULES array.How the classifier works
BrightScript signals (any one high-spec or two weak signals -> tag as
brightscript):sub/function/end sub/end function/endif/endwhile/endforas <Type>annotations (String, Integer, Boolean, Object, Dynamic, Float, ...)CreateObject(\"ro...\")-- case-insensitive on theRoprefixm.top/m.global/m.videoand anym.fieldreference, assignment, or method callBrightScript>)')&h...)Library \"...brs\"statementRoku_Ads()framework callobserveFieldScoped/callFuncSceneGraph node methodsNon-BrightScript filters (decisive -- prevents BRS misclassification):
<?xml, SceneGraph component tags with attribute/close-bracket boundary -- explicitly NOT matching<Component: ...>BRS debug-dump syntax)GET /pathORPOST https://...)#EXT-X-...)ChannelUp/ChannelDown)*** Settings ***,*** Variables ***, ...)key : Typeshape definitions)init(): v2style)Directory-context pass (sweep tool only -- the lint rule is path-blind):
In confirmed BRS directories (REFERENCES/brightscript/, REFERENCES/scenegraph/, DEVELOPER/core-concepts/, DEVELOPER/advertising/, DEVELOPER/media-playback/, DEVELOPER/getting-started/, DEVELOPER/dev-tools/, DEVELOPER/discovery/, DEVELOPER/voice/, DEVELOPER/performance-guide/), fences that don't hit strong classifier signals AND don't contain explicit non-BRS content (above) are promoted to
brightscriptwithdirectory-contextjustification. Catches 1-line BRS method calls likeadIface.setAdUrl(myAdUrl)that have no distinctive BRS keyword on their own but live in unambiguously-BRS docs.Test plan
node .github/scripts/docs-lint/index.mjsshows ZERObrightscript-fence-requirederrors after the sweepREFERENCES/brightscript/interfaces/ifscreen.md(1pipe-no-blank-aboveerror + 2html-blank-between-tagswarnings)> \``and deep-indented```` inside list items) hand-patched and re-verifiedOut of scope
roku-pay-best_practicesunderscore mismatch claim -- already fixed upstream; not visible in currentv2.0.createobject(\"roprogramguide\")\``` -- info string has code in it, looks like a missing close fence). Flagged for manual review; not in scope here.Related
Part of the May 16 audit cleanup plan. Step 1 (typos +
_order.yaml+ empty-link) is in flight as PR #52. Next sweep PRs in the queue: terminology canonicalization (~25 hits), broken-absolute-link sweep (252 remaining).