mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-27 22:15:33 +00:00
fix(lint): code-fence-wrap detector and fixer regex now agree (#1597)
The code-fence-wrap detector in lintContent used the /m multiline flag, so ^/$ matched start/end of any line. The rule fired on any page that simply contained a ```markdown code block, not only pages wrapped end-to-end. The matching fixer in fixContent has no /m flag, so it can only strip whole-file wrappers. Result: detected issues were marked fixable: true, yet fixContent could never strip them. `gbrain dream` reported "0 fix(es) applied, N remaining" perpetually for the rule. Drops the /m flag from the detector so detector and fixer stay in sync. Whole-file wrapper detection is preserved; inner code blocks no longer trigger the rule. Real-world impact: a brain with 5 docs pages containing markdown examples (skill READMEs, decision registry, journal templates) reports 5 phantom "fixable: true" issues every dream cycle, never converging. After this fix, the dream-cycle lint phase reports only real-and-unfixable issues (missing frontmatter, missing title/type) which is the intended behavior. Two regression tests added in test/lint.test.ts: - Page contains a single inner ```markdown block - Page contains multiple inner ```markdown blocks Both assert no code-fence-wrap issue is reported. The existing "detects wrapping code fences" test (true-positive case) continues to pass; total tests in the file are 18 -> 20. Co-authored-by: Thomas Chung <thomaschung@macbookair.lan> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Time Attakc <89218912+time-attack@users.noreply.github.com>
This commit is contained in:
co-authored by
Thomas Chung
Claude Opus 4.7
Time Attakc
parent
0a757bf780
commit
e7ffbc057c
@@ -127,7 +127,12 @@ export function lintContent(content: string, filePath: string, opts: LintContent
|
||||
}
|
||||
|
||||
// Rule: Wrapping code fences (```markdown ... ```)
|
||||
if (content.match(/^```(?:markdown|md)\s*\n/m) && content.match(/\n```\s*$/m)) {
|
||||
// Detector intentionally has NO /m flag so ^/$ match start/end of the whole
|
||||
// file, not inner lines. Keeps detector in sync with fixContent() below,
|
||||
// which also has no /m flag. Without this, lint reports "fixable" false
|
||||
// positives on any page that simply contains a ```markdown code block, but
|
||||
// fixContent can never strip them (its regex only matches whole-file wrappers).
|
||||
if (content.match(/^```(?:markdown|md)\s*\n/) && content.match(/\n```\s*$/)) {
|
||||
issues.push({
|
||||
file: filePath, line: 1, rule: 'code-fence-wrap',
|
||||
message: 'Page wrapped in ```markdown code fences (LLM artifact)',
|
||||
|
||||
@@ -32,6 +32,29 @@ describe('lintContent', () => {
|
||||
expect(issues.some(i => i.rule === 'code-fence-wrap')).toBe(true);
|
||||
});
|
||||
|
||||
test('no false positive: page CONTAINS an inner ```markdown code block', () => {
|
||||
// Real-world case: a docs/SKILL page that shows a markdown example inline.
|
||||
// Before this fix, the detector used the /m flag so ^/$ matched start/end
|
||||
// of any line, which fired on any file that simply contained a ```markdown
|
||||
// line. But fixContent's regex has no /m flag and can only strip whole-file
|
||||
// wrappers, so the issue was reported as "fixable: true" yet never fixed.
|
||||
const content =
|
||||
'---\ntitle: Skill\n---\n\n# Skill\n\nExample input shape:\n\n' +
|
||||
'```markdown\n# Inner page\nContent.\n```\n\nThat ends the example.\n';
|
||||
const issues = lintContent(content, 'test.md');
|
||||
expect(issues.filter(i => i.rule === 'code-fence-wrap')).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('no false positive: multiple inner ```markdown blocks', () => {
|
||||
// Documentation pages frequently include several markdown examples.
|
||||
const content =
|
||||
'---\ntitle: Examples\n---\n\n# Examples\n\nFirst:\n\n' +
|
||||
'```markdown\nfoo\n```\n\nSecond:\n\n' +
|
||||
'```markdown\nbar\n```\n\nDone.\n';
|
||||
const issues = lintContent(content, 'test.md');
|
||||
expect(issues.filter(i => i.rule === 'code-fence-wrap')).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('detects placeholder dates', () => {
|
||||
const content = '---\ntitle: Test\ntype: person\ncreated: YYYY-MM-DD\n---\n\n# Test';
|
||||
const issues = lintContent(content, 'test.md');
|
||||
|
||||
Reference in New Issue
Block a user