Persist comment source monitoring
This commit is contained in:
1 parent
5e1fc5def9
commit
8d932fcf36
16 files changed
+376
-24
No files matched your search
@@ -35,7 +35,7 @@ Never document real values. `.env` is ignored and may contain production credent
|
||||
- `userAgent`: Reddit JSON request identifier.
|
||||
- `targetGenders`: allowed parsed values.
|
||||
- `filterSellers`, `sellerKeywords`, `sellerDomains`: seller policy inputs; see also the `conversations` section, whose off-platform kill is independent of this flag. The defaults treat Telegram references, including `t.me` and `telegram.me` links, as seller signals alongside paid-content platforms and payment prompts.
|
||||
- `prioritizeRecentPosts`, `recentWindowMinutes`: recency/fallback behavior.
|
||||
- `prioritizeRecentPosts`, `recentWindowMinutes`: candidate recency/fallback behavior. `recentWindowMinutes` also controls how long comment-author source posts remain in the durable rotating watchlist.
|
||||
- `maxReadyCandidates`: hard ceiling for the active candidate target; valid range 1–500. Runtime lowers the actual target to what authenticated running accounts can send within `recentWindowMinutes` under current rolling-hour and message-spacing limits.
|
||||
- `physiqueTargeting`: optional image-candidate filter with `enabled`, inclusive `minScore`, and inclusive `maxScore` values from 1 to 10. It is disabled by default. When enabled, a model score outside the range or an image without enough visible body evidence to score is rejected before opener generation. Saving the setting also reconciles prepared image candidates in the ready and delivery-retry stages: candidates that no longer qualify are rejected, while retained candidates receive the newly applied range snapshot shown in the funnel. A candidate already leased for sending is not changed mid-send. The setting is hot-read by existing account runtimes; chat sources are unaffected.
|
||||
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ stateDiagram-v2
|
||||
|
||||
### 1. Discovery
|
||||
|
||||
The discovery loop rotates through enabled subreddits and authenticated runtimes. A runtime fetches Reddit `/new` data using the process-shared `RedditRequestCoordinator`. In the default `post-author` targeting mode those posts enter intake directly. An image subreddit configured for `comment-author` instead reads top-level comments from at most five newly listed posts and batches previously unseen eligible comment text through the reaction classifier. Candidates require a verdict at or above 0.8 confidence that the commenter wants to receive or experience the depicted person's role; comments describing what their author would do to the pictured person do not qualify. When `reddit.targetGenders` is non-empty, the expressed gender perspective must also be included. An `unknown` perspective fails closed unless explicitly targeted. A bounded in-process cache prevents unchanged comments from repeatedly consuming model calls. The candidate ID, author, timestamp, and permalink come from the comment while the original post image and title remain attached as preparation context; the usual image screen later verifies the depicted gender against the same target list. Intake then deduplicates candidate IDs and authors, excludes processed/contacted history, stores the full snapshot, source type, weight, and timestamps, and logs exact intake counts. Queued comments carry the classifier-policy version; active candidates admitted by the broader historical role policy are rejected on upgrade rather than allowed to send.
|
||||
The discovery loop rotates through enabled subreddits and authenticated runtimes. A runtime fetches Reddit `/new` data using the process-shared `RedditRequestCoordinator`. In the default `post-author` targeting mode those posts enter intake directly. An image subreddit configured for `comment-author` admits each newly listed source post to a durable SQLite watchlist until the post leaves `reddit.recentWindowMinutes`. Each poll rotates to the least-recently checked source post and requests a bounded batch of up to 100 comments sorted newest-first, so a source remains eligible to produce later commenter candidates after its first scan and across process restarts. Comment IDs and body hashes retain prompt-free classifier verdicts; unchanged comments do not consume another model call, while an edited body is reclassified. Candidates require a verdict at or above 0.8 confidence that the commenter wants to receive or experience the depicted person's role; comments describing what their author would do to the pictured person do not qualify. When `reddit.targetGenders` is non-empty, the expressed gender perspective must also be included. An `unknown` perspective fails closed unless explicitly targeted. The candidate ID, author, timestamp, and permalink come from the comment while the original post image and title remain attached as preparation context; the usual image screen later verifies the depicted gender against the same target list. Intake then deduplicates candidate IDs and authors, excludes processed/contacted history, stores the full snapshot, source type, weight, and timestamps, and logs exact intake and comment-gate counts. Queued comments carry the classifier-policy version; active candidates admitted by the broader historical role policy are rejected on upgrade rather than allowed to send.
|
||||
|
||||
The queue grows to a demand-based target rather than a fixed backlog. The target is the smaller of configured `reddit.maxReadyCandidates` and the work that authenticated running accounts can still send within the recent-post window, accounting for rolling hourly capacity and minimum message spacing. Intake admits only the current deficit, newest Reddit posts first, pauses at zero outbound capacity, and reports fetched posts left unevaluated because the funnel is full. Reddit request pacing, not a tight application poll, remains the primary request limiter.
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@ The special legacy-unassigned account exists only to preserve rows created befor
|
||||
### Durable work and idempotency
|
||||
|
||||
- `candidate_queue`: global candidate snapshot, source/priority, state, prepared payload, worker lease, retry timing, selected account, and rejection/error details. Image preparation snapshots retain the generated opener, grounded analysis, both AI scores, the physique range used, source-image URL, and experiment/model/tone metadata for delivery and operator review.
|
||||
- `comment_source_watches`: durable rotating source-post snapshots with last-check and expiry timestamps for comment-author discovery.
|
||||
- `comment_source_comment_observations`: prompt-free comment ID/body hash and classifier verdict cache, retained across restarts so unchanged comments avoid another model call and edited bodies can be reconsidered.
|
||||
- `delivery_outbox`: account-scoped prepared delivery and idempotency status retained for legacy/recovery paths.
|
||||
- `conversation_states`: account/conversation policy and derived state JSON.
|
||||
- `conversation_automation_claims`: account/conversation/inbound-event claim with intended reply and `pending`, `sent`, or terminal `superseded` state plus audit timestamps.
|
||||
|
||||
@@ -31,7 +31,7 @@ Configured subreddits have a source type:
|
||||
- `image`: image-led posts are downloaded and analyzed before an opener is generated.
|
||||
- `chat`: text-led posts require a parseable self-declared gender and adult age, then use the chat-opener prompt.
|
||||
|
||||
Image subreddits may separately target either the post author (the default) or a qualifying commenter. Comment-author targeting scans a bounded set of top-level comments on newly listed image posts and uses a fail-closed AI classification. A comment qualifies only when it personally expresses a desire to receive or experience the depicted person's role; describing what the commenter would do to the pictured person does not qualify. Confidence must be at least 0.8, and the gender perspective expressed by the comment must be included in `reddit.targetGenders` when that list is non-empty. `unknown` therefore fails closed unless it is explicitly targeted. The normal image screen also verifies that the depicted role matches `reddit.targetGenders`. The comment verdict is an interpretation of public text, not a claim about the author's actual gender or identity. Generic praise, ambiguous reactions, deleted/moderator comments, and the post author's own comments do not qualify. The original image remains scene context, but commenter openers use a separate prompt contract and must ground the message in what the commenter expressed. Drafts fail closed when they attribute the pictured body, pose, post, or image to the commenter, request another image, or omit a clear connection to the comment.
|
||||
Image subreddits may separately target either the post author (the default) or a qualifying commenter. Comment-author targeting durably watches newly listed image posts throughout the configured recent window and checks their newest comments in rotation, rather than treating a source post as finished after one pass. A comment qualifies only when it personally expresses a desire to receive or experience the depicted person's role; describing what the commenter would do to the pictured person does not qualify. Confidence must be at least 0.8, and the gender perspective expressed by the comment must be included in `reddit.targetGenders` when that list is non-empty. `unknown` therefore fails closed unless it is explicitly targeted. The normal image screen also verifies that the depicted role matches `reddit.targetGenders`. The comment verdict is an interpretation of public text, not a claim about the author's actual gender or identity. Generic praise, ambiguous reactions, deleted/moderator comments, and the post author's own comments do not qualify. The original image remains scene context, but commenter openers use a separate prompt contract and must ground the message in what the commenter expressed. Drafts fail closed when they attribute the pictured body, pose, post, or image to the commenter, request another image, or omit a clear connection to the comment.
|
||||
|
||||
Image analysis may produce a subjective 1–10 visible-physique score. It is not a medical assessment and remains unknown when the image does not show enough of the body for a grounded judgment. The scale is deliberately critical: 5 is broadly average, 6 requires visible above-average leanness or definition, and 8–10 are reserved for rare athletic or model-like physiques. Nudity and photographic presentation do not increase the score. Physique targeting is disabled by default. When an operator enables an inclusive minimum/maximum range, image candidates outside that range—and unscorable image candidates—are rejected before opener generation; chat candidates are unaffected.
|
||||
|
||||
|
||||
+2
-1
@@ -20,7 +20,7 @@ This is an ownership map, not an API dump. Read the owning implementation and te
|
||||
|
||||
| Module | Owns | Important constraints |
|
||||
| --- | --- | --- |
|
||||
| `services/monitor.ts` | Subreddit ordering, post/comment candidate fetching, reaction/age/gender/seller screening, rejection summaries | Comment reactions fail closed at the confidence gate and, when configured, the expressed-gender gate; cheap checks run first; preserve exact rejection/deferred counts; listing 404 disables the subreddit. |
|
||||
| `services/monitor.ts` | Subreddit ordering, post/comment candidate fetching, reaction/age/gender/seller screening, rejection summaries | Comment sources rotate durably and fetch newest comments; reactions fail closed at recipient-role, confidence, and configured expressed-gender gates; cheap checks run first; preserve exact rejection/deferred counts; listing 404 disables the subreddit. |
|
||||
| `reddit/api.ts` | Reddit JSON calls, post/comment parsing, seller/profile evidence, username resolution, error types | All reads must use the coordinator; redact error metadata. |
|
||||
| `reddit/request-coordinator.ts` | Process-wide Reddit request spacing and cooldown | Space failed requests too; 429 cooldown is global. |
|
||||
| `services/processor.ts` | Source-specific AI preparation and outbound safety | Returns prepared or explicit skip; performs no remote chat send. |
|
||||
@@ -30,6 +30,7 @@ This is an ownership map, not an API dump. Read the owning implementation and te
|
||||
| `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, prepared-message replacement, counts, and manual clearing | Mutations require an eligible state or expected worker lease; recover expired/interrupted work; reject active comments admitted under a superseded eligibility policy; operator edits clear AI attribution; manual removals preserve sending leases and terminal audit rows. |
|
||||
| `database/comment-source-watch-repository.ts` | Durable comment-source rotation plus comment body-hash/verdict observations | Watch lifetime follows the configured recent window; persist no comment body; reclassify when the body hash changes. |
|
||||
|
||||
## Account growth
|
||||
|
||||
|
||||
Reference in new issue
Block a user