Skip to content

Staging review: payout safety fixes, UI polish and plainer copy - #84

Merged
jlwaugh merged 4 commits into
stagingfrom
fix/staging-review
Oct 28, 2026
Merged

jlwaugh merged 4 commits into
stagingfrom
fix/staging-review

Conversation

@itexpert120

Copy link
Copy Markdown
Collaborator

Fixes from a full review of main...staging (mostly the new work orders feature), plus UI and copy improvements.

Bug fixes

  • Terminated work orders can no longer be paid. payNow and starting a DAO payment now refuse on a terminated order (the terminate dialog already promised this). Linking a DAO proposal that was started before termination still works.
  • The next step no longer says "Sending… automatic" when nothing will send. An approved request with no payout agent now waits on the agency, with a "Pay it" button.
  • No duplicate notifications from concurrent calls. Submitting a request, in-app signing and DAO proposal sync now use conditional updates, so a double click or a refresh racing the scheduler can't notify twice or overwrite a terminated order.
  • .5 is accepted as a NEAR amount.

UI

  • Money actions:
    • Pay now and edits that need re-signing ask for confirmation first.
    • Approve reads "Approve and pay" when it pays straight away.
    • Amount fields show their currency.
  • Terminated orders keep their payout history, and their requests show "Approved, not paid".
  • Builders:
    • An unsaved draft prompts before leaving.
    • Paid requests show the approved amount and a transaction link.
    • Signing has a retry when the document fails to load.
  • Base shadcn:
    • 16px inputs on phones (no iOS zoom).
    • Larger buttons on touch screens.
    • Solid 2px focus rings.
    • success and warning colour tokens.
    • "Confirm"/"Cancel" dialog defaults.
  • Background: an off-white page with white cards replaces the dot grid.
  • Copy: shorter wording on the work orders page, setup checklist and renewals. Agency admins see "ask your operator" instead of server environment variable names.

Not in this PR (needs a decision)

  • Double payment risk: rejecting a request after a DAO payment started, or after an automatic payout that needs review, lets the builder request the same work again even if the original payment goes through.
  • Wrong DAO lookup: syncPayment checks proposals against the organization's current DAO rather than the paying DAO recorded on the billing row.
  • Owner key not verified: the key supplied for create_agent isn't checked against the owner account's full-access keys.
  • Google Drive connect: the OAuth state is consumed before the signed-in user is checked.

Testing

  • Automated:
    • Typecheck and lint pass in all packages.
    • 741 API, 249 UI and 126 plugin tests pass, including new ones for termination, progress and NEAR amounts.
  • Manual:
    • Clicked through create, offer, approve, terminate and edit as an agency user on local dev, at desktop and phone width, in light and dark mode.
    • The builder-side screens were not clicked through: they need a NEAR wallet sign-in.

🤖 Generated with Claude Code

itexpert120 and others added 3 commits October 28, 2026 21:18
…, clearer payout UI

- Refuse Pay now and new DAO payments on a terminated work order; a started
  DAO payment can still be linked
- Approved requests nothing pays automatically wait on the agency, not "Sending"
- Guard submit, in-app sign and proposal sync with conditional updates so
  concurrent calls can't double-notify or overwrite a terminated order
- Accept ".5" as a NEAR amount
- UI: confirm Pay now and edits that need re-signing, currency on amount
  fields, payout history kept on terminated orders, unsaved-draft guard,
  popup-safe template tabs, payout settings validation, local times,
  builder signing retry, clearer next-step and dashboard badges

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…k-order steps

- Base shadcn: 16px inputs on phones (no iOS zoom), larger buttons on touch
  screens, solid 2px focus rings, success/warning tokens and badge variants,
  capitalised ConfirmDialog defaults
- Work orders: "Pay it" next-step action for DAO payments, "Approved, not paid"
  on terminated orders, advanced form fields under More options, confirm
  before "Don't renew", operator wording for server setup hints, larger text
  on the builder's work order page

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… copy

- Replace the dot-and-grain background with a --page token: off-white under
  white cards in light mode, unchanged in dark mode
- Shorter, plainer wording on the work orders page, setup checklist,
  compensation requests and renewal decisions; payout setup hints no longer
  name server environment variables

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@multi-review

multi-review Bot commented Oct 28, 2026

Copy link
Copy Markdown

