Default the legacy execution-disposition preview to recently created issues, keep an explicit --all escape hatch, and cover the lookback behavior with a targeted test.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Default the legacy execution-disposition preview to a 48-hour lookback and require --all for full historical scans. This keeps repair passes from treating stale blocked/review rows as current cleanup work unless the operator explicitly asks for a backfill.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The board accepted the canonical executionDisposition payload + classifier
but found the visible badges in IssueRow / IssueProperties / Storybook too
noisy on production surfaces. UI-only walkback: keep the data layer, drop
every visible badge.
- Delete IssueDispositionBadge component and its test.
- Drop the badge import, suppression rule, and trailing-slot references in
IssueRow (desktop + mobile). Existing waiting pill, status-icon ring, and
blockerAttention copy remain unchanged.
- Drop the badge IIFE and related imports from IssueProperties so the
Status row only renders the StatusIcon again.
- Prune the badge cases from IssueRow.test (Live, Stalled, dispatchable,
Resuming, explicit-waiting suppression) so the file still type-checks.
- Storybook: remove "Canonical disposition badges" and "IssueRow with
disposition badge inline" sections plus DispositionRowSurface and
dispositionRowFixtures. The rest of Status Language is unchanged.
Kept: executionDisposition on issue payloads, the resolver and its test,
and the PAP-2818 contract doc — future features can consume the field
without re-running the classifier work.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Align CSS max-height with MENTION_MENU_HEIGHT (208) so the rendered
menu fills the layout-reserved space; previously max-h-[200px] clipped
the box 8px short of the JS layout budget, leaving a visible gap above
the caret line on the flipped path.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Drop the dispatchable "Ready" variant from the badge: the only place it ever
rendered was Storybook (IssueRow and IssueProperties already returned null
for it). dispositionCategory now returns null for dispatchable.
- Pull agent_continuable into a discrete "Resuming" category with a muted
indigo treatment so it doesn't share the rose alarm family with Recovery /
Needs attention / Stalled, and surface "Resuming · n/m" on the visible
badge instead of hiding the attempt counter in the tooltip.
- Differentiate human_escalation_required by owner on the visible label:
Needs board / Needs manager / Needs owner / Needs external. Color stays in
the rose family but the actionable bit is no longer hover-only.
- Bump invalid (Stalled) to a solid rose-600 fill so it stands out against
the rest of the rose family at scan distance, satisfying the parent plan's
acceptance criterion that the board can spot a stalled review leaf without
reading the full thread.
- Mirror the IssueRow suppression rule on IssueProperties so the Status row
doesn't double-render the same waiting/recovery signal as the chat-thread
IssueBlockedNotice.
- Add aria-label={tooltip} on the badge so screen readers get the path
detail, not just the category label.
- Storybook: rename and split the disposition matrix to cover all four
escalation owners, both Resuming attempts, and add a populated IssueRow
surface that shows the badge in production layout context (Live, Resuming,
Needs board, Needs manager, Stalled).
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Mention menu now sits on the same line as the caret and to the right of
the cursor (tracking each typed character instead of staying glued to
the @ marker). When the menu would overflow below the viewport it flips
above the line so it doesn't cover the line.
Touch handling no longer preventDefaults on touchstart, so the dropdown
scrolls natively on mobile; selection runs only on touchend if the
finger lifted with negligible movement (a tap, not a scroll).
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Adds IssueDispositionBadge that maps the canonical disposition to a
small palette of categories (live, ready, waiting, blocked-chain,
recovery, needs attention, stalled). Renders the badge in the inbox
row and on the issue detail status row, suppressing it where the
existing waiting/recovery copy already conveys the same signal so we
don't double up. Storybook gains a section showing every category for
UX review.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Adds a per-issue read-model resolver that loads the disposition state
vector (active runs, queued wakes, agents, interactions, approvals,
recovery/productivity-review issues, latest run evidence) and runs the
shared classifier. Wires it into issue list, detail, and
heartbeat-context responses, and surfaces it on the shared Issue type
as `executionDisposition` so the board can read execution health
without inferring it from status alone.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The explicit-wait IssueBlockedNotice rendered Target/Owner/Resume as a row
of pills. Drop the Target pill entirely and render the remaining Owner and
Resume entries as a plain dl/dt/dd block — the value matters more than the
chip styling for these long-form details.
The "Jump to questions/confirmation/approval" affordance referenced anchor
ids that did not exist in the DOM (`issue-thread-interaction-{id}` and
`issue-approval-{id}`); the actual anchors are `interaction-{id}` and
`approval-{id}`. Switch to those ids and use a button with
scrollIntoView({behavior:"smooth"}) so the jump actually scrolls to the
target.
Add a small ExplicitWaitingJumpAnchor component that flips the arrow ↑/↓
based on whether the target is above or below the banner, recomputing on
scroll/resize.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The Target/Owner/Resume chips in the explicit-wait IssueBlockedNotice
banner used inline-flex with `truncate max-w-[Nrem]` on inner spans, so
on narrow viewports a single chip (especially Resume's full sentence)
extended past the container edge. Cap each chip at max-w-full and let
the value span wrap on word boundaries; desktop layout is unchanged.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Wraps fenced code blocks in MarkdownBody with a relative container and an
absolute-positioned Copy button (top-right) that copies the block contents
to the clipboard via navigator.clipboard with an execCommand fallback for
non-secure contexts. The button is hidden by default and reveals on hover
or focus, swaps to a check icon and "Copied\!" label for ~1.5s after
clicking, and falls back to "Copy failed" when the clipboard write throws.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Replaces the rose liveness-break banner for issues whose blocker-attention
read model reports `state="covered"` with `reason="explicit_waiting"`.
- IssueBlockedNotice: add a sky-toned banner with Hourglass icon, kind-aware
headline/body copy (plan confirmation, user response, suggested tasks,
board approval, generic fallback), Target/Owner/Resume pill row, a "Jump
to confirmation" anchor, and a sky chip strip for parent-of-leaf chain
waits. Rose banner still wins on tie via the existing precedence.
- StatusIcon: add a sky ring + bottom-right nub for explicit_waiting and
emit `data-blocker-attention-state="explicit_waiting"`. Tooltip is
"Waiting on board/user/agent" or prefixed "Blocked · ..." when blocked.
- IssueRow: add a sky `Waiting · {owner}` pill (collapses to `Waiting` on
mobile) when the row's attention reason is explicit_waiting. Owner label
resolves via new optional agent/user maps wired in by IssuesList & Inbox.
- IssueDetail/IssueChatThread: lift the linkedApprovals query into the chat
tab and pass interactions/approvals/agentMap/userLabelMap/currentUserId
through to the new banner.
- Storybook + tests: extend coveredBlockedMatrix with sky cells, add four
new BlockedNotice fixtures (plan, user response, board approval, chain),
and cover the new states with unit tests on StatusIcon, IssueBlockedNotice,
and IssueRow.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The user reported having to click Jump-to-latest ~10 times before the
viewport actually pinned to the latest comment on long threads (e.g.
PAP-2536). The virtualizer estimates 220px per unmeasured row, so
totalSize is hugely underestimated until rows render and get measured;
a single smooth scroll lands above the real bottom and each subsequent
click walks closer as more rows mount and expand.
- IssueChatThread.handleJumpToLatest now awaits an optional
onRefreshLatestComments before resolving the latest target so any
comment that arrived after the initial load (or was dropped on a
live-update reconnect) is in the loaded set first.
- scrollToLatestCommentWithSettle issues the initial smooth scroll,
then on an 80 ms tick re-issues scrollIntoView({ block: "end" }) on
the latest comment row for up to 4 s, exiting once the row's bottom
matches the scroll container's bottom (within 4 px) and scrollTop +
scrollHeight have been stable for 3 ticks. If the row hasn't been
mounted into the virtualizer buffer, scrollToIndex is used to nudge
the offset until it is.
- IssueDetail destructures `refetch` from the comments useInfiniteQuery
and threads refetchLatestComments through to IssueChatThread.
QA verified on PAP-2720: single-click convergence in 327-407 ms across
5 successive trials, comment-fa353646 lands flush with the viewport
bottom (-0.44 px sub-pixel), stopped-scroll stability holds.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Suppress bounded run-liveness continuation wakes when an active pause hold
covers the issue, and cancel due scheduled retries with errorCode `issue_paused`
instead of promoting them only to be cancelled at claim time. Adds regression
coverage for both gates plus the no-pause-hold passthrough invariant.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
StatusIcon adds an AlertTriangle overlay on the red-ring blocked variant
when the read model reports recovery_needed; tooltip and aria-label
spell out the liveness break and which leaf is invalid.
IssueBlockedNotice gets a rose container variant with two copy
templates: parent-perspective ("paused at a liveness break in [leaf]")
and leaf-perspective ("productive run that exited without queueing a
continuation"). The sub-row label flips to "Liveness break at" and an
owner pill renders with the next-action verb derived from the
nextActionHint.
IssueRow surfaces "liveness break at {leaf}" in the meta line for
recovery_needed parents so inbox/MyIssues rows show the actionable leaf
without opening the parent.
The status-language Storybook matrix gains the four new state/reason
combinations and parent/leaf-perspective notice variants. Targeted
vitest cases cover both the icon overlay and notice rendering.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
A blocked parent like PAP-2089 currently reports a generic
needs_attention chain even when its leaf is the productive-run-stopped
shape from PAP-2674's plan. Extend listIssueBlockerAttentionMap to
fetch each candidate leaf's latest issue-linked succeeded run plus its
productivity-review state, classify the leaf as recovery_needed when it
matches the shape, and propagate the leaf identifier, next-action
owner, and CTA hint up to the root. The leaf itself also surfaces
recovery_needed on its own attention so the leaf-level notice can
render when an inbox wake lands directly on it.
Adds two integration cases (productive_run_stopped and
continuation_exhausted) to the embedded-Postgres regression suite.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Phase 5 of the liveness plan needs the blocker read model to distinguish
a "productive run stopped without continuation" leaf from generic
attention or stalled-review chains. Extend the shared type so server and
UI share one vocabulary for the new surface (state, reasons, owner,
hint).
Co-Authored-By: Paperclip <noreply@paperclip.ing>