From d7fcf867afe0ab75544991e6c8db25d40dbccc6d Mon Sep 17 00:00:00 2001 From: Dennis Paul Date: Wed, 20 May 2026 14:10:49 +0200 Subject: [PATCH] fix(local-files): floor mtimeMs to integer for BIGINT compatibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fs.Stats.mtimeMs is documented as a float that preserves sub-millisecond precision when the underlying filesystem supports it (APFS, ext4, btrfs, etc.). The local-files reader propagated this float through: statSync().mtimeMs (float) → episode.maxMessageTime / timeCreated → consolidate.ts chunkSessionTimestamp → reconsolidate.ts entryTime → KnowledgeEntry.{createdAt,updatedAt,lastAccessedAt} → INSERT INTO knowledge_entry (… BIGINT cols) SQLite tolerates the float via type-affinity coercion, but Postgres rejects it strictly: PostgresError: invalid input syntax for type bigint: "1779275328228.197" Every novel-entry insert from a local-files-sourced session fails on a Postgres-backed deployment, while updates (which use Date.now()) succeed — producing a confusing partial-success failure mode where extraction works but no rows reach the store. Fix: Math.floor(stat.mtimeMs) at both statSync call sites in the reader, so all downstream uses inherit a guaranteed-integer value. No schema or API change. Existing 27 local-files tests still pass. --- src/daemon/readers/local-files.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/daemon/readers/local-files.ts b/src/daemon/readers/local-files.ts index 41648ca..225995e 100644 --- a/src/daemon/readers/local-files.ts +++ b/src/daemon/readers/local-files.ts @@ -96,7 +96,13 @@ export class LocalFilesEpisodeReader implements IEpisodeReader { try { content = readFileSync(filePath, "utf8"); - mtimeMs = statSync(filePath).mtimeMs; + // fs.Stats.mtimeMs is a float on most filesystems (sub-millisecond + // precision is preserved when available — see Node fs docs). Coerce + // to integer ms here so the value can be stored in the BIGINT + // columns used for created_at / updated_at / last_accessed_at / + // max_message_time. Postgres rejects fractional bigints with + // "invalid input syntax for type bigint: \"…\".\"…\"". + mtimeMs = Math.floor(statSync(filePath).mtimeMs); } catch { // File disappeared between scan and read — skip silently. continue; @@ -171,7 +177,8 @@ export class LocalFilesEpisodeReader implements IEpisodeReader { const fullPath = join(this.dir, entry.name); try { const stat = statSync(fullPath); - results.push({ path: fullPath, mtimeMs: stat.mtimeMs }); + // Coerce to integer ms — see comment in getNewEpisodes. + results.push({ path: fullPath, mtimeMs: Math.floor(stat.mtimeMs) }); } catch { // File disappeared between readdir and stat — skip. }