Repository navigation
Description
Before submitting
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
Area
apps/server
Steps to reproduce
On Windows with NTFS last-access updates on. This is the default "System Managed" mode (fsutil behavior query disablelastaccess → 2 (System Managed, Last Access Time Updates ENABLED)):
- Open T3 Code and leave it idle. Don't edit
~/.t3/userdata/keybindings.json. - Have any process read
keybindings.jsonwhen its last-access time is over about an hour old. Examples:type %USERPROFILE%\.t3\userdata\keybindings.json, an agent grepping~/.t3, Defender, Windows Search, or backup/sync tools. - A "Keybindings updated – Keybindings configuration reloaded successfully." toast appears.
The underlying watcher behavior can be reproduced in plain Node (no T3 involved):
const fs = require('fs'), path = require('path');
const dir = path.resolve('watchtest'); fs.mkdirSync(dir, { recursive: true });
const f = path.join(dir, 'keybindings.json'); fs.writeFileSync(f, '[]');
fs.utimesSync(f, new Date(Date.now() - 3 * 3600e3), fs.statSync(f).mtime); // make atime stale
setTimeout(() => {
const w = fs.watch(dir, (ev, name) => console.log('EVENT', ev, name));
setTimeout(() => { fs.readFileSync(f); /* read only */ setTimeout(() => w.close(), 1500); }, 500);
}, 1500);
// Output on Windows: "EVENT change keybindings.json"Expected behavior
The toast (and the keybindingsUpdated push) should only happen when the keybindings config actually changes.
Actual behavior
"Keybindings updated" toasts show up at random times during normal use, while keybindings.json itself stays the same (on my machine its mtime is still the original write from 2 days ago; only its atime changes).
Cause, from reading the shipped bundle:
apps/server/src/keybindings.ts→startWatchercallsfs.watch(keybindingsConfigDir)and filters onevent.path === "keybindings.json", debounced 100ms, then callsrevalidateAndEmit. That function invalidates the cache, reloads from disk and alwaysemitChanges, with no comparison against the previous state.- On Windows, libuv's
ReadDirectoryChangesWmask includesFILE_NOTIFY_CHANGE_LAST_ACCESS. So when a plain read bumps the atime, Node reportschange keybindings.json. NTFS only bumps the atime about once per hour, which is why the toasts come at irregular intervals instead of in a loop. subscribeServerConfigforwards each change as a{ type: "keybindingsUpdated" }event. In the web app, the config-event handler (p8/handleinmain-*.js) shows the success toast for every such event that isn't within 2s of the previous one.
Suggested fix: in revalidateAndEmit, skip emitChange when the reloaded { keybindings, issues } equal the cached state (or when mtime/size didn't change). The client could also skip the toast when the resolved keybindings didn't change.
Impact
Minor bug or occasional failure
Version or commit
0.1.2-nightly.20261022.3526
Environment
Windows 11 (10.0.26200), T3 Code (Nightly) desktop app, NTFS with DisableLastAccess = 2 (System Managed, enabled)
Logs or stack traces
$ stat keybindings.json
atime=2026-10-22 10:00:25 -0400 mtime=2026-10-20 09:16:01 -0400Workaround
fsutil behavior set disablelastaccess 1 (admin + reboot) turns off last-access updates for the whole system. Excluding ~/.t3/userdata from Windows Search and Defender cuts down on readers but doesn't remove all of them.
Activity