Multi Review · 9268c40

I found no high-severity problems. The backend changes add termination guards to payNow and daoPayable, and switch submit, in-app signing and syncPayment to conditional updates; these hold on every caller I traced. The UI now shows the payouts and requests panels for terminated orders, but buttons that only make sense on a payable order still appear there. The new linking exception also leaves the DAO payment dialog half-broken.

3 issue(s)

What was checked (13 areas)
  • daoPayable and its 3 callers (linkProposal with linking:true; paymentProposal and startDaoPayment without it)
  • payNow refuseTerminated; retryBlockedPayouts/followUpPayouts sweep handling of terminated orders
  • syncPayment conditional updates and its callers (linkProposal, refreshPayment)
  • sign transaction: claim before signature insert, compared with the old update() helper
  • submitRequest conditional update vs autoApproval.onSubmitted / notifyManagers
  • progressOf new approved/paying/pay branches; ProgressAction consumers (admin $id onAction, NextStepCard, builderView nulling next)
  • nearToAtomic callers (saveSettings, top-up, balance) and contract regexes
  • RequestsPanel/RequestItem visibility on terminated orders, ProposalForm quote/start/link flow
  • ApproveForm 'Approve and pay' label vs payoutReadiness hold
  • WorkOrderForm resign ConfirmDialog and submit paths (form submit, Cmd+Enter)
  • DraftEditor useBlocker and leave dialog; builder page panels on terminated orders
  • OperatorHint session lookup, pending-tab usage in template-fields/template-setup
  • dashboard progress badge, builder-signing retry, members scroll/focus

Findings

  • 🟡 Low api/src/services/work-orders/service.ts:2769 On a terminated order, the DAO payment dialog's quote request and its "Create the proposal" button are refused with CLOSED
    The linking exception only covers linkProposal. On a terminated order with daoPaymentStartedAt set, the UI now shows "Link the DAO proposal". That opens ProposalForm, which immediately loads its quote through paymentProposal, which calls daoPayable without linking. That call throws CLOSED, so the dialog shows "Work order X is terminated: nothing more can be paid" in red where the amount should be. "Create the proposal with my wallet" is disabled (!q), and it would hit CLOSED through startDaoPayment anyway. For USD work orders, the admin can't see the locked NEAR amount the proposal has to match exactly. Only the proposal-number field still works, which makes the flow look broken even though linking is allowed.
    Suggested fix: Allow paymentProposal (read-only) when daoPaymentStartedAt is set, e.g. pass { linking: true } from it too. Alternatively, have the UI skip the quote query and wallet button when the order is terminated and show the locked payoutAmount instead.
  • 🟡 Low ui/src/routes/_layout/_authenticated/admin/work-orders/$id.tsx:311 Terminated orders now show "Review and approve" on submitted requests, which always fails
    RequestsPanel is now rendered for terminated orders whenever they have requests. RequestItem still shows "Review and approve" for any submitted request when canManage, without checking terminated. A request the builder submitted before the agency terminated therefore offers an approve dialog, and approveRequest then rejects it with NOT_PAYABLE ("nothing can be approved"). Before this change the panel was hidden for terminated orders.
    Suggested fix: In RequestItem, hide the approve button when terminated. Keep Reject so the request can be closed out.
  • 🟡 Low ui/src/routes/_layout/_authenticated/work-orders/$id.tsx:229 Builders on a terminated order get an editable draft with a Submit button that always fails
    The requests card is now shown for terminated orders with requests. Draft requests still render through DraftEditor, so a draft created at period end before termination shows editable fields, Save and Submit. submitRequest refuses with CLOSED for terminated orders, so the builder can edit and save but never submit. The new leave-page blocker also prompts about unsaved changes on a request that can't go anywhere.
    Suggested fix: When wo.status === "terminated", render drafts read-only (e.g. through SubmittedRequest), or hide them.

Comment @multi-review to re-review new commits, or @multi-review full for a full review.

… succeed

- Format the setup test so `biome ci` passes.
- A DAO payment started before termination can still be quoted, so the
  link dialog shows the locked amount; creating a new proposal stays refused
  and its button is hidden.
- No "Review and approve" on submitted requests of a terminated order.
- Builders see unsubmitted drafts of a terminated order read-only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jlwaugh
jlwaugh merged commit b2fc9ba into staging Oct 28, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants