- Shift+click now works on #observablehq-toc links, KPI boxes, and [id] elements
- _inferWidgetName detects TOC context and labels suggestions accordingly
- Click handler adds inToc branch alongside existing inSidebar
- _updateMode: 1-second setTimeout before activating highlight mode
so normal Shift+typing doesn't flicker the UI; clears immediately on
Shift release or window blur
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Click handler: sidebar <a> and <summary> are no longer excluded;
e.preventDefault() stops navigation while shift is held
- _inferWidgetName: sidebar-first branch returns nav link text,
section heading text, or "Navigation" fallback
- pageName is "Navigation" for sidebar clicks (not the current page title)
- CSS: sidebar a and summary highlighted (dashed indigo outline + tint)
when shift is held, same as main content widgets
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- improvement-modal.js: API expects `domain` not `domain_slug` (422 fix)
- todo.md: section heading and KPI label renamed to "Suggestions"
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- updateMode() now subscribes to keydown, keyup AND mousemove so the
body class stays in sync regardless of where focus is (mirrors the
pattern from the working modifier-click demo)
- cursor: copy replaces crosshair (matches copy-affordance semantics)
- figure, h2–h4 and [data-widget-name] elements get a dashed indigo
outline + subtle background tint when shift is held, so the user
can see which elements are annotatable before clicking
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
improvement-modal.js:
- Replace contextmenu handler with click+shiftKey check — browser
context menu is no longer intercepted
- Add keydown/keyup/blur listeners: holding Shift applies
.impr-shift-mode to <body>, switching cursor to crosshair
across the entire page as a visual affordance
- Update hint text to "Ctrl + Enter to submit · Escape to cancel"
todo.md:
- New "Improvements" section shows open dashboard-improvement TD items
with a "review →" link to the UI Feedback page
- KPI sidebar row added for open improvement count (indigo when > 0)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- improvement-modal.js: global contextmenu handler that opens a modal
showing page/widget context; submits suggestions as TD items with
debt_type="dashboard-improvement" to POST /technical-debt/
- _footer.md: shared Observable footer that auto-initialises the modal
on every dashboard page
- ui-feedback.md: review/approval page — lists open suggestions with
resolve / won't-fix / in-progress action buttons; archived items shown
below; live-polled
- observablehq.config.js: "UI Feedback" added under Workstreams group
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
EP catalogue (all domains):
- EP-RAIL-001 ep_id patched (schema fix: add ep_id to EPUpdate)
- EP-RAIL-003 (git bare-repo mirrors) and EP-RAIL-004 (offsite secondary
backup) registered from railiance-cluster/docs/backup-restore.md
- EP-CUST-003..007 ep_ids assigned to existing custodian EPs
- EP-CUST-008 (State Hub API auth) and EP-CUST-009 (update_workstream MCP
tool) registered as new custodian extension points
TD catalogue (railiance — first 5 items):
- TD-RAIL-001: backup cron runs as root without audit trail (high/security)
- TD-RAIL-002: k3s kubeconfig world-readable mode 644 (medium/security)
- TD-RAIL-003: no Ansible role unit tests (medium/test)
- TD-RAIL-004: age key extracted via awk — fragile (medium/impl)
- TD-RAIL-005: etcd snapshot retention uncoordinated (low/impl)
Dashboard (T08 + T10):
- Extract API URL and POLL to src/components/config.js; all 15 pages
now import from the shared module (contributions/goals keep custom POLL)
- Shared .kpi-infobox, .filter-bar, .filter-search/.filter-owner CSS
moved to observablehq.config.js head <style> block; removed from 9 pages
- Build: 0 errors, 0 warnings
API (T09):
- progress.py: limit param now Query(100, le=1000) — prevents unbounded
list requests; closes TD-CUST-004 for the only endpoint that had limit
CUST-WP-0004 marked completed (all 10 tasks done).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Move Interventions under Workstreams in the navigator
- Add action-confirm.js: shared modal component for actions requiring a
mandatory comment (survives live-poll re-renders, unlike inline DOM mutation)
- Wire action-confirm into Interventions (Mark done) and Decisions (Resolve)
- Fix Interventions completed section: fetch all tasks and filter client-side
so resolved interventions (needs_human=false) still appear under Completed
- Add docs/interventions.md help page with ? button on the h1
- Replace all hardcoded "Bernd" with "human" across dashboard src and docs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace Inputs.table() with buildEntityTable() across workstreams and
tasks pages. Add click-to-detail modal (openEntityModal) on all entity
list views: workstreams, tasks, extension points, and technical debt.
- New component: src/components/entity-modal.js
- openEntityModal(entity, type) — full-detail overlay (Esc/click-outside to close)
- buildEntityTable(rows, cols, onRowClick) — table-layout:fixed, overflow-safe wrapper
- CSS injected lazily; no separate stylesheet required
- Tables: table-layout:fixed keeps content within the content column;
title col 32%, workstream col 14%, all cells ellipsis + title tooltip
- Cards (EP, TD): onclick → modal; workstream name span gets title tooltip
- Blocked task cards also wired to modal
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New custom element (src/components/help-tip.js):
- Floating card appears on hover/focus, appended to document.body
(position:fixed) so it escapes overflow:hidden in the TOC sidebar
- Attributes: label (bold), description (body), doc (optional
"Learn more →" link)
- Mouse-over-card grace period so the link stays reachable
- Correct viewport clamping (horizontal + prefer-above/fallback-below)
workstreams.md:
- WHI metric abbreviations (DD/BR/SPR/PEP/CDDR) now use <help-tip>
with full name, one-sentence description, and doc link
- Domain breakdown labels show domain-scoped stats (open count,
blocked%, runnable%) and a doc link
- Cycle ⚠ icon upgraded to <help-tip> with explanation
- Removed dotted underline; cursor:help comes from the element CSS
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extracts the TOC-injection pattern into a reusable component:
src/components/toc-sidebar.js
injectTocTop(id, element) — prepends an element to #observablehq-toc,
removing any previous instance with the same id first so reactive cells
can re-inject on each poll without accumulating duplicates.
decisions.md now uses injectTocTop to place a single widget (live
indicator + Decision Health KPI box) into the right-column sidebar,
removing the standalone live-indicator cell and the ad-hoc id/remove
pattern that was previously inlined.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
KPI infobox
- Replace slim kpi-bar with a boxed card (border, shadow, 195–240px) floating
right in a flex header alongside the live indicator
- Rows: avg resolve time (last ≤5 resolved) + avg open age (all open)
- avg open age colored via CSS var --oc: red/orange/black per threshold
- "no open decisions" shown as muted italic when queue is empty
doc-overlay component (src/components/doc-overlay.js)
- withDocHelp(element, docPath) — adds absolute-positioned ? button
that is invisible until the parent is hovered; click opens overlay
- Overlay: fixed backdrop + animated box with iframe; closes on Esc,
backdrop click, or the close button
- CSS injected once via style tag (STYLE_ID guard, same pattern as MultiSelect)
? buttons wired up in decisions.md
- KPI infobox → /docs/decisions-kpi
- Cumulative chart (wrapped in position:relative div) → /docs/decisions-kpi
- Filter & List section header → /docs/decisions-kpi
Reference page (src/docs/decisions-kpi.md)
- Standalone Observable Framework page at /docs/decisions-kpi
- Documents: KPI card (avg resolve, avg open age, color thresholds),
Resolution History chart (cumulative, period→resolution mapping, filter
interaction, timestamp logic), Filter & List (type/status/search, card
age badge, escalation)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds src/components/multiselect.js — a compact dropdown multi-select that is
Observable-compatible (exposes .value, dispatches bubbling input events) so it
works with view(), Inputs.form, and Generators.input without modification.
Component behaviour:
- Closed state: pill button showing "Label: All" (muted) or active selection
(1-2 items shown by name, 3+ shown as "N of M"); blue border when active
- Open state: dropdown with per-item checkboxes + "Clear selection" link
(only visible when something is selected); closes on outside click / Escape
- Styles injected once into document.head (STYLE_ID guard prevents duplicates)
- Uses CSS custom properties for light/dark mode compatibility
Workstreams page update:
- Domain and Status filters now use MultiSelect instead of Inputs.checkbox
- Filter bar layout reduced to a tight inline row (0.5rem gap)
- Owner text filter restyled to match trigger button height
- No changes to filter logic or downstream cells (filters.domain / .status
are still string[] with empty = show all)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>