From 4b4b1197ee776597dfbe9ed2a9995a9015d6986d Mon Sep 17 00:00:00 2001 From: Brad Groux Date: Wed, 28 Jan 2026 17:29:10 -0600 Subject: [PATCH] fix(types): replace as-any casts with proper type narrowing --- .../telemetry/events-2026-01-28.ndjson | 64 +++++++++++++++++++ server/.veritas-kanban/activity.json | 33 ++++++++++ server/src/services/telemetry-service.ts | 3 + web/src/hooks/useFeatureSettings.ts | 23 ++++--- 4 files changed, 111 insertions(+), 12 deletions(-) diff --git a/.veritas-kanban/telemetry/events-2026-01-28.ndjson b/.veritas-kanban/telemetry/events-2026-01-28.ndjson index b3e91780..6623d91e 100644 --- a/.veritas-kanban/telemetry/events-2026-01-28.ndjson +++ b/.veritas-kanban/telemetry/events-2026-01-28.ndjson @@ -3913,3 +3913,67 @@ {"type":"task.created","taskId":"task_20260128_PNHngW","status":"todo","id":"evt_bpE9jp_MFCZ8","timestamp":"2026-01-28T23:18:51.954Z"} {"type":"task.status_changed","taskId":"task_20260128_KXgXs-","project":"veritas-kanban","status":"done","previousStatus":"in-progress","id":"evt_i7ObLcav49RK","timestamp":"2026-01-28T23:19:15.060Z"} {"type":"task.status_changed","taskId":"task_20260128_fTudfN","project":"veritas-kanban","status":"in-progress","previousStatus":"todo","id":"evt_KlHOdVR_-UaW","timestamp":"2026-01-28T23:19:41.071Z"} +{"type":"task.status_changed","taskId":"task_20260128_iFNFgD","project":"veritas-kanban","status":"done","previousStatus":"in-progress","id":"evt_X1C7orlxRQFY","timestamp":"2026-01-28T23:26:39.708Z"} +{"type":"task.status_changed","taskId":"task_20260128_LTxaqy","project":"veritas-kanban","status":"in-progress","previousStatus":"todo","id":"evt_yTxRPnoZCryp","timestamp":"2026-01-28T23:27:17.549Z"} +{"type":"task.status_changed","taskId":"task_20260126_legacy1","status":"blocked","previousStatus":"review","id":"evt_VMmyWf9VwZWJ","timestamp":"2026-01-28T23:27:27.839Z"} +{"type":"task.created","taskId":"task_20260128_lj4Z99","status":"todo","id":"evt_8FTG7WXaHgz-","timestamp":"2026-01-28T23:27:27.849Z"} +{"type":"task.created","taskId":"task_20260128_sBF9Nv","status":"todo","id":"evt_psmbhNov4Z3R","timestamp":"2026-01-28T23:27:27.855Z"} +{"type":"task.status_changed","taskId":"task_20260128_sBF9Nv","status":"in-progress","previousStatus":"todo","id":"evt_kUekHpbkWHGb","timestamp":"2026-01-28T23:27:27.857Z"} +{"type":"task.created","taskId":"task_20260128_SYLpR_","status":"todo","id":"evt_rReB8JRWaG4u","timestamp":"2026-01-28T23:27:27.858Z"} +{"type":"task.status_changed","taskId":"task_20260128_SYLpR_","status":"blocked","previousStatus":"todo","id":"evt_Y4rBSSjj9Hzo","timestamp":"2026-01-28T23:27:27.859Z"} +{"type":"task.created","taskId":"task_20260128_43vnTM","status":"todo","id":"evt_vzAzLJLruX6_","timestamp":"2026-01-28T23:27:27.860Z"} +{"type":"task.status_changed","taskId":"task_20260128_43vnTM","status":"done","previousStatus":"todo","id":"evt_K5t87ZXDtUV4","timestamp":"2026-01-28T23:27:27.860Z"} +{"type":"task.created","taskId":"task_20260128_p1PLRl","project":"my-project","status":"todo","id":"evt_5ahbJVZwBUlf","timestamp":"2026-01-28T23:27:27.864Z"} +{"type":"task.status_changed","taskId":"task_20260126_idem1","status":"blocked","previousStatus":"review","id":"evt_w-UnHxp5CtVj","timestamp":"2026-01-28T23:27:27.866Z"} +{"type":"task.created","taskId":"task_20260128_BQ3-gL","status":"todo","id":"evt_7pro9QOmHrO6","timestamp":"2026-01-28T23:27:27.868Z"} +{"type":"task.created","taskId":"task_20260128_QkCHxG","status":"todo","id":"evt_eV7jh9FyC_8t","timestamp":"2026-01-28T23:27:27.873Z"} +{"type":"task.status_changed","taskId":"task_20260126_multi2","status":"blocked","previousStatus":"review","id":"evt_mgK-mP4QJPqz","timestamp":"2026-01-28T23:27:27.876Z"} +{"type":"task.status_changed","taskId":"task_20260126_multi1","status":"blocked","previousStatus":"review","id":"evt_J2puAECXTaZk","timestamp":"2026-01-28T23:27:27.876Z"} +{"type":"task.created","taskId":"task_20260128_MmcFgY","status":"todo","id":"evt_PnxqHkye-g2g","timestamp":"2026-01-28T23:27:27.876Z"} +{"type":"task.created","taskId":"task_20260128_hT819y","status":"todo","id":"evt_EeX4hqyr1UqT","timestamp":"2026-01-28T23:27:27.889Z"} +{"type":"task.status_changed","taskId":"task_20260128_MmcFgY","status":"in-progress","previousStatus":"todo","id":"evt_ffL8-vv2NeQA","timestamp":"2026-01-28T23:27:27.890Z"} +{"type":"task.created","taskId":"task_20260128_7fgNop","status":"todo","id":"evt_bIyUvz9NeRPL","timestamp":"2026-01-28T23:27:27.895Z"} +{"type":"task.created","taskId":"task_20260128_1B5w5Q","status":"todo","id":"evt_6TMhdPb7sWeY","timestamp":"2026-01-28T23:27:27.898Z"} +{"type":"task.created","taskId":"task_20260128_IYgvXl","status":"todo","id":"evt_sbRP7kB7XO49","timestamp":"2026-01-28T23:27:27.912Z"} +{"type":"task.created","taskId":"task_20260128_5xHrOL","status":"todo","id":"evt_jT5Uw8_mvNsR","timestamp":"2026-01-28T23:27:27.932Z"} +{"type":"task.created","taskId":"task_20260128_ZYZWzi","status":"todo","id":"evt_b7xFKC3Vi24S","timestamp":"2026-01-28T23:27:27.935Z"} +{"type":"task.created","taskId":"task_20260128_aOoNnj","status":"todo","id":"evt_UCyxa6b1hdvo","timestamp":"2026-01-28T23:27:27.938Z"} +{"type":"task.created","taskId":"task_20260128_QmqnPn","status":"todo","id":"evt_GcEQSPE0Lsa_","timestamp":"2026-01-28T23:27:27.943Z"} +{"type":"task.created","taskId":"task_20260128_V68maD","status":"todo","id":"evt_b0kpvnwOejnU","timestamp":"2026-01-28T23:27:27.952Z"} +{"type":"task.created","taskId":"task_20260128_7qD-UI","status":"todo","id":"evt_hoRGbBuazqbJ","timestamp":"2026-01-28T23:27:27.969Z"} +{"type":"task.created","taskId":"task_20260128_QI6jIO","status":"todo","id":"evt_QA5cXJlxsjNQ","timestamp":"2026-01-28T23:27:27.974Z"} +{"type":"task.created","taskId":"task_20260128_BT3M14","status":"todo","id":"evt_kINtIAZlazKX","timestamp":"2026-01-28T23:27:27.979Z"} +{"type":"task.created","taskId":"task_20260128_CkCfO_","status":"todo","id":"evt_Xwvg2Aua7BGw","timestamp":"2026-01-28T23:27:27.981Z"} +{"type":"task.created","taskId":"task_20260128_QKDumH","project":"test-project","status":"todo","id":"evt_7RbOiyIaJ0UI","timestamp":"2026-01-28T23:27:27.981Z"} +{"type":"task.created","taskId":"task_20260128_p-6qI6","status":"todo","id":"evt_urI8YxvCXGch","timestamp":"2026-01-28T23:27:27.987Z"} +{"type":"task.created","taskId":"task_20260128_Rzpwgn","status":"todo","id":"evt_ZaIyhKoW1o9h","timestamp":"2026-01-28T23:27:27.988Z"} +{"type":"task.created","taskId":"task_20260128_jqse3Q","status":"todo","id":"evt_RB5e5Z6bNvIb","timestamp":"2026-01-28T23:27:27.989Z"} +{"type":"task.created","taskId":"task_20260128_haeVOH","status":"todo","id":"evt_2pYQjXXWAVSP","timestamp":"2026-01-28T23:27:27.996Z"} +{"type":"task.restored","taskId":"task_20260126_arch1","status":"done","id":"evt_Pa0qC9CJdKMG","timestamp":"2026-01-28T23:27:27.998Z"} +{"type":"task.status_changed","taskId":"task_20260126_arch1","status":"blocked","previousStatus":"done","id":"evt_JiMmO53cXCHJ","timestamp":"2026-01-28T23:27:27.999Z"} +{"type":"task.created","taskId":"task_20260128_czW7n3","status":"todo","id":"evt_46j7Bf4iE0aO","timestamp":"2026-01-28T23:27:27.999Z"} +{"type":"task.archived","taskId":"task_20260126_arch1","status":"blocked","id":"evt_MlGWo9pnFH-z","timestamp":"2026-01-28T23:27:28.000Z"} +{"type":"task.archived","taskId":"task_20260128_czW7n3","status":"todo","id":"evt_djComEhLRvgk","timestamp":"2026-01-28T23:27:28.001Z"} +{"type":"task.created","taskId":"task_20260128_-uhv7U","status":"todo","id":"evt_5AN6TJvorSKF","timestamp":"2026-01-28T23:27:28.004Z"} +{"type":"task.status_changed","taskId":"task_20260128_-uhv7U","status":"in-progress","previousStatus":"todo","id":"evt_-Wk7-9J36ZgZ","timestamp":"2026-01-28T23:27:28.009Z"} +{"type":"task.created","taskId":"task_20260128_dXHAIj","status":"todo","id":"evt_NGKNGQMc2CqP","timestamp":"2026-01-28T23:27:28.013Z"} +{"type":"task.created","taskId":"task_20260128_sUEmpo","status":"todo","id":"evt_B-mZSF4GBdxd","timestamp":"2026-01-28T23:27:28.018Z"} +{"type":"task.created","taskId":"task_20260128_n5aO8k","status":"todo","id":"evt_Z1PmMp2u-Ra9","timestamp":"2026-01-28T23:27:28.022Z"} +{"type":"task.created","taskId":"task_20260128_8cHMuK","status":"todo","id":"evt_mSQj8c3rdvvS","timestamp":"2026-01-28T23:27:28.026Z"} +{"type":"task.created","taskId":"task_20260128_jwxuzA","status":"todo","id":"evt_OUceL334UP69","timestamp":"2026-01-28T23:27:28.027Z"} +{"type":"task.created","taskId":"task_20260128_HtzXYk","status":"todo","id":"evt_YxwdchAAEvnZ","timestamp":"2026-01-28T23:27:28.033Z"} +{"type":"task.created","taskId":"task_20260128_sOYg1P","status":"todo","id":"evt__DpsvkFuEiAj","timestamp":"2026-01-28T23:27:28.035Z"} +{"type":"task.created","taskId":"task_20260128_zaUHfj","status":"todo","id":"evt_CkdOdJrXE6VE","timestamp":"2026-01-28T23:27:28.039Z"} +{"type":"task.created","taskId":"task_20260128_6VFrU8","status":"todo","id":"evt_lYPzqEziVTLs","timestamp":"2026-01-28T23:27:28.042Z"} +{"type":"task.created","taskId":"task_20260128_Glgvaf","status":"todo","id":"evt__TBFocfkJOpn","timestamp":"2026-01-28T23:27:28.043Z"} +{"type":"task.created","taskId":"task_20260128_JvmuVL","status":"todo","id":"evt_FwLG9vQIPZyg","timestamp":"2026-01-28T23:27:28.049Z"} +{"type":"task.created","taskId":"task_20260128_GAGA6m","status":"todo","id":"evt_UjxLEK6-s1YE","timestamp":"2026-01-28T23:27:28.057Z"} +{"type":"task.created","taskId":"task_20260128_U_4372","status":"todo","id":"evt_av3ebPB-ncTr","timestamp":"2026-01-28T23:27:28.063Z"} +{"type":"task.created","taskId":"task_20260128_UvcmNW","status":"todo","id":"evt_gUz2BpieniHE","timestamp":"2026-01-28T23:27:28.068Z"} +{"type":"task.created","taskId":"task_20260128_Y-3iHI","project":"project-a","status":"todo","id":"evt_U8R_y4wYTe3x","timestamp":"2026-01-28T23:27:28.083Z"} +{"type":"task.created","taskId":"task_20260128_ukkEcs","project":"project-a","status":"todo","id":"evt_3dDxNWLtB5Dd","timestamp":"2026-01-28T23:27:28.084Z"} +{"type":"task.created","taskId":"task_20260128_jj1qjE","project":"project-b","status":"todo","id":"evt_4pgFqXEVC1af","timestamp":"2026-01-28T23:27:28.085Z"} +{"type":"task.created","taskId":"task_20260128_MhTVqi","status":"todo","id":"evt_FWu4L4Fnl3aI","timestamp":"2026-01-28T23:27:28.110Z"} +{"type":"task.created","taskId":"task_20260128_hAmiS8","status":"todo","id":"evt_xyDVtMkhHNpf","timestamp":"2026-01-28T23:27:28.123Z"} +{"type":"task.created","taskId":"task_20260128_iuB0lF","status":"todo","id":"evt_MkA_8ItHmobO","timestamp":"2026-01-28T23:27:28.127Z"} +{"type":"task.created","taskId":"task_20260128_oiEekN","status":"todo","id":"evt_YRPGA9mojxOK","timestamp":"2026-01-28T23:27:28.128Z"} diff --git a/server/.veritas-kanban/activity.json b/server/.veritas-kanban/activity.json index dbd0f6cd..9e7003b7 100644 --- a/server/.veritas-kanban/activity.json +++ b/server/.veritas-kanban/activity.json @@ -1,4 +1,37 @@ [ + { + "id": "activity_1769642837550_cmukzh57h", + "type": "status_changed", + "taskId": "task_20260128_LTxaqy", + "taskTitle": "PERF: Optimize telemetry storage growth and query performance", + "details": { + "from": "todo", + "status": "in-progress" + }, + "timestamp": "2026-01-28T23:27:17.550Z" + }, + { + "id": "activity_1769642805992_n500diz9w", + "type": "comment_added", + "taskId": "task_20260128_iFNFgD", + "taskTitle": "QUALITY: Audit and fix 39 silent catch blocks", + "details": { + "author": "Veritas", + "preview": "Audited all catch blocks across server/src and web..." + }, + "timestamp": "2026-01-28T23:26:45.992Z" + }, + { + "id": "activity_1769642799708_eggjdun33", + "type": "status_changed", + "taskId": "task_20260128_iFNFgD", + "taskTitle": "QUALITY: Audit and fix 39 silent catch blocks", + "details": { + "from": "in-progress", + "status": "done" + }, + "timestamp": "2026-01-28T23:26:39.708Z" + }, { "id": "activity_1769642381071_3yttsvfj6", "type": "status_changed", diff --git a/server/src/services/telemetry-service.ts b/server/src/services/telemetry-service.ts index de01b70a..09e92144 100644 --- a/server/src/services/telemetry-service.ts +++ b/server/src/services/telemetry-service.ts @@ -1,5 +1,8 @@ import fs from 'fs/promises'; +import { createReadStream, createWriteStream } from 'fs'; import path from 'path'; +import { createGzip, gunzipSync } from 'zlib'; +import { pipeline } from 'stream/promises'; import { nanoid } from 'nanoid'; import type { TelemetryEvent, diff --git a/web/src/hooks/useFeatureSettings.ts b/web/src/hooks/useFeatureSettings.ts index 89b33b96..3472d815 100644 --- a/web/src/hooks/useFeatureSettings.ts +++ b/web/src/hooks/useFeatureSettings.ts @@ -51,7 +51,7 @@ export function useUpdateFeatureSettings() { const queryClient = useQueryClient(); return useMutation({ - mutationFn: (patch: Partial) => api.settings.updateFeatures(patch), + mutationFn: (patch: Record) => api.settings.updateFeatures(patch), onMutate: async (patch) => { // Cancel in-flight fetches await queryClient.cancelQueries({ queryKey: QUERY_KEY }); @@ -61,13 +61,13 @@ export function useUpdateFeatureSettings() { // Optimistically update if (previous) { - const optimistic: Record> = { ...previous }; - const patchRecord = patch as Record>; - for (const section of Object.keys(patchRecord)) { - if (section in optimistic && typeof patchRecord[section] === 'object') { + // SAFETY: FeatureSettings sections are all objects — use Record view for dynamic key access + const optimistic = { ...previous } as unknown as Record>; + for (const section of Object.keys(patch) as Array) { + if (section in optimistic && typeof patch[section] === 'object') { optimistic[section] = { ...optimistic[section], - ...patchRecord[section], + ...patch[section], }; } } @@ -96,23 +96,22 @@ export function useUpdateFeatureSettings() { export function useDebouncedFeatureUpdate(delayMs = 500) { const update = useUpdateFeatureSettings(); const timeoutRef = { current: null as ReturnType | null }; - const pendingRef = { current: {} as Record> }; + const pendingRef = { current: {} as Record }; const flush = useCallback(() => { if (Object.keys(pendingRef.current).length > 0) { - update.mutate({ ...pendingRef.current } as Partial); + update.mutate({ ...pendingRef.current }); pendingRef.current = {}; } }, [update]); const debouncedUpdate = useCallback( - (patch: Partial) => { + (patch: Record) => { // Merge into pending batch - const patchRecord = patch as Record>; - for (const section of Object.keys(patchRecord)) { + for (const section of Object.keys(patch)) { pendingRef.current[section] = { ...(pendingRef.current[section] || {}), - ...patchRecord[section], + ...patch[section], }; }