diff --git a/tests/docs-parity-live-registry.test.cjs b/tests/docs-parity-live-registry.test.cjs index 8c5887a96..f0c218369 100644 --- a/tests/docs-parity-live-registry.test.cjs +++ b/tests/docs-parity-live-registry.test.cjs @@ -197,9 +197,14 @@ function extractCommandTokens(content) { return false; } - const allSlash = (stripped.match(/\/gsd-[a-z0-9][a-z0-9-]*/g) || []); - const allColon = (stripped.match(/\/gsd:[a-z0-9][a-z0-9-]*/g) || []); - const allDollar = (stripped.match(/\$gsd-[a-z0-9][a-z0-9-]*/g) || []); + // Negative lookbehind: only match tokens NOT preceded by a letter, digit, + // `/`, `_`, or `-`. This prevents matching the `/gsd-core` substring inside + // the org/repo path `open-gsd/gsd-core` (and similar path-embedded segments) + // while still matching real invocations preceded by BOL, space, backtick, or + // `(`. Fixes false-positive class identified in #489. + const allSlash = (stripped.match(/(? !isInternal(t))); const colon = new Set(allColon.filter(t => !isInternal(t))); @@ -483,3 +488,44 @@ describe('adversarial: polarity inversion catches drift deny-list misses', () => assert.ok(!registry.has('/gsd-research-phase'), '/gsd-research-phase must not be in the live registry'); }); }); + +// ─── Tokenizer regression tests (#489) ─────────────────────────────────────── + +describe('extractCommandTokens() — repo-path false-positive regression (#489)', () => { + test('open-gsd/gsd-core#22 repo path does NOT produce a /gsd-core token', () => { + // Before the lookbehind fix, /gsd-core inside `open-gsd/gsd-core#22` + // would be matched by the slash regex — a false positive. + const { slash, colon, dollar } = extractCommandTokens( + 'see open-gsd/gsd-core#22 for details' + ); + const all = [...slash, ...colon, ...dollar]; + assert.ok( + !all.includes('/gsd-core'), + 'repo path open-gsd/gsd-core#22 must not produce a /gsd-core token; got: ' + all.join(', ') + ); + assert.strictEqual(all.length, 0, 'expected zero tokens from a bare repo-path string; got: ' + all.join(', ')); + }); + + test('space-preceded /gsd-totally-not-a-real-command is still extracted (real invocation)', () => { + // A genuine (but unregistered) command reference after whitespace must be + // captured so the live-registry check can flag it as unknown. + const { slash } = extractCommandTokens( + 'run /gsd-totally-not-a-real-command here' + ); + assert.ok( + slash.has('/gsd-totally-not-a-real-command'), + 'invocation after whitespace must be extracted; slash set: ' + [...slash].join(', ') + ); + }); + + test('backtick-wrapped `/gsd-plan` is still extracted (real invocation)', () => { + // Backtick-wrapped commands (common in markdown) must still be captured. + const { slash } = extractCommandTokens( + 'use `/gsd-plan` to plan' + ); + assert.ok( + slash.has('/gsd-plan'), + 'backtick-wrapped invocation must be extracted; slash set: ' + [...slash].join(', ') + ); + }); +});