Skip to content

Own visible feedback in each workspace surface #204

Description

@alexeygrigorev

Own visible feedback in each workspace surface

Status: blocked for coordinated release — Slices 1–5 are Tester-passed and PM-accepted; accepted Slices 3–5 are merged in local main through ab0d805, held and unpushed; no shipped/deployed claim
Tags: bug, portal, frontend, testing, design, P1
Depends on: #217 preview/deployment/post-deployment identity gate for coordinated publication; all #204 slice dependencies are complete
Blocks: None
Next owner: Orchestrator after #217 release/identity PASS, for safe coordinated push; then On-Call
Resume condition: #217 completes its HUMAN preview, ordinary main/OIDC deployment, terminal On-Call result, and HUMAN identity verification; then publish the accepted slices without carrying the rejected old #146 candidate.

Scope

Replace the permanently hidden shared .library-heading cluster with honest,
owning-surface feedback. The replacement must cover every legitimate operator
action with pending, durable success, empty, partial, validation, permission,
not-found, conflict, retry, and failure states. Keep authoritative refresh and
canonical-URL behavior intact. Do not introduce a persistent cross-route status
banner or a second global toast system where local state is clearer.

Current baseline is main at bfb5be0 after #201 and #202. The old blockers
are stale: #201/#202 are closed, while #200 remains open and still owns the
hidden .docs-sidebar-only Knowledge/editor work. This issue is therefore
decomposed so the first slice starts without touching #200. The active #205
candidate owns the exact files listed under Sequencing; defer the editor
slice until it lands or its owner explicitly coordinates the rebase.

Implement as focused, independently verifiable slices:

Slice 1: non-Knowledge route summaries

Migrate Home, Tasks, Admin/Users, and Device away from hidden shared status.
Their visible headers, summary strips, queues, tables, diagnostics, forms, and
device authorization panels must carry loading, unavailable, count, validation,
pending, success, conflict, and failure outcomes directly. Remove the setStatus
dependency and calls from these surface modules and their fixtures. The shared
writer may remain temporarily for callers owned by later slices; do not add new
callers.

