Zion Boggan zionboggan.com ↗

Flag extensionless files under dot-directories in the hallucination detector

Extension detection read the last dot in the full path, so a dot-directory
segment such as .github/ made an extensionless path like .github/CODEOWNERS
look like it had an extension and skipped it. Extension is now read from the
basename, so dot-directory config paths (.github/CODEOWNERS, .github/workflows/ci,
.husky/pre-commit) are flagged when missing while dotted code symbols stay unflagged.
632c0a5   Zion Boggan committed on Jun 13, 2026 (1 week ago)
src/hallucinate.js +4 -3
@@ -139,9 +139,10 @@ function normalizeFileKey(p) {
}
function tokenExtension(tok) {
- const dot = tok.lastIndexOf('.');
- if (dot < 0) return '';
- return tok.slice(dot + 1).toLowerCase();
+ const base = tok.split('/').pop();
+ const dot = base.lastIndexOf('.');
+ if (dot <= 0) return '';
+ return base.slice(dot + 1).toLowerCase();
}
function hasSlash(tok) {
test/treetrace.test.js +20 -0
@@ -851,6 +851,26 @@ test('hallucinations: a file created during the session is not flagged', () => {
}
});
+test('hallucinations: extensionless files under dot-directories are flagged when missing', () => {
+ const dir = tempProject();
+ try {
+ const root = {
+ id: 'node_001', kind: 'root', status: 'accepted', parent: null,
+ text: 'Open .github/CODEOWNERS and .github/workflows/ci and .husky/pre-commit, and reference JSON.parse and test.skip.',
+ title: 'review config',
+ actions: [],
+ };
+ const result = detectHallucinations({ nodes: [root] }, dir);
+ const files = result.hallucinations.filter((h) => h.category === 'hallucinated_file_or_path').map((h) => h.reference);
+ assert.ok(files.includes('.github/CODEOWNERS'), `dot-directory path should be flagged (got ${files})`);
+ assert.ok(files.includes('.github/workflows/ci'), 'nested dot-directory path should be flagged');
+ assert.ok(files.includes('.husky/pre-commit'), 'hyphenated dot-directory path should be flagged');
+ assert.ok(!files.includes('JSON.parse') && !files.includes('test.skip'), 'dotted code symbols must not be flagged');
+ } finally {
+ rmSync(dir, { recursive: true, force: true });
+ }
+});
+
test('security report: surfaces real signals and omits benign sessions', () => {
const dir = tempProject();
try {