From 777ad4af912863be0f6c6e4cbbe9418fbc4aaae3 Mon Sep 17 00:00:00 2001 From: Chris Amow Date: Sat, 15 Aug 2026 03:57:31 -0500 Subject: [PATCH] version at bottom --- docs/NEXT_STEPS.md | 18 ++++++++++++++++++ static/app.js | 14 +++++++++++++- static/index.html | 2 +- static/style.css | 2 +- 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/docs/NEXT_STEPS.md b/docs/NEXT_STEPS.md index f852758..4a805c2 100644 --- a/docs/NEXT_STEPS.md +++ b/docs/NEXT_STEPS.md @@ -8,6 +8,24 @@ decisions behind them in `docs/plan.md`. ## Fix next +### Revisit the trendline live-edge bend with painted-pixel evidence + +Production still appears to show a bend where 30m manual lines cross from the +last real candle into future whitespace. The deployed code is verified to use +one canvas `LineSeries`, retained transparent time-scale points, and canonical +source-space prices. Diagnostic values can report unequal historical/future +screen slopes when the final candles are sparse, but synthetic browser coverage +passes after gap slots are inserted. The transparent-point production fix did +not visibly settle the report, so do not add another geometry patch from the +current theory. + +Next investigation should compare the painted canvas pixels around the join +against the chart API's expected coordinates in the user's production viewport. +This is the same class of problem where self-consistent API coordinates once +missed a real overlay offset. Capture the asset commit, final three bar times, +their logical/x coordinates, the first two future coordinates, canonical line +prices, and page-pixel samples from the rendered line before changing code. + ### Deepen freshness telemetry The status bar now reports when the browser received its latest snapshot or bar. diff --git a/static/app.js b/static/app.js index fbcf9bb..13d8120 100644 --- a/static/app.js +++ b/static/app.js @@ -233,6 +233,16 @@ createApp({ hour: 'numeric', minute: '2-digit', second: '2-digit', }).format(new Date(dataReceivedAt.value)); }); + const build = ref({ commit: '', startedAt: '' }); + const buildStamp = computed(() => { + const commit = (build.value.commit || 'dev').slice(0, 7); + if (!build.value.startedAt) return commit; + const at = new Date(build.value.startedAt); + if (Number.isNaN(at.getTime())) return commit; + return `${commit} ${new Intl.DateTimeFormat(undefined, { + day: 'numeric', month: 'short', hour: 'numeric', minute: '2-digit', + }).format(at)}`; + }); const quoteChange = computed(() => { if (price.value == null || !(sessionOpen.value > 0)) return null; const points = price.value - sessionOpen.value; @@ -1164,6 +1174,8 @@ createApp({ await migrateLegacyToken(); await refreshStatus(); await refreshComments(); + const version = await fetch('/api/version').then(response => response.json()).catch(() => ({})); + build.value = { commit: version.commit || 'dev', startedAt: version.started_at || '' }; connect(); timer = setInterval(() => { now.value = Date.now(); refreshStatus(); }, 5000); }); @@ -1174,6 +1186,6 @@ createApp({ window.removeEventListener('keydown', handleKeydown); }); - return { status, price, sessionOpen, quoteChange, animateCurrentPrice, autoScrollLivePrice, barAge, dataUpdatedAt, timeframe, timeframes, drawingColors, drawingColorRows, drawingColorName, colorRowLabels, symbolChoices, selectedSymbol, symbolColor, symbolScale, symbolScales, symbolPanelOpen, prefs, clusters, clustersByPrice, events, diagnosticMode, captureBusy, captureDiagnostic, armedTool, drawName, drawColor, drawWidth, drawSide, snap, selectedDrawing, selectedDrawings, manualLines, hasDrawingSelection, allShownSelected, selectedAreHidden, alertPrice, alertNote, alertEarlyPoints, levelColor, levelWidth, addPriceAlert, armTool, selectTimeframe, allEnabled, toggleGroup, deleteSelected, deleteLine, toggleDrawingSelection, toggleSelectAll, toggleSelectedVisibility, renameLine, updateLineStyle, updateLevelNumber, setArmed, commentText, commentFloat, comments, drawings, filteredDrawings, drawingFilter, drawingKind, deleteDrawing, toggleComment, togglePinned, chooseSymbol, toggleSymbolPanel, startSymbolDrag, dropSymbol, optionExpirations, optionExpiryId, optionSide, optionMode, optionMin, optionMax, optionContracts, optionUnderlying, optionBusy, optionError, optionSearched, optionCopied, onOptionsToggle, searchOptions, copyOption }; + return { status, price, sessionOpen, quoteChange, animateCurrentPrice, autoScrollLivePrice, barAge, dataUpdatedAt, buildStamp, timeframe, timeframes, drawingColors, drawingColorRows, drawingColorName, colorRowLabels, symbolChoices, selectedSymbol, symbolColor, symbolScale, symbolScales, symbolPanelOpen, prefs, clusters, clustersByPrice, events, diagnosticMode, captureBusy, captureDiagnostic, armedTool, drawName, drawColor, drawWidth, drawSide, snap, selectedDrawing, selectedDrawings, manualLines, hasDrawingSelection, allShownSelected, selectedAreHidden, alertPrice, alertNote, alertEarlyPoints, levelColor, levelWidth, addPriceAlert, armTool, selectTimeframe, allEnabled, toggleGroup, deleteSelected, deleteLine, toggleDrawingSelection, toggleSelectAll, toggleSelectedVisibility, renameLine, updateLineStyle, updateLevelNumber, setArmed, commentText, commentFloat, comments, drawings, filteredDrawings, drawingFilter, drawingKind, deleteDrawing, toggleComment, togglePinned, chooseSymbol, toggleSymbolPanel, startSymbolDrag, dropSymbol, optionExpirations, optionExpiryId, optionSide, optionMode, optionMin, optionMax, optionContracts, optionUnderlying, optionBusy, optionError, optionSearched, optionCopied, onOptionsToggle, searchOptions, copyOption }; }, }).mount('#app'); diff --git a/static/index.html b/static/index.html index cd20dae..d1c358e 100644 --- a/static/index.html +++ b/static/index.html @@ -35,7 +35,7 @@ - UPDATED {{ dataUpdatedAt }} + BUILD {{ buildStamp }}UPDATED {{ dataUpdatedAt }}