Primary files: frontend/src/surfaces/home.js,
frontend/src/surfaces/tasks/index.js,
frontend/src/surfaces/tasks/quick-create.js,
frontend/src/surfaces/tasks/recurring.js,
frontend/src/surfaces/work-detail/*,
frontend/src/surfaces/operations/admin.js, and
frontend/src/surfaces/operations/device.js.

Slice 2: Inbox and Assistants mutations

Move intake capture/triage and Assistant creation/lifecycle/draft feedback into
the queue row, detail panel, or form that initiated the action. Preserve the
existing entity routes and authoritative snapshot refresh. A successful mutation
is confirmed by refreshed durable state, not only by disappearing copy.

Primary files: frontend/src/surfaces/operations/inbox.js,
frontend/src/surfaces/operations/inbox-actions.js,
frontend/src/surfaces/operations/assistants.js, and affected contracts.

Slice 3: Task/Card action recovery

Keep Task/Card conflicts in their established focused [role="alert"]
recovery UI, and give generic mutation failures the same owning-panel treatment:
retain the attempted change where valid, announce the error, and offer reload or
retry without routing the decision through a global toast. Preserve optimistic
control disabling, version guards, focus return, and stale-response checks.

Primary files: frontend/src/surfaces/work-detail/task-actions.js,
frontend/src/surfaces/work-detail/card-panel.js, related panel renderers, and
frontend/test/work-detail-surface.test.mjs.

Slice 4: Knowledge list/search/navigation

Only after #200 lands, migrate residual catalog, search, Process Docs, and
document-navigation status writers into their loaded/empty/filter-empty/partial/
unavailable/not-found result states. Partial search keeps successful sources,
names unavailable sources, and offers recovery. Single-document misses remain
distinct from corpus outages. Do not duplicate #200; implement only feedback left
behind by it.

Primary files: frontend/src/surfaces/knowledge/catalog.js,
frontend/src/surfaces/knowledge/search.js,
frontend/src/surfaces/knowledge/process-docs.js,
frontend/src/surfaces/knowledge/navigation.js.

Slice 5: Editor and final shell deletion

Only after #205 lands or its owner explicitly coordinates the boundary, finish
editor-owned feedback and delete the obsolete shared shell mechanism. Save,
create, rename, delete, draft batches, structural-edit misses, and image uploads
report in the editor footer, create form, changes panel, or adjacent media/
section control as appropriate. Remove .library-heading, #status-text,
#library-title, #clear-selection-button, their bindings/CSS/fixtures/browser
waits, setStatus, and the reportError -> setStatus side channel. No alias,
compatibility selector, dual writer, or hidden synchronization point may remain.
Update route-focus fallbacks to a visible owning element and preserve
authoritative refresh/focus.

Sequencing

Acceptance Criteria

  • Every former hidden-status category has reachable text in the surface or
    action region that owns it: loading, empty, filtered empty, partial,
    unavailable, validation, permission, not-found, conflict, retryable
    failure, and durable success.
  • Pending actions identify the operation, prevent duplicate submission, and
    leave controls usable or clearly disabled without trapping keyboard focus.
  • Validation appears beside the affected field/control and moves focus to
    the first invalid control without losing entered data.
  • Conflicts explain that the record changed, retain usable intent/input,
    and provide Review/Reload and Retry or an explicit discard path.
  • Failures appear in the affected panel/form/row, not only in a transient
    global toast. Existing global toasts are removed from migrated flows when
    local state is clearer; no second global toast system is added.
  • Success confirms the refreshed durable result and restores a predictable
    focus target; destructive confirmation and retry flows restore or move
    focus intentionally.
  • Routine updates use polite live-region semantics; blocking errors use
    assertive semantics only where appropriate. States never rely on color or
    position alone.
  • Stale responses cannot overwrite a newer route/action. Refresh and
    back/forward continue to restore the canonical route/entity state.
  • Keyboard-only operation matches pointer behavior. Mobile interactive
    controls meet the 44px target rule, and overlays retain Escape, focus
    containment, and focus restoration.
  • At desktop 1440x900 and mobile 390x844, representative states have no
    clipped controls, overlapping text, layout shift, or horizontal page
    overflow.
  • Browser synchronization uses armed requests/responses or visible
    owning-surface state; no assertion waits on a hidden node.
  • At final completion, production markup/runtime/CSS/bindings and browser
    contracts contain no reference to .library-heading, #status-text,
    #library-title, #clear-selection-button, setStatus, or the
    reportError -> setStatus side channel.
  • Synthetic public-safe data only. No credentials, private links, raw SOP
    content, sponsor/finance context, production writes, provider calls, or
    AWS/data mutations appear in code, fixtures, issue evidence, or screenshots.

Test Scenarios

Scenario: Route summary stays honest

Given: delayed or failing GET /docs, GET /work/api/tasks, and
GET /work/api/cards responses
When: Home or a Tasks section renders and then hydrates or fails
Then: visible summary/count/runtime states distinguish loading, ready, empty,
partial, and unavailable; successful sections remain visible during a partial
failure; no hidden node participates.

Scenario: Mutation failure reaches its owner

Given: armed failures or conflicts on POST /work/api/tasks,
POST /work/api/cards, PUT /work/api/recurring/:id,
PATCH /work/api/users/:id, POST /work/api/intake,
POST /work/api/assistant-jobs, PUT /work/api/tasks/:id, or
PUT /work/api/cards/:id
When: the operator submits, retries successfully, and exercises a conflict
Then: the initiating form/panel/row shows pending and outcome states, retains
input/intent, announces the transition, provides recovery, and the refreshed
server state is authoritative.

Scenario: Search reports partial results

Given: one docs/work search source succeeds and another returns 503
When: unified search completes
Then: matching results remain visible, the failed source is named with recovery,
the result count does not imply complete success, and filtered-empty versus
corpus-empty remain distinguishable.

Scenario: Async ownership is race-safe

Given: a delayed Task/Card/Inbox/Assistant response followed by navigation to a
different canonical route
When: the older response resolves
Then: the newer route remains authoritative, cleanup occurs, and no stale status
or detail overwrites the current view.

Scenario: Removed shell cluster cannot satisfy tests

Given: the final implementation
When: production paths, fixtures, styles, bindings, parity scripts, and browser
contracts are scanned for the removed selectors/functions
Then: no live writer/wait/assertion remains, and route identity/focus assertions
use visible owning elements.

Scenario: Responsive and accessible evidence

Given: healthy, pending, partial/error, conflict/validation, and success states
using public-safe synthetic fixtures
When: Tester captures desktop 1440x900 and mobile 390x844 views
Then: keyboard traversal, screen-reader roles/names, contrast, target size,
reflow, and absence of overflow/overlap are inspected and recorded.

Verification Commands

Run from the repository root for each independently shippable slice:

npm run test:frontend:unit
npm run test:frontend:coverage
npm run test:backend
npm run typecheck:backend
npm run test:e2e:backend

Also run the focused suites for changed surfaces during development, but full
Playwright is mandatory before merge because the shared shell and canonical
browser contracts span surfaces. Known unrelated failures must be reproduced on
the merge base, attributed to an existing owner outside the diff, and accompanied
by passing changed journeys with no new failure.

Final ghost audit:

rg -n 'library-heading|#status-text|#library-title|#clear-selection-button|\bsetStatus\b|reportError\b' \
  frontend/index.html frontend/src frontend/test backend/e2e backend/scripts

At completion there must be no live production or synchronization match. A match
in historical issue text is not implementation evidence.

Capture inspected evidence under
.tmp/screenshots/issue-204/slice-01/ through
.tmp/screenshots/issue-204/slice-05/, using descriptive state/viewport names.
Screenshots supplement but do not replace functional, keyboard, screen-reader,
API, and race assertions.

Out of Scope

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1ImportantbugSomething is brokendesignDesign and UXfrontendFrontend UIportalShared portal shell and UXtestingTests and QA

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions