Add outreach candidate editing controls
This commit is contained in:
1 parent
c75e71f26e
commit
79c508be2b
19 files changed
+434
-12
No files matched your search
@@ -109,6 +109,8 @@ an administrator credential.
|
||||
| `GET` | `/api/attention` | Get operator attention items | read | no |
|
||||
| `GET` | `/api/outreach` | Get active outreach candidates and funnel stages | read | no |
|
||||
| `DELETE` | `/api/outreach` | Cancel every unsent outreach candidate except in-flight sends | admin | yes |
|
||||
| `PATCH` | `/api/outreach/{postId}/message` | Replace a prepared outreach message before sending | admin | yes |
|
||||
| `DELETE` | `/api/outreach/{postId}` | Cancel one unsent outreach candidate | admin | yes |
|
||||
| `GET` | `/api/growth` | Get per-account comment growth state | read | no |
|
||||
| `GET` | `/api/growth/{accountId}` | Get one account's growth settings, communities and comment history | read | no |
|
||||
| `PATCH` | `/api/growth/{accountId}` | Enable, disable or re-pace comment growth for an account | admin | yes |
|
||||
|
||||
@@ -48,6 +48,8 @@ Matrix cooldowns retain the operation that triggered them. A room-creation or in
|
||||
|
||||
The operator can manually clear the unsent funnel from the authenticated dashboard. The repository atomically moves discovered, screening, ready, and retryable candidates to a terminal rejection with the reason `Cleared manually by operator`, releases their leases, and retains the audit rows so those candidates are not rediscovered. A `sending` lease is never changed because its remote Matrix outcome may already be in flight. Clearing does not change bot mode; running discovery may refill the funnel immediately.
|
||||
|
||||
The same surface supports individual cancellation and prepared-message editing. Individual cancellation uses the same terminal audit transition and refuses `sending` or completed rows. Editing is limited to `ready` and `retryable` candidates with a preparation snapshot; it atomically replaces only the opener, clears generated strategy/experiment selection metadata, labels the model attribution `operator-edited`, and re-runs the deterministic outbound location/meeting safeguard. Both operations return HTTP 409 when a stale dashboard loses a race to dispatch.
|
||||
|
||||
Screening, retry promotion, dispatch, and the operator's active-queue view are ordered by the Reddit post creation time, newest first; source priority is only a tie-breaker. The dispatch worker leases the newest ready candidate for an account, materializes the processed post in that account's repository, applies the account rate limiter, checks dry-run, and atomically claims the recipient globally. `ChatService.startConversationDetailed()` returns one of:
|
||||
|
||||
- `sent`: persist the message and outcome metadata, commit recipient history, update activity, and mark the candidate sent;
|
||||
|
||||
@@ -65,6 +65,7 @@ The special legacy-unassigned account exists only to preserve rows created befor
|
||||
13. Browsing decisions are unique per account and thing. Before selecting, the service also checks for a `simulated-upvote` by any other owned account, but account-specific rejections do not unnecessarily reserve an item globally.
|
||||
14. A browsing selection is persisted as `pending` before any vote request. It becomes `submitted` only after Reddit confirms the authenticated upvote, or `failed` with the safe error reason; unconfirmed selections are never retried. Browsing rows never contribute to adaptive comment-growth promotion.
|
||||
15. Manual outreach clearing is a terminal audited transition, not deletion. It rejects discovered, screening, ready, and retryable candidates, releases their leases, and never changes a `sending` row whose remote outcome may be uncertain.
|
||||
16. Individual candidate removal follows the same audited transition. Prepared opener edits are allowed only in ready/retryable states; the transaction updates the queue snapshot and any matching processed-post projection, clears AI experiment attribution, and carries `operatorEdited: true` with model ID `operator-edited` through delivery.
|
||||
|
||||
10. Recipient account status changes only after a definitive Reddit profile response. Transient lookup failures retain the previous value, and the shared check timestamp prevents duplicate lookups across account runtimes during the four-hour interval.
|
||||
|
||||
|
||||
+3
-1
@@ -36,6 +36,8 @@ Prepared cards in the authenticated outreach funnel expose the exact opener, gro
|
||||
|
||||
The funnel header also offers a destructive, confirmed **Clear funnel** action. Its dialog names the number of cancellable candidates, explains that audit rows remain and running discovery can refill the queue, and separately identifies any in-flight sends that cannot safely be cancelled. Success is reported from the authoritative API response before the funnel query refreshes.
|
||||
|
||||
Each non-sending candidate has a confirmed **Remove** action. Prepared candidates in ready or retrying state also have **Edit message**: the modal validates the 1–2000 character limit, the server re-applies outbound safeguards, and a successful edit is shown as operator-authored attribution. Buttons are intentionally absent once the candidate is sending, while the server still enforces the state boundary against stale pages.
|
||||
|
||||
## State model
|
||||
|
||||
- Remote state: TanStack Query snapshots parsed by shared Zod schemas.
|
||||
@@ -63,7 +65,7 @@ Rules:
|
||||
- Duplicate/replayed events must be harmless.
|
||||
- A disconnected stream marks data stale but does not blank useful cached content.
|
||||
- Invalid event payloads are contained and repaired with a snapshot refresh.
|
||||
- The notification centre retains useful lifecycle history, including successful syncs. Sticky toasts are reserved for inbound replies/media and attention-worthy failures or runtime/account states; they remain visible until the operator dismisses them.
|
||||
- The notification centre and sticky toasts are reserved for inbound replies/media and attention-worthy failures or runtime/account states. Routine sync completions, successful sends, healthy lifecycle changes, and raw logs remain visible in their owning screens instead of creating notifications. Toasts remain visible until the operator dismisses them.
|
||||
- Raw technical logs belong in Operations, not as general user notifications.
|
||||
|
||||
## Authentication and privacy
|
||||
|
||||
@@ -22,6 +22,7 @@ The product has five connected goals:
|
||||
- Remote side effects are fail-closed: a send is recorded only after the chat service confirms it; interrupted reply claims reconcile against Matrix history before retrying. A queued reply refreshes Matrix immediately before sending and becomes an auditable superseded claim if a newer inbound event or terminal state appeared while it waited.
|
||||
- Dry-run prepares and records decisions but never sends.
|
||||
- Operators can see funnel stages, prepared opener and scoring context, blurred source images, account state, rate limits, failures, handoffs, and recent activity rather than inferring success from a process-health check.
|
||||
- Operators may replace a prepared opener before it is leased for sending. The edited text still passes the deterministic location/meeting safeguard, loses generated strategy/experiment attribution, and is durably labelled `operator-edited` rather than credited to the model.
|
||||
|
||||
## Candidate policy
|
||||
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ This is an ownership map, not an API dump. Read the owning implementation and te
|
||||
| `services/strategy-selector.ts` | Weighted explore/exploit selection and experiment metadata | Separate image/chat strategy sections; respect mature response window and sample floor. |
|
||||
| `services/recipient-deduplicator.ts` | Global recipient history plus live reservation | Case-insensitive; release failures, commit successes, recover stale claims. |
|
||||
| `utils/rate-limiter.ts` | Per-account send spacing/hour limits/jitter | Increment only for confirmed sends; reply priority may use the same limiter. |
|
||||
| `database/candidate-queue-repository.ts` | Durable candidate state machine, leases, retries, counts, and manual clearing | Mutations require the expected worker lease; recover expired/interrupted work; manual clearing preserves sending leases and terminal audit rows. |
|
||||
| `database/candidate-queue-repository.ts` | Durable candidate state machine, leases, retries, prepared-message replacement, counts, and manual clearing | Mutations require an eligible state or expected worker lease; recover expired/interrupted work; operator edits clear AI attribution; manual removals preserve sending leases and terminal audit rows. |
|
||||
|
||||
## Account growth
|
||||
|
||||
|
||||
Reference in new issue
Block a user