← Commit history

0.30.2: bar fill is a pure function of the row's current phase

Drew Owens ·5844577023 · ·parent 8343572
4 files changed +60−4
docs/BUILD-NOTES.md+38
@@ -3,6 +3,44 @@ Decisions taken while building, and the places where the plan and the code disagreed. Newest first. +## Build notes, 2026-08-17 (0.30.2, a bar cannot disagree with its lane)++The Drone Project lane showed mixed bar colours, some teal, some blue. Not a+rendering glitch: the bars were telling the truth about a stale value.++**Root cause, traced not guessed.** Sixteen Drone bars had inline+`background: var(--ph1)` while the lane's colour is `var(--ph3)`, and every one of+those tasks had `phase: 5` in the served data, so the phase was RIGHT and the+colour was wrong. Those tasks have a data-file phase of 0 (Workcells, the only lane+that existed when they were made) and a sidecar override of 5 (Drone, where they+were moved). At load `buildRows` paints each bar with `phaseColor(0)` = the ph1+slot; then `applyState` sets `r.phase = 5` and re-homes the row but never touches+the inline colour. Bar fill was set imperatively at build and patched at a handful+of phase-change sites, so a path that moved a phase without touching the style,+`applyState` here and `deletePhase`'s reassign among them, left the old lane's+colour behind. It survived reload because the same sequence repeats every load.++**Fix: bar fill is a pure function of the row's CURRENT phase.** `recolorByPhase`+sets every bar and milestone rule from `phaseColor(r.phase)`, and it runs from the+two choke points every change flows through, `reflowRows` (drag, phase edit,+Alt+arrow, delete-reassign, and the load-time `applyOrder`) and `updateBar`. So a+bar can never disagree with its lane, and the existing mismatch heals on the next+relayout, which every reload performs: measured at 16 mismatched Drone bars before,+0 after a plain reload with nothing else done.++**Both colour kinds, honoured.** `phaseColor` returns an explicit `p.color`+unchanged, which is theme-invariant by the 0.30.0 model, or the `var(--phN)` ramp+slot, which stays a CSS variable in the inline style and so is recoloured by a+theme switch for free. A task moved into a lane takes that lane's EFFECTIVE colour+whichever kind it is: verified a ramp lane imparts its ramp slot, an explicitly+orange lane imparts `#f0883e` to both the rows already in it and a row dragged in,+and a dark-to-light switch moves a ramp bar from rgb(0,184,177) to rgb(0,164,157)+while the orange bar stays put.++Every phase-change path recolours: table phase dropdown, gantt vertical drag,+Alt+arrow cross-lane, and the section editor's delete-with-reassign. Eleven suites+green including the sections and unification sweeps, zero JS errors.+ ## Build notes, 2026-08-17 (0.30.1, the last two data events read like sentences)  `plan.unify` and `plan.freight` were both landing in the changelog as
gantt.html+19−1
@@ -1327,8 +1327,26 @@ function orderKeyMap(){ function reflowRows(){   items.forEach((r,i)=>{r._itemIdx=i;labelsEl.appendChild(r._lDiv);bars.appendChild(r._bDiv);if(r.id&&barEls[r.id])barEls[r.id].idx=i;});   items.filter(r=>r.type==='milestone'&&r._msLine).forEach(r=>bars.appendChild(r._msLine));+  recolorByPhase();   keepTailLast(); }+// Bar fill and milestone-rule colour are a PURE FUNCTION of the row's current+// phase, nothing else. Before this they were set imperatively at build time and+// patched at a handful of phase-change sites, so any path that changed a phase+// without also touching the inline style left the bar showing its old lane's+// colour: a task with a data-file phase of 0 and a sidecar override of 5 was built+// teal-slot and never recoloured, which is the mixed-colour Drone lane. phaseColor+// returns an explicit p.color unchanged (theme-invariant by design) or the+// var(--phN) ramp slot (which the theme recolours for free), so both kinds land+// on the destination lane's effective colour.+function recolorByPhase(){+  items.forEach(r=>{+    if(isDerivedGroup&&isDerivedGroup(r))return;+    const c=phaseColor(r.phase);+    if(r.id&&barEls[r.id])barEls[r.id].bar.style.background=c;+    if(r._msLine)r._msLine.style.color=c;+  });+} function refreshChartGeometry(){   if(prefs.view==='table')return;   layoutMsCaps(); sizeTailroom(); drawDeps();@@ -3448,7 +3466,7 @@ function refreshMsChrome(r){ // restating those too. This used to patch only the geometry and the dates, so a // description restored from the sidecar (or edited in the table) left the bar // hovering the version that was in the data file.-function updateBar(id){const r=items.find(d=>d.id===id),be=barEls[id];if(!r||!be)return;if(r._noteEl)r._noteEl.textContent=r.note||'';const x1=toX(r.start),x2=toX(r.end);be.bar.style.left=x1+'px';be.bar.style.width=Math.max(x2-x1,6)+'px';be.bar.dataset.dates=fmt(r.start)+' → '+fmt(r.end);be.bar.dataset.title=r.name;be.bar.dataset.body=r.description||'';be.bar.dataset.prov=provLabel(r);drawDeps();}+function updateBar(id){const r=items.find(d=>d.id===id),be=barEls[id];if(!r||!be)return;if(r._noteEl)r._noteEl.textContent=r.note||'';const x1=toX(r.start),x2=toX(r.end);be.bar.style.left=x1+'px';be.bar.style.width=Math.max(x2-x1,6)+'px';be.bar.style.background=phaseColor(r.phase);be.bar.dataset.dates=fmt(r.start)+' → '+fmt(r.end);be.bar.dataset.title=r.name;be.bar.dataset.body=r.description||'';be.bar.dataset.prov=provLabel(r);drawDeps();} function closeEditor(){editorEl.classList.remove('show');editorEl.innerHTML='';} function closeMenus(){exportMenu.classList.remove('show');importMenu.classList.remove('show');} 
package.json+1−1
@@ -2,7 +2,7 @@   "slug": "adom-gantt",   "title": "Adom Gantt",   "type": "app",-  "version": "0.30.1",+  "version": "0.30.2",   "description": "Interactive Gantt chart viewer for project timelines, with a table view over the same data. Data-driven, dark by default with a print-friendly light mode, and fully editable in the browser: drag bars to move or resize, multi-select and batch-shift dates, manage dependency arrows inline, reorder rows, filter by phase, and undo. Toggle to the table for every task and milestone as a row with owner, deadline and status, filtered per owner and edited in place. Every edit is recorded in an append-only changelog so an AI can read what a human changed and build on it. Imports JSON, CSV, MS Project XML and Jira CSV; exports JSON, CSV, SVG and a self-contained HTML snapshot.",   "main": "server.js",   "bin": {
page.json+2−2
@@ -2,7 +2,7 @@   "slug": "adom-gantt",   "title": "Adom Gantt",   "type": "app",-  "version": "0.30.1",+  "version": "0.30.2",   "description": "Interactive Gantt chart viewer for project timelines, with a table view over the same data. Data-driven, dark by default with a print-friendly light mode, and fully editable in the browser: drag bars to move or resize, multi-select and batch-shift dates, manage dependency arrows inline, reorder rows, filter by phase, and undo. Toggle to the table for every task and milestone as a row with owner, deadline and status, filtered per owner and edited in place. Every edit is recorded in an append-only changelog so an AI can read what a human changed and build on it. Imports JSON, CSV, MS Project XML and Jira CSV; exports JSON, CSV, SVG and a self-contained HTML snapshot.",   "main": "server.js",   "bin": {@@ -63,4 +63,4 @@     "name": "Drew Owens",     "email": "[email protected]"   }-}\ No newline at end of file+}