T7.5 - A6: the sidebar answers the stand-up question

Use case from the task: someone is asked in a stand-up why a package has not
moved; they open it on a phone and need the answer without scrolling or
clicking. The navigator row now carries:

- a triage line: status - priority - due date - P6 activity, with an em dash
  for anything unset (a placeholder is information; a gap is a question)
- the open-constraint count (already in the state chip; on a held row it moves
  into the hold line so it is never displaced by "on hold")
- the hold reason INLINE, from the newest live entry in data.holds - the modal
  captured it at T7.3, so this is display work, exactly as the task said. A
  held package with no recorded entry (legacy data) says "no reason recorded -
  log it from the status control" rather than rendering an empty red slot.

The row's title attribute keeps its hover summary, but hover stops being the
only path to any of this (C1 - Field View runs on tablets). Triage and reason
lines WRAP instead of ellipsizing - an ellipsis would hide exactly the data
the row exists to show; the reason clamps at three lines so one essay cannot
swallow the panel. Rows align flex-start to take the extra height.

At 390px the panel is the existing overlay drawer; the row fits it with no
sideways overflow and stays a >= 44px tap target.

Verification (each probe run alone): NEW tests/triage_check.py 16/16 covering
the held/plain/legacy row matrix at 1440px and 390px. Regression:
frame_check 39/39.

Items: A6

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-19 10:28:02 -07:00
parent 60434d452c
commit 5d27a1e086
4 changed files with 255 additions and 0 deletions

View File

@@ -2247,12 +2247,30 @@ function renderWpNav(){
: (open ? open + ' open' : (waiting ? 'waits on ' + waiting : 'ready'));
const active = (editingId && p.id === editingId) ? ' active' : '';
const title = (p.number || '') + ' — ' + (p.subject || '') + ' · ' + (p.status || '') + ' · ' + state;
// A6: the stand-up answer, inline. Status, priority, due date, P6 activity
// and the open count all on the row; a held package says WHY it is held,
// from the newest live hold entry - the modal captured it, so display it.
// The title attribute above keeps the hover summary, but hover is never
// the only path (C1: Field View runs on tablets).
const triage = esc(p.status || 'Draft') + ' · ' + esc(wpPriorityOf(p))
+ ' · due ' + esc(p.due || '—') + ' · P6 ' + esc(p.p6Id || '—');
let holdLine = '';
if (p.status === 'Issue') {
const live = (p.holds || []).filter(h => h && !h.released);
const h = live[live.length - 1];
const why = h ? (h.constraint ? h.constraint + ': ' : '') + (h.details || '')
: 'no reason recorded — log it from the status control';
holdLine = '<span class="wp-nav-hold">⛔ ' + (open ? open + ' open — ' : '')
+ esc(why) + '</span>';
}
return '<button type="button" class="wp-nav-item' + active + '" onclick="wpNavOpen(' + r.i + ')"' +
' title="' + esc(title) + '">' +
'<span class="wp-nav-badge" style="background:' + wpBadgeColor(p) + '">' + esc(wpBadgeText(p)) + '</span>' +
'<span class="wp-nav-body">' +
'<span class="wp-nav-num">' + esc(p.number || '(unnumbered)') + '</span>' +
'<span class="wp-nav-subj">' + esc(p.subject || 'untitled') + '</span>' +
'<span class="wp-nav-triage">' + triage + '</span>' +
holdLine +
'</span>' +
'<span class="wp-nav-state"><span class="wp-nav-dot ' + dot + '"></span>' + esc(state) + '</span>' +
'</button>';

View File

@@ -882,6 +882,18 @@
body { --nav-w: 288px; }
body.wp-nav-collapsed { --nav-w: 56px; }
/* A6: the triage line and the inline hold reason. These WRAP - an ellipsis
here would hide exactly the data the row exists to show. The hold reason is
clamped at three lines so one essay of a reason cannot swallow the panel. */
.wp-nav-item { align-items: flex-start; }
.wp-nav-item .wp-nav-badge { margin-top: 2px; }
.wp-nav-triage { display: block; font-size: 10.5px; line-height: 1.5;
color: var(--text-muted); white-space: normal; margin-top: 1px; }
.wp-nav-hold { display: -webkit-box; -webkit-line-clamp: 3;
-webkit-box-orient: vertical; overflow: hidden;
font-size: 10.5px; line-height: 1.45; color: var(--red);
white-space: normal; margin-top: 2px; }
/* -- collapse toggle -- */
.wp-nav-top { display: flex; align-items: center; padding: 8px 10px 2px; }
.wp-nav-toggle {