You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ui(free): make partial outcomes and recovery actions easier to understand #281
WriteLeash deliberately reports per-item outcomes such as APPLIED, UNCHANGED, SKIPPED, CONFLICT, FAILED and NEEDS_REVIEW. These distinctions are safety-critical, but a merchant who sees a partial result may not know what happened, what was not changed, or which next action is safe.
This is a follow-up UX backlog item, separate from the current table/copy polish issues. First inspect the current v0.2.1 UI and avoid duplicating information already shown clearly.
Scope
Results and History outcome summaries
Conflict / NEEDS_REVIEW explanations and next-step guidance
Existing Preview, Resume, fresh Preview and eligible Undo pathways only
Required direction
Explain outcomes in merchant language while retaining the canonical typed status somewhere visible for support/debugging.
For partial jobs, state completed, unchanged, skipped, conflicted, failed and needs-review counts where those counts are available from persisted results.
Give a safe next step per outcome: for example, inspect the item, create a fresh Preview for conflicts, Resume only when available, or review eligibility before Undo.
Never imply a failed or uncertain operation definitely rolled back; never present Undo as a universal rollback.
Keep explanations concise and contextual. Do not add a new workflow or automatic recovery behavior.
Acceptance criteria
Each existing terminal/partial status has a reviewed plain-language explanation.
The UI clearly distinguishes “not changed,” “conflict—preserved,” “failed,” and “needs review.”
Counts are sourced from persisted job/item results, not inferred from percentage or transient browser state.
No new mutation, retry, Resume or Undo is triggered by viewing the screen.
Keyboard, no-JS where applicable, translation, and existing admin/acceptance gates remain green.
Before/after screenshots and tests cover complete, partial, conflict-heavy and NEEDS_REVIEW examples.
Out of scope
No changes to status semantics, journal schema, retry policy, conflict detection, Undo eligibility, APIs, or job execution. Do not promise that external side effects are reversed.
Merge gate
Presentation/copy first. If implementation crosses into execution or persistence, stop and split into a separately approved issue. Open a PR; do not merge or auto-merge. Only @MrDarkRoot reviews and merges; PR_FAST and CI_COVERAGE must be green.
Scope addendum — verified against ui/batch-273-278 head 29669358b2 (symbols, not stale line numbers):
Scope (presentation/copy only, after #284 merges):
Free_Admin::render_job_view() — results summary (job headline + counts from self::result_summary($counts, $state, true)) + per-item outcome cell via self::render_item_outcome($state, $reason, $job_state, $observation). The outcome line is self::item_label($state, $job_state) plus reason/conflict sentence, with typed STATE · reason kept visible via support_details() (collapsed <details><summary>Details</summary>).
Free_Admin::render_history_table() — outcome column self::job_label($job['status']) + self::result_summary($entry['apply'], $job['status'], true), typed job state retained in the same support_details( $job['public_id'] ) cell.
Do not redo#273 columns, #274ul.subsubsub filters, #275 primary panel (render_approve_form() top+bottom), or #276 progress bar (render_progress_bar() + progress_total/processed). Presentation/copy first; execution/persistence requires a split issue and @MrDarkRoot approval.
Required status table (merchant line + keep typed status visible via Details):
Typed status
Merchant line
Typed status source
APPLIED
Changed
item_label() / Details carries APPLIED · …
UNCHANGED
Not changed
Details
SKIPPED (UNSUPPORTED/BLOCKED)
Skipped
Details
CONFLICT
Newer price kept
Details
FAILED
Not changed; needs attention
Details
NEEDS_REVIEW
Needs review; outcome uncertain
Details
Per-row next step (one line, contextual): inspect item; fresh Preview only for conflicts; Resume only when the existing Resume remaining products control is already available; Undo only when existing self::undo_availability() / eligibility already allows it.
Invariants (must hold):
Counts come from persisted Job_Repository::observe() / Undo_Repository job/item rows, never from the progress percent (progress_total/processed are presentation derived from the same counters but not the source for counts).
Viewing the page must not POST Resume, Undo, or Apply — all are authenticated POST with capability + action-specific nonce + typed validation (read-only progress poll never writes).
Never say a failure rolled back, and never call Undo a full rollback — Undo only restores eligible prices that are still safe to restore; later/external effects (does not reverse: orders, completed sales or effects in other plugins and services) remain. The Undo summary keeps Not changed; needs attention / Needs review; outcome uncertain distinct from Newer price kept.
Activity
MrDarkRoot commentedon Oct 14, 2026
Scope addendum — verified against
ui/batch-273-278head29669358b2(symbols, not stale line numbers):Scope (presentation/copy only, after #284 merges):
Free_Admin::render_job_view()— results summary (job headline + counts fromself::result_summary($counts, $state, true)) + per-item outcome cell viaself::render_item_outcome($state, $reason, $job_state, $observation). The outcome line isself::item_label($state, $job_state)plus reason/conflict sentence, with typedSTATE · reasonkept visible viasupport_details()(collapsed<details><summary>Details</summary>).Free_Admin::render_history_table()— outcome columnself::job_label($job['status'])+self::result_summary($entry['apply'], $job['status'], true), typed job state retained in the samesupport_details( $job['public_id'] )cell.Do not redo #273 columns, #274
ul.subsubsubfilters, #275 primary panel (render_approve_form()top+bottom), or #276 progress bar (render_progress_bar()+progress_total/processed). Presentation/copy first; execution/persistence requires a split issue and @MrDarkRoot approval.Required status table (merchant line + keep typed status visible via
Details):APPLIEDitem_label()/DetailscarriesAPPLIED · …UNCHANGEDDetailsSKIPPED(UNSUPPORTED/BLOCKED)DetailsCONFLICTDetailsFAILEDDetailsNEEDS_REVIEWDetailsPer-row next step (one line, contextual): inspect item; fresh Preview only for conflicts; Resume only when the existing
Resume remaining productscontrol is already available; Undo only when existingself::undo_availability()/ eligibility already allows it.Invariants (must hold):
Job_Repository::observe()/Undo_Repositoryjob/item rows, never from the progress percent (progress_total/processedare presentation derived from the same counters but not the source for counts).Resume,Undo, orApply— all are authenticated POST with capability + action-specific nonce + typed validation (read-only progress poll never writes).does not reverse: orders, completed sales or effects in other plugins and services) remain. The Undo summary keepsNot changed; needs attention/Needs review; outcome uncertaindistinct fromNewer price kept.Merge pull request #285 from MrDarkRoot/ui/281-outcomes
docs(marketing): record #279 capture blocked after #281 rebase
marketing: replace v0.1 screenshots with current-build captures (#279)
docs(review): record #282 pass not run after #281 rebase
test(free): record the #282 lab pass on the post-#281 admin (#282)
docs(review): record #282 pass not run after #281 rebase
test(free): record the #282 lab pass on the post-#281 admin (#282)
test(review): refresh #170 Admin source hash for grant copy (#298)