UI implementation - HULKs/labello GitHub Wiki

UI implementation

LabelloApp composes explicit feature state. It does not dereference implicitly to workflow state. Read UI design for presentation and acceptance, and architecture for crate boundaries.

State and requests

Owner State
runtime API transport, command queue, responses, active requests, repainting, persistence scheduling, presence
auth Sign-in options, session discovery, server prelabel availability, failures, account-bound recovery, global preference loading and legacy choices
datasets Dataset metadata/users, statistics, leaderboard selection, dataset request identities
admin Filters, snapshots, roles, staged configuration, export
import Wizard, source registration, planning, durable job progress
navigation App drawer, statistics modal, focus restoration
work Assignment, annotation, review, migration, canvas, edit history

Closed UiCommand and UiMessage enums define the async boundary. The live loop checks request ownership before delegating to feature reducers and dispatchers. live/ownership.rs owns request IDs, auth/workspace/import epochs, command rollback, stale-response rejection, and prepared-assignment cleanup. Feature reducers use that gate rather than introducing their own. Each frame starts up to eight already-queued requests in order. Dependencies still enter the queue only after their prerequisite response; background refreshes do not add a frame each before item activation. The bounded batch leaves rendering time for the UI.

Initial authentication requests sign-in options and the current session in parallel under one request identity. The reducer publishes the session only after both responses arrive and sign-in options succeed. Dataset and preference requests then use the restored session. Browser bootstrap starts discovery before graphics initialization and the first layout; endpoint changes and logout invalidate the combined response through the central request gate.

During browser startup the existing HTML loading placeholder remains visible while the shared reducers, refreshes and persistence queues restore the initial workspace. The UI skips intermediate login/catalog layouts until the session, dataset, assignment and draft recovery settle. It then renders the workspace or the applicable sign-in, empty or failure state. An already-ready image does not wait for a background availability refresh. Later navigation uses the usual retained UI and loading bars. Startup waits for browser draft readiness only while the assignment lease is valid; an expired assignment remains visible through the usual work UI.

The app bar uses the bundled 256-pixel PNG copy of the SVG app icon and caches one texture per egui context. This keeps SVG parsing and rasterization out of the browser client. The SVG remains the favicon and loading-placeholder asset. To regenerate the PNG from the SVG with ImageMagick, run convert -background none assets/labello-icon.svg -resize 256x256 -strip PNG32:assets/labello-icon.png.

Structured unauthorized failures survive dispatch. After an accepted failure is reduced, the root coalesces a session recheck. Recovery blocks work commands and hides account-scoped content while retaining the draft for its original account. A different account replaces the workspace. Endpoint replacement clears account, dataset, import, and pending ownership before new requests start.

Rendering boundaries

glossary.rs owns canonical presentation names and definitions; glossary/shortcuts.rs maps persisted action IDs to those names and their contextual help. Renderers share that catalog in both WASM and the native inspector. See the product glossary.

Module Responsibility
setup.rs Login, advanced connection, pre-authentication About, dataset setup and schema-copy preview
panels/app_bar.rs Measured global navigation, expanding collapsed-header dataset identity, bounded presence, grouped navigation drawer; remains visible during loading
panels/loading_bars.rs Scoped retained bars and validated inspector context during image loads
app/shell.rs Layout, persistent bottom action panel, resize repaint
panels/workspace.rs Canvas area, second-bar context, canvas controls
panels/workspace_actions.rs Workflow commands at every width, unified Previous and Skip
panels/workspace_overflow.rs Action measurement, visible prefix, overflow focus and command identity
panels/task_selector.rs Task selection; workflow_marker.rs owns reason icons and the committed-workflow marker
panels/inspector.rs, panels/prelabels.rs Context details, annotation controls, filtered suggestions
prelabel_flow.rs, live/prelabels.rs Admin runs, reset, model checks and managed hint presentation
prelabel_review.rs Pending editable prelabels, confirmation/deletion, sequence selection and progress; shared annotation history and browser drafts retain local changes
panels/review_context_bar.rs, review_context.rs Measured inline/stacked context summary, compact progress presentation and height; exact review target identity, type, phase and version
panels/overlays.rs Tutorial, recovery, transitions, settings, discard decisions
review_corrections.rs Accumulated drafts, canvas previews, immutable retries, object/disposition editing
review_revision.rs Locally staged replacement decisions and stable commit retries
missing_objects.rs Read-only historical location evidence and browser exit warning
manual_migration.rs Migration cursor, discovery focus, companion reconciliation
workspace_canvas.rs Adapter from app state to reusable canvas
statistics.rs, statistics/leaderboard.rs Statistics modal, periods/ranks, podium, history and activity
statistics/streak.rs Daily flames and reduced-motion-aware goal animation from domain streak projections
avatar.rs, statistics/avatar.rs Shared bounded public-avatar cache and contributor rows
dataset_inspector Gallery, filters, preview scheduling, read-only canvas, return-to-review draft

panels/loading_bars.rs scopes retained presentation to auth/workspace epochs, view, dataset and selected workflow. It stores only display data and migration action descriptions, never assignments, image state, drafts or command ownership. Shell rendering refreshes it after accepted responses and navigation. Loading disables retained controls and keyboard actions without reducing the opacity of the containing panel or image. The shell applies the same rule to pending navigation; actual confirmation dialogs retain their modal backdrops. Empty/error completion and scope changes discard the presentation. The global app bar is outside this blank/retained policy.

Same-view next/previous navigation retires assignment and request ownership while retaining the image fields for display. work.retired_image marks those fields as non-actionable. It never retains an active assignment. Work synchronization, hint polling, canvas edits, panel actions and shortcuts cannot use retired work. The accepted image response replaces the display together; an empty result, failure, or scope change clears it. A settled-view marker keeps retries and later availability checks silent even after an empty or failed result. Scope changes reset that marker. Inspector loading presentation uses the last validated ReviewContext, while live target validation remains unchanged. Statistics, Setup lists, admin image/backup catalogs and incremental inspection pages retain loaded data without routine refresh indicators. Errors, retries, explicit filter changes and operation progress keep their existing feedback. Inspect stages subsequent image pixels and annotation state in one replacement until both requests succeed. The displayed identity, texture, state and canvas change together; same-image refresh preserves pan and zoom. Replacement failures keep the previous display and retry target. New selections and auth suspension cancel obsolete requests. Return-to-review actions remain disabled during a replacement. Admin distinguishes refresh requests from saves; an empty loaded Setup catalog remains settled during refresh. About retains server identity while checking it again, but the browser reload coordinator waits for the new response before preparing or navigating. Import job status polls remain silent while explicit operation progress remains visible.

canvas.rs keeps public entry points; rendering, painting, interaction, hit-testing, and viewport geometry remain separate internal concerns. Painting owns the shared keypoint/stroke policy. Rendering exposes the same projected states through AccessKit without image coordinates. Gesture tests stay with the canvas. The workflow reducer retains every persisted annotation ID, including deleted versions; Undo/Redo rebases a restored object on its latest version. Later keypoint autosaves mark an existing skeleton as a new human-edited revision. Non-submitting annotation saves retain an operation-scoped background marker. Workflow selection, local annotation edits, prelabel confirmation, and companion guide navigation remain available while saving; transaction guards still prevent overlapping save, submit, or release requests. A workflow change stages the normal confirmation and waits for the save before committing a transition. Save replies preserve newer local edits through the edit generation check. Annotation reconciliation copies immutable origin, object group, creation time, workflow, and annotation type from persisted state before comparing drafts and rebasing versions. This also applies to Undo/Redo and browser recovery, so a snapshot taken before prelabel acceptance cannot replace server provenance. Routine saves use periodic statistics refresh; completion requests an immediate refresh.

Browser build recovery

build_information owns mismatch recovery decisions and the generation gate for asynchronous preparation. Its browser adapter in labello-wasm owns the per-tab attempt marker, fresh asset requests, and navigation. Native UI has no reload adapter. The existing endpoint-owned identity request gate remains authoritative.

The shell queues current drafts and writes preferences before advancing recovery. The persistence owner confirms that those writes have committed. Recovery waits for active commands, gestures, and unrecoverable staged input. Asset preparation never navigates; the shared owner checks current work again after it completes, so edits made during asset downloads must also be saved. Once navigation starts, the shell shows Updating Labello... and accepts no further edits. Recovery does not release assignments or change auth/workspace epochs. Failed preparation retains the app and exposes manual retry in About. See deployment for the cache and attempt-limit contract.

Browser input

apps/labello-wasm/src/pen_input.rs normalizes browser pen Pointer Events before eframe's mouse/touch compatibility listeners. Its browser-only app wrapper feeds egui pointer events to the unchanged LabelloApp, including synchronous press/release processing for browser user activation. It owns pen capture, cancellation, duplicate-event suppression, and separate finger touch events. pointer_input.rs retains the adapter's pointer identity and canvas hit region. Shared scroll areas consult that identity to keep pen presses out of drag-scroll; pen ownership also suspends egui's touch long-press timeout and restores the configured timeout when a mouse or finger owns the pointer again. This prevents active finger contacts from stealing a held pen's widget drag ownership. Canvas gestures allow independent pen editing during two-finger navigation. Annotation policy and persistence remain in the shared canvas and workflow owners. See the stylus input contract for evidence boundaries.

Browser persistence

persistence.rs composes record validation, normalized storage identity, retry queues, restore orchestration, completion handling, IndexedDB, local storage, and an in-memory test store. Server and user identity scope keys. Applying a response or draft requires its complete identity and current workspace to match. Browser storage is recoverable convenience; server assignments and events remain authoritative. No second client domain model, offline authority, or synchronization framework belongs here.

Pending prelabel objects are projected into the normal canvas and object selector, but remain outside work.annotations and annotation save commands. Confirmation transfers one object's edited geometry and its original signed evidence into the annotation draft. Deleting a pending box marks its local object deleted, hides its canvas geometry, and preserves selection and view until explicit confirmation records the dismissal and advances. Pending skeleton deletion still advances immediately. The normal history snapshot includes pending objects, so Undo/Redo retains their geometry, pending deletions, and selection. Browser annotation drafts store pending objects in a separate optional field and remain recoverable after autosaving confirmed work. Older drafts default to no pending objects; older clients cannot mistake the separate field for accepted annotations. Model and generation checks gate visibility and confirmation after recovery. Submission cannot bypass visible pending objects. The retained workspace bar presentation includes the current confirmation action and object progress.

Working-preview decoding in image_transfer/browser.rs runs asynchronously in the browser after the client's encoded-size and dimension validation. The bitmap is closed even if pixel conversion fails. Cancelled transfers cannot install a texture or refill a newer workspace's preview cache. Native inspection keeps the Rust decoder; browser failures do not fall back to another representation.

Assignment navigation and review

Annotation and Review share the measured two-line context summary and centered canvas-control layout. Workflow and Inspector toggles stay at the left and right edges. Each workflow projects its own progress, type and class into retained bar presentation; image transitions retain the summary and control geometry together. Review additionally shows the submission author avatar. The summary is passive text. Panel toggles own Inspector opening and focus return. Profile presentation loads with review images through get_review_submitters and the existing request/epoch gate. It matches image, workflow and authoritative submitter ID before using public profile data. Ordinary review uses ReviewRound.submitted_by; migration review uses the current confirmation author. Profile-request failure falls back to the known submitter ID without blocking review. Missing submission provenance reads Submitter unavailable. Retained image-loading presentation includes the avatar and attribution, and is cleared with the same view/workflow/account scope as the rest of the bar.

app/support.rs consumes completion shortcuts including their repeat events, but dispatches only fresh key presses. app/shortcuts.rs applies this to NextImage, review approval/rejection, and prelabel acceptance/discard. The egui held-key state survives item changes, loading, errors, and modal guards; no per-item cooldown or rearming is used. After shortcut dispatch, app/shell.rs removes repeated Space/Enter events before focused controls render, including dialogs and overflow menus. Text editing retains repeat input, as do unrelated shortcuts. Pointer controls retain their normal single-click activation.

app/transitions.rs gates view, About, and workflow changes. Untouched work releases before navigation; failure keeps the workspace. Pending navigation blocks edits and further transitions. work.assignment_touched records edits, decisions, correction input, migration placement/exclusions, and recovered drafts. Saving, undoing, discarding, or reloading the same assignment does not clear it. A new assignment resets it. Selection, pan/zoom, and target inspection alone do not set it.

Previous review first reopens and loads the previous assignment, then releases the displaced one. Releasing first would make the displaced review the latest terminal assignment. The current image stays visible while opening; accepted confirmation closes its modal but keeps conflicting actions blocked until completion. Errors preserve current work. Statistics uses its separate assignment-preserving modal.

Normal, migration, and revision review share the correction owner for item position, validity, local decisions, navigation, reset, and overview eligibility. Opening an editor is not a correction. Actual differences enable rejection and amber previews. NextImage, Space by default, approves an unchanged item or submits a valid correction. Y/N actions use the same owners. Objects corrections submit immediately; Overview submits its image changes together. Historical whole-image revision approval remains staged. Reset invalidates the affected decision. Unchanged items still require approval, even when other items have corrections.

Migration review queue items submit through the shared item-review command using the server-captured target, including Overview. Only legacy whole-image migration assignments use positional migration-review target selection and its endpoint.

Overview additions retain editor and undo history after completion. The next blank canvas placement starts another object. Reopened or recovered completed additions are staged before another starts; editing an earlier point in an unfinished skeleton does not overwrite it on placement. A selected positioned keypoint can toggle Visible/Hidden; hidden placement resets to Visible after use. Delete annotation discards the selected local addition as a whole, with text-focus, busy-state, and overlay guards. Invalid additions block confirmation.

Objects review projects a migrated skeleton's source box as a read-only guide, including automatic focus and Refocus. The guide never enters editable annotation state or selectable canvas IDs. Excluded-object review exposes Create skeleton for excluded object in the bottom action bar, with a skeleton-plus icon when the label does not fit. The Inspector retains exclusion-reason editing.

Each item submission sends its scoped correction batch. Workflow assignments use the loaded state's review round and target fingerprint; historical assignments retain their captured review context. Missing context reports a recovery action and preserves staged corrections. Failure retains an immutable retry request. The server preserves unchanged approvals and requires Objects review for additions and Overview review for edited images. Review context is derived from exact assignment and target identity, never stale display state. Completed migration review retains its outgoing position until replacement or clearing; it does not restart review.

Migration and companions

Direct revisit uses the audited server command and returned cursor. Busy state blocks duplicate activation; discard confirmation preserves a draft until the new target is accepted. Failed opens/saves reuse stable retry identity. Canonical save conflicts require discard confirmation before reloading. Returning focus selects the overview entry or compact full-image action. The server chooses confirmation or outstanding dependency work; the UI does not override it. Historical passes resume the latest pass's outstanding decisions, with no new global pass-start control. Discovery editing and companion reconciliation retain their separate drafts and transaction rules.

companion_guides.rs projects untouched, unreviewed companion boxes as their exact source keypoints in Annotate. The projection retains the box ID for selection but never enters annotation state or save payloads. Drawing revises that box through the normal edit/history/save path. Existing reviewed or edited boxes remain boxes, and missing historical sources fall back to ordinary editing. The annotation primary action advances through pending companion guides, saving the current box without completing the assignment and focusing the next guide. Only after all guides are drawn or deleted does it submit the image. Explicit whole-assignment transition submission still requires every guide to be resolved. Keypoint-guide focus permits a small canvas margin at image edges so corner markers remain visible; it does not change annotation coordinates. Box creation uses a three-canvas-point minimum per dimension, rather than a fixed fraction of the image. Geometry clamping uses only a numerical floor, so small boxes are not enlarged when rendered, hit-tested, or edited at deep zoom. Workspace preferences are not overwritten while dataset/assignment loading or restoration is pending, so a restored deep view survives asynchronous browser startup.

Automatic annotation focus is limited to pending/accepted prelabels and migration companions. Manually drawn boxes keep the current zoom and pan even after prelabel review has started; existing explicit Refocus remains available during prelabel review.

Bounding-box assignments without a restored selection select their first visible migration companion. Focus occurs once per activation of an annotation identity, not each version, autosave, or manual pan/zoom. Selecting another object and returning refocuses it; R can explicitly refocus. View padding never changes geometry or provenance. Migration canvas preparation initializes skeleton drafts independently of Inspector visibility.

Images and reservations

live_workflow::load_working_preview uses Data Saver v1 for loads, retries, reopen, reload, and prefetch. Failures never request Standard, legacy RGBA, or original bytes. Native and WASM decoding use the same bounds and geometry. image_transfer owns cancellation; existing request epochs reject stale replies. It also retains up to eight decoded working previews, bounded to 32 MiB, by dataset and immutable image identity. Auth/workspace invalidation replaces the cache, so late transfers cannot repopulate the new scope. Reusing pixels still reloads image metadata and authoritative state and requires display validation. Old :data-saver preferences are ignored. The dispatcher requests another frame while commands remain, including after discarding superseded requests.

Claims finish independently of image cancellation. Cleanup retains dispatched load ownership across invalidation until replies are reduced, because repeated claims may share an assignment ID. Current/prepared work and queued commands retain their exact reservation. New loads wait for pending releases; stale and failed-prefetch cleanup use the original API instance. Activating an image removes its assignment from the prepared queue and drops same-image leases that the fresh state explicitly marks finished or cancelled. Unknown newer reservations remain queued. These removals do not release the active assignment or send redundant releases for already ended leases.

The dataset's preloadQueueSize owns the annotation/review target. Resizing returns surplus reservations to the centralized cleanup owner. Prefetch uses the existing claim request with prefetch: true; a denied claim loads no image data. The claim response distinguishes an imbalance limit from unavailable work. The workflow tooltip always retains the loaded/target count and appends (imbalance limit) for a balance pause. Expected pauses retain background retries without appearing as load failures; transport or image-load failures retain their failure status. Availability replies carry queue size and optional eligible reservation IDs. A reply prunes only reservations captured by that request, so a delayed snapshot cannot discard a newer preparation. Current work and its draft are independent of queue reconciliation. Prepared lease deadlines use elapsed time from claim dispatch rather than the browser's wall clock. Promotion discards expired entries, and review retains its existing authoritative revalidation.

Statistics and presence

Statistics data and requests belong to datasets; visibility and focus belong to navigation. Opening or refreshing the modal changes no workspace epoch and preserves work. Legitimate workflow replies continue beneath it. Authentication or workspace invalidation and lost original ownership dismiss it. Recovery takes precedence; companion reconciliation temporarily covers it and then resumes it ahead of ordinary transition dialogs. Resize requests a sizing pass and immediate repaint. Keyboard focus scrolls content into view; fixed headers/popups keep their own placement.

Domain owns scoring; storage selects focus and aggregates. UI never awards points. Background statistics refresh runs every 30 seconds, or every three seconds while the modal is open. Saves, reviews and migration completions request an immediate refresh; in-flight requests coalesce into one follow-up. Existing epoch gates reject stale responses, and expired or failed-refresh focus data is hidden. Dataset-owned state retains period, contributor/history selection, streak sorting and activity day, clamping the day after period changes.

Domain derives streaks from contributor history. statistics/streak.rs renders flames and reduced-motion-aware goal animation. The app-bar flame opens Statistics.

runtime.presence binds samples to endpoint/account, one request, poll timing, and consecutive failures. Every authenticated view polls every ten seconds with an eight-second timeout; visibility return coalesces an immediate refresh. Epoch invalidation clears names without modifying drafts or assignments. Avatar loading shares bounded credential-free public GitHub requests and caches failures. Last-known presence survives one or two failures; three show unavailable until recovery. Annotation and review headers show active users; all authenticated headers show the same connection dot. Green means connected without a pending problem; yellow covers initial checking, one or two failed polls, saving, or unsaved edits; red covers three failures, save failure, or application/storage errors. Hover, activation, and keyboard focus expose the same details. Recovery clears connection failures immediately. Presence has no daily-count footer.

Dataset inspector

Inspect uses closed commands and the shared auth/workspace/request gate. Leaving clears its data and cancels transfers. Workspace preferences restore the destination; gallery filters, scroll state, and return drafts are memory-only. Same-account recovery retains the reason and cancels obsolete reads.

Filters apply before pagination under the API rules. Filter menus recalculate available viewport height each frame and scroll only when needed. Choices keep full accessible names without repeating them in hover tooltips. The gallery loads consecutive metadata batches of up to 100 without waiting for scrolling or previews. Counts distinguish matching images from the loaded list. Pending filter replacement labels the still-displayed previous results; accepted replacement resets the list, and obsolete replies are rejected. Failures preserve displayed results and require Retry.

Virtualized rows allow two concurrent thumbnail reads and 48 cached textures. Offscreen reads are cancelled and removed from request ownership before newly visible previews load. Selected images immediately reuse a thumbnail while state and Data Saver load independently. An uncached selection requests its thumbnail even outside the visible grid. Selected-image previews take priority over new background thumbnails. Previous/next crosses loaded-page boundaries. Pan/zoom and intersecting workflow/status/type visibility never edit annotations.

Boxes and skeletons use class colors. A visible box supplies its object group's label; hiding boxes restores labels on visible keypoints. Labels use screen-space text, bounded two-line layout, full accessible names/tooltips, and canvas clipping. Opaque class-color backgrounds choose black or white text for at least 4.5:1 contrast. Labels start inside the visible box corner when possible and move down to avoid crowding where space permits; a label can exceed a small box's width.

Return-to-review controls remain available in the Overlays panel or drawer for reviewers/data admins. Full-width workflow-name buttons include type icons and selected state independently of overlay visibility. The domain's shared return_to_review_block policy supplies eligibility for boxes and skeletons; adjacent info controls expose exclusion reasons to pointer, keyboard, and assistive-technology users. Imported workflows default to review None, so completed imports need explicit approval configuration before return.

A pending request or entered reason guards navigation until completion/discard. Failure preserves the exact retry identity; refresh prepares a new identity while keeping the reason. Success or discard clears the draft and keeps controls available. Notification delivery is not implemented.

Import, export, and schema reuse

Import owns editable drafts, recovery, source registration, planning, polling, and upload; storage owns durable lifecycle. The all-zero YOLO pose policy is an explicit plan choice, defaults to incomplete, survives recovery, and invalidates accepted plans on change. Its width and acknowledgement stay bounded even when other mapping fields expand the form.

admin.export in export_flow owns saved-metadata selection, job history, summary acknowledgement, and one pending action. Closed export commands/replies use shared auth/workspace/dataset ownership. Invalidation clears state; queue/dispatch failure clears pending state locally. Polling occurs at most once per second while visible. Explicit actions can supersede polls; stale replies lose their request owner. Refresh failure retains stale data and Retry. An uncertain mutation refreshes history instead of blindly creating another job.

Reload restores active/Ready captures only. Terminal jobs stay inspectable in history; changing selection clears old terminal details. Active/Ready jobs require cancellation before another preflight. Start needs unchanged options, saved Admin configuration, a Ready job, and explicit summary acknowledgement. Domain validates local class mapping; server preflight owns completeness and source consistency. Download performs authorization checks and opens the attachment URL without buffering bytes in WASM. UI reports requested download, not transfer completion.

Setup schema reuse has a dedicated preview request without workspace switching. Only the latest selected source can populate it. None clears the preview; a source blocks creation until its catalog entry and preview are available. Failures never implicitly select None. Server creation rechecks source permissions and definition validity. See administration.

Notices and build information

Work owns automatic workflow-change feedback separately from transient errors and saved workflow reasons. An accepted fallback captures old/new task, class and annotation-type identities with the previous workflow's availability explanation. Later refreshes cannot rewrite that text. Missing reasons use the generic unavailable category. The nonmodal notice remains visible after item loading; it does not consume confirmation shortcuts or require acknowledgment. Explicit selection, auth/dataset changes, or leaving work clear obsolete feedback.

workflow_reasons.rs owns image-and-workflow-scoped saved feedback. Assignment load fetches it with state/preview under the same ownership gate; failure fails that load. Only reasons matching both assignment identities are installed; unscoped reasons do not match, and no matching feedback means no notice. Optional public GitHub author identity arrives in the same API response without a Statistics visit. This transport enrichment changes no persisted event.

Newest messages lead and earlier/replaced feedback stays explicit. The event and explanation remain visible, followed by workflow and status. A 24-point avatar and username share a row with the initially collapsed Additional info disclosure; expanded object identity and UTC time use the full width below it. The shared avatar cache and initials fallback avoid repeated downloads; unavailable login reads Unknown author. Message identity keeps disclosure state stable across redraws, and multiple-message counts appear at the bottom. Long explanations scroll; short viewports open full feedback from the event title in a bounded non-modal window. Dismissal lasts for the opened context; accepted reload or reopening installs a new one, and image/workflow/dataset/view changes clear it. Revisiting completed review alone creates no notice.

Return-to-review reasons are not yet included. Object reasons survive navigation and browser recovery by annotation identity; reset/discard clears them. Submission combines labels, separators, and text under the existing 2000-byte limit without truncation, preserving exact retry identity.

build_information.rs owns public endpoint-bound identity requests, comparison, About, clipboard feedback, and the bottom warning. Requests coalesce and admit one completion; endpoint changes invalidate them, while session/workspace changes do not. Refresh clears stale server identity. WASM injects its compiled identity, clipboard promise, and visible-focus adapter; mutable release.json never defines the executing browser's identity. Copy succeeds only after the platform confirms it; failure opens selectable manual-copy text. Mismatch navigation uses ordinary transition guards. No mismatch means no reserved status-panel height.

The primary action in annotation, migration, and review is anchored to the bottom right, after the secondary actions, with the same icon fallback at narrow widths. This includes migration saving and final confirmation, and review approval or correction submission. Compact review puts secondary actions above the decision row.

The bottom action bar remains empty until session, dataset, image, and required assignment are loaded. Background availability refresh preserves loaded actions. Resize measurement requests a settling repaint only when height changes, avoiding input-dependent gaps or repaint loops at unsupported tiny sizes.

admin/prelabel_models.rs renders managed model inspection, named tensor selection and explicit dataset-class mappings. Checks belong to the Admin owner and use the existing request/epoch gate. Replies must also match the current configuration ID and filename. Filename edits, configuration reload, save and discard clear stale inspection state. Rendering stages profile edits; ordinary Admin save remains the publication boundary.

Editing after placement

New annotation boxes stay selected for movement/resizing. Completed skeletons keep their selected annotation and expose per-keypoint Visible/Occluded controls in the inspector when the task permits hidden points. These changes use the same edit history, versioning, and autosave owner as geometry edits. Canvas keypoint selection survives pointer release and is validated against the current editable object before routing visibility changes. Placement retains the most recent point as the editing target; next-point placement mode remains separate.

Review overview box additions retain their correction editor after staging, matching skeleton additions. Further edits remain local until review submission. Blank-canvas placement can start another object after retaining the current one.

Migration annotation previews keypoint placement from primary press through drag, then sends the final clamped position to the workflow on release. Escape, lost pointer input, read-only state, and view gestures cancel the preview. A guided one-keypoint object's blank-canvas press repositions its existing point while preserving its visibility and object identity. Multi-keypoint placement order and explicit guide confirmation remain unchanged.

Migration full-image confirmation starts a missing-object skeleton on a blank canvas press and release and selects existing objects directly. No separate Add missing object or Edit added object buttons are shown in the inspector. The class workflow panel selects the separate Overview queue. After a complete one-keypoint draft, the next blank placement saves it through the existing migration command and starts the next object only after success. Selecting another object uses the same save-before-switch path. The reducer retains the final dragged position in the pending canvas action and the current draft on failure for retry. Multi-keypoint drafts require explicit object confirmation before starting another object. Assignment completion still requires explicit confirmation. Existing objects retain selection priority. Completed drafts remain editable before explicit confirmation, with placed-point visibility controls for both guided and missing-object drafts. These controls preserve migration dirty-state ownership.

Shortcut display names, button-name aliases, category ordering and conflict-context copy live in panels.rs; the settings renderer in panels/overlays.rs uses that catalog for display and search. This presentation catalog does not change domain action IDs, conflict eligibility, dispatch or persisted bindings. Row text receives bounded width before controls, with stacked controls below 600 content points. The existing shortcut draft/save/reducer owner remains authoritative for settings.

Global preferences and statistics scope

preferences.rs owns account preference loading and the legacy-source selector. The existing shortcut draft/save reducer remains the editing owner. Global loads use account-bound requests without dataset identity. Accepted loads preserve an already edited settings draft. Dataset loads do not replace shortcuts; they ensure account preferences have loaded. Workspace/authentication invalidation rejects obsolete requests.

statistics/overview.rs owns the modal's independent scope, request identity, remote state and authorized dataset projections. datasets.stats remains the active dataset projection used by the workspace streak. Scope selection starts no workspace epoch and never replaces work metadata, annotations or assignments. The domain aggregates counts, raw score components and contributor UTC days; rankings, acceptance percentages and streaks derive from that combined history. Matching task/class identifiers remain in separate source-dataset breakdowns. Global views omit dataset scoring multipliers, focus and assignment balance.

The active dataset keeps its existing coalesced refresh path. Other scopes refresh through the overview owner while the modal is visible. Scope changes clear the old view before loading; accepted failures clear overview data because its authorized membership could have changed. Authentication/workspace invalidation clears the overview and dismisses the modal. The global endpoint fails closed rather than returning partial aggregates. Dataset reads are sequential; there is no cross-dataset atomic snapshot or large-server performance guarantee.

Class workflow navigation

In Annotate and Review, panels/task_selector.rs groups enabled one-class tasks under their class identity. Each class is a heading followed by one row per activity: bounding-box annotation, migration, and direct skeleton annotation when applicable. Every row places its passes in two right-aligned columns, Objects and Overview, whose names appear once in workflow_pass_header. The panel and drawer hosts render that header outside their scroll areas. Unsplit workflows use only the Overview cell and keep an Annotate or Review accessible name. Review uses bounding-box and skeleton review activities and retains its existing task-transition and correction guards. Unconfigured activities take up no rows. Multiple tasks within one activity become indented rows with wrapped task names and their own pass cells under a shared activity heading; there is no chooser. Every pass cell acts directly. The shared workflow selection guard supplies both disabled state and its reason icon for every pass cell. Phase restrictions, all blocking loads, saving, migration updates, transitions, and modal blocks have state-only tooltips and accessible descriptions. No explanatory text or focus-bonus footer appears beside the cells. The availability retry control sits above the classes. panels/workflow_boost.rs paints the boosted workflow's pass cells without changing layout or native button state. It uses the shared reduced-motion preference, defaults to static rendering without an adapter, and requests frames only during its bounded activation/hover/focus shimmer. The scoring window remains authoritative; failed statistics or expiry remove the cue. Classes are separated by a fixed eight-point gap. The panel width fits the widest unwrapped class heading, activity label or shared-activity task name between 240 and 360 points; longer task names wrap or truncate without expanding the canvas layout, and accessible names include class, activity, and task. Temporarily blocked configured activities remain disabled with an explanation.

Objects and Overview select server-owned queues, not local phases of the current image. Switching saves unfinished input and releases the departing workflow's reservations. Overview eligibility waits for prerequisite objects; the selector cannot bypass that gate. A migration workflow with no focusable sources uses ordinary full-image annotation. Loading, saving and pending transitions retain their guards, and workflow-cycle shortcuts continue selecting tasks.

Work-item presentation

work_items.rs owns Objects/Overview selection, item-scoped editor projection and backward/forward navigation over server history. work_items/edits.rs maps local editors to typed durable proposals and restores them after validated assignment loading. It never treats a browser draft as authoritative completion. Review browser backups contain unsaved edits, not untouched selection or proposals already saved by the server.

The command/reducer path saves partial work before Skip, Previous or departure; failed saves retain the editor and lease. Prefetch identities include the item, so multiple objects on one image remain distinct.

WASM command dispatch polls each request once immediately before handing a pending future to the local executor. Reducer-generated commands start before rendering, and commands from user input start at the end of the UI pass, before painting. This overlaps network work with drawing without awaiting a response in the frame. Background statistics requests retain their ownership in the queue while an image loads; they resume after success or failure. An open statistics view bypasses this deferral. Other commands can pass a deferred statistics request.

History loading performs display revalidation in the same asynchronous operation before sending its result to the UI. The reducer still checks exact assignment identity and current request ownership before activation. Activation records display/seen; prefetch only revalidates. New prefetch requests wait during foreground image navigation and while a forward history item remains. Existing prepared items remain reusable. Continuing a selected workflow can claim the next item while advisory availability refreshes. The server still validates current roles, limits and eligibility. An empty continuation clears the retired image and returns to availability-based workflow routing; initial selection still waits for availability. Reservation cleanup waits for in-flight claims before releasing the workflow. Shared rendering presents one Previous and Skip action. A failed save before Previous, refused Previous request or history display revalidation retains the current workspace and exposes a dismissible navigation error in the canvas notice area, with an accessible alert role. It takes precedence over a workflow-change notice. Retry and workflow departure clear it; stale responses cannot create it.