@floomhq/signaldash 0.35.0 → 0.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -17
- package/bin/sd.mjs +3 -3
- package/package.json +2 -2
- package/skills/signaldash/SKILL.md +33 -13
- package/skills/signaldash-safe-usage/SKILL.md +11 -6
package/README.md
CHANGED
|
@@ -102,7 +102,7 @@ setup installs both from the same pinned npm package
|
|
|
102
102
|
the human chose to execute:
|
|
103
103
|
|
|
104
104
|
```bash
|
|
105
|
-
npx -y @floomhq/signaldash@0.
|
|
105
|
+
npx -y @floomhq/signaldash@0.37.0 <invite-code>
|
|
106
106
|
```
|
|
107
107
|
|
|
108
108
|
Run that command in a terminal, not in an agent chat. Do not ask an agent to
|
|
@@ -187,6 +187,16 @@ SignalDash exposes:
|
|
|
187
187
|
Every operation runs through the hosted SignalDash backend. Agents never
|
|
188
188
|
receive the Unipile access key.
|
|
189
189
|
|
|
190
|
+
The inspiration library also extracts LinkedIn post references already stored
|
|
191
|
+
inside conversation `signals`. This path scans SQLite only and makes zero
|
|
192
|
+
LinkedIn or Unipile calls. Feed URLs and post slugs become canonical activity
|
|
193
|
+
URNs; `lnkd.in` is contacted with redirects disabled, and the redirect location
|
|
194
|
+
is parsed without requesting `linkedin.com`. An unresolved short link remains
|
|
195
|
+
an `offen` library row with its raw URL. `conversation_sources` preserves each
|
|
196
|
+
sharing signal, thread, time, direction, and exact or unresolved sharer identity
|
|
197
|
+
even when several signals deduplicate to one library URN. The dedicated database
|
|
198
|
+
flag can disable extraction without a deployment.
|
|
199
|
+
|
|
190
200
|
The hourly Secretary push reuses the existing LinkedIn collector cycle and
|
|
191
201
|
adds no second inbox poll. It sends only when a new tracked-thread reply,
|
|
192
202
|
own-post comment or reaction, or approval-ready draft was stored after push was
|
|
@@ -295,6 +305,16 @@ uses the same sender binding, action ledger, duplicate guard, daily budget, and
|
|
|
295
305
|
provider-warning lock as immediate publishing. An interrupted or ambiguous
|
|
296
306
|
execution fails closed and is never retried automatically.
|
|
297
307
|
|
|
308
|
+
`li_scheduled_posts` is the shared planning read across posts stored by
|
|
309
|
+
SignalDash and the configured Buffer LinkedIn channel. Every item names its
|
|
310
|
+
source, and the response reports independent completeness for SignalDash,
|
|
311
|
+
Buffer, and native LinkedIn. Unipile has no documented endpoint for posts or
|
|
312
|
+
drafts scheduled natively in LinkedIn, so that source is always explicit as
|
|
313
|
+
`unavailable`. SignalDash does not call undocumented Voyager routes or automate
|
|
314
|
+
linkedin.com to fill the gap. An empty item list therefore means only that the
|
|
315
|
+
visible SignalDash and Buffer sources are empty, never that the native LinkedIn
|
|
316
|
+
calendar is empty.
|
|
317
|
+
|
|
298
318
|
`sd_schedule_message` puts one exact message into one exact chat at one exact
|
|
299
319
|
time, on WhatsApp or LinkedIn, text only. It enqueues; it never sends. The
|
|
300
320
|
attachment bytes a WhatsApp send accepts are refused here rather than held on
|
|
@@ -351,9 +371,10 @@ explicitly enables it with `confirm:true`. The optional filters are an exact
|
|
|
351
371
|
public-identifier allowlist and description-keyword matches; when both groups
|
|
352
372
|
are configured, both must match. The single backend worker reads one bounded
|
|
353
373
|
received-invitation page, accepts at most five invitations per run and ten per
|
|
354
|
-
UTC day by default, jitters every action, and also consumes the
|
|
355
|
-
LinkedIn
|
|
356
|
-
setting. `sd_auto_accept_status` exposes accepted counts
|
|
374
|
+
UTC day by default, jitters every action, and also consumes the invitation
|
|
375
|
+
daily lane and aggregate LinkedIn brake. Three consecutive parse or provider
|
|
376
|
+
errors disable the setting. `sd_auto_accept_status` exposes accepted counts
|
|
377
|
+
today and this week,
|
|
357
378
|
failed attempts today, remaining capacity, the stop reason, and sanitized
|
|
358
379
|
records for invitations whose provider shape could not be parsed. Both the current nested
|
|
359
380
|
`specifics.shared_secret` and legacy top-level shape are supported; secrets are
|
|
@@ -405,22 +426,30 @@ npx -y @floomhq/signaldash connections linkedin-connections.csv
|
|
|
405
426
|
|
|
406
427
|
## Safety limits
|
|
407
428
|
|
|
408
|
-
SignalDash enforces
|
|
429
|
+
SignalDash enforces daily write caps. The operating skill adds the human
|
|
409
430
|
workflow around that runtime control:
|
|
410
431
|
|
|
411
|
-
- Every successful
|
|
412
|
-
`
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
432
|
+
- Every successful LinkedIn write includes aggregate `rate_limit` data and its
|
|
433
|
+
applicable `lane_rate_limit` when classified. `rate_limit.limit`, `used`,
|
|
434
|
+
`remaining`, and `resets_at` retain their stable response shape. A lane
|
|
435
|
+
refusal returns HTTP
|
|
436
|
+
429 with an exact invitation, message, or engagement code and
|
|
437
|
+
`rate_limit_lane`; the aggregate brake retains
|
|
438
|
+
`code: "rate_limit_exceeded"`. Every 429 includes `Retry-After`.
|
|
439
|
+
Counters are persisted server-side and reset at midnight UTC.
|
|
440
|
+
- LinkedIn uses three per-sender lanes: 20 invitation actions, 30 messages in
|
|
441
|
+
existing threads, and 50 replies or reactions on own posts per UTC day by
|
|
442
|
+
default. Publishing and first comments count with own-post engagement. A
|
|
443
|
+
separate aggregate cap of 75 is the emergency brake across the lanes. Sent
|
|
444
|
+
invitations retain the unchanged 100-attempt UTC-week policy.
|
|
445
|
+
- WhatsApp and email sends together, and message deletes, retain their own
|
|
446
|
+
independent budgets. A `429` names
|
|
417
447
|
the cap it hit; it is never a statement about another lane. Two caveats worth
|
|
418
448
|
knowing: on the day a deployment first upgrades past the lane split, that
|
|
419
449
|
day's existing count is still read on the LinkedIn side (it is ambiguous, and
|
|
420
450
|
the conservative reading is the safe one) and clears at the next UTC midnight;
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
budget but a WhatsApp budget each.
|
|
451
|
+
LinkedIn, WhatsApp/email, and delete ledgers are keyed to the stable logical
|
|
452
|
+
user or sender rather than multiplied by live bearer sessions.
|
|
424
453
|
- Read the exact thread before every send.
|
|
425
454
|
- Preview an exact invitation target and note before sending it.
|
|
426
455
|
- List the exact received or sent invitation before accepting or withdrawing it.
|
|
@@ -429,7 +458,8 @@ workflow around that runtime control:
|
|
|
429
458
|
- Never infer a recipient from a partial name.
|
|
430
459
|
- Never send a duplicate or retry an ambiguous timeout without re-reading.
|
|
431
460
|
- Invitation auto-accept remains off until explicitly enabled, consumes both
|
|
432
|
-
its dedicated daily cap
|
|
461
|
+
its dedicated daily cap, the invitation lane, and the aggregate LinkedIn
|
|
462
|
+
brake, and disables
|
|
433
463
|
itself after three consecutive parse or provider errors.
|
|
434
464
|
- Do not parallelize sends or work around a rate limit.
|
|
435
465
|
- Do not bypass paid-discovery previews, pacing, request caps, or cost caps.
|
|
@@ -439,8 +469,8 @@ workflow around that runtime control:
|
|
|
439
469
|
|
|
440
470
|
LinkedIn invitation writes are single-object actions. SignalDash serializes
|
|
441
471
|
them with other LinkedIn writes, requires an exact preview or list read,
|
|
442
|
-
applies the
|
|
443
|
-
policy by default. For a new invitation, jitter completes before the final
|
|
472
|
+
applies the invitation daily lane and aggregate brake, and enforces a separate
|
|
473
|
+
100-attempt weekly policy by default. For a new invitation, jitter completes before the final
|
|
444
474
|
preflight and action reservation; that preflight verifies relationship state,
|
|
445
475
|
pending invitations in both directions, and absence of an existing one-to-one
|
|
446
476
|
chat. Provider timeouts become non-retryable `outcome_unknown` locks.
|
package/bin/sd.mjs
CHANGED
|
@@ -637,7 +637,7 @@ const TOOLS = [
|
|
|
637
637
|
{
|
|
638
638
|
name: "sd_budget_status",
|
|
639
639
|
path: "/sd/budget_status",
|
|
640
|
-
description: "Read authoritative SignalDash LinkedIn attempt capacity for
|
|
640
|
+
description: "Read authoritative SignalDash LinkedIn attempt capacity for the invitation, existing-thread message, and own-post engagement daily lanes, the aggregate emergency brake, and the unchanged weekly invitation cap.",
|
|
641
641
|
inputSchema: {
|
|
642
642
|
type: "object",
|
|
643
643
|
properties: {},
|
|
@@ -948,7 +948,7 @@ const TOOLS = [
|
|
|
948
948
|
{
|
|
949
949
|
name: "sd_campaign_preview",
|
|
950
950
|
path: "/sd/campaign/preview",
|
|
951
|
-
description: "Inspect one campaign before approval: every exact recipient, every exclusion and its reason, the exact message text for each step, the timing, the
|
|
951
|
+
description: "Inspect one campaign before approval: every exact recipient, every exclusion and its reason, the exact message text for each step, the timing, the invitation and existing-thread message lanes, the aggregate brake, and the approval_url to send the human. Show the human this content. This read also authorizes a later exact cancel. An agent cannot approve a campaign; only the authenticated human page can, and it can hand you a one-time code for sd_campaign_approve.",
|
|
952
952
|
inputSchema: {
|
|
953
953
|
type: "object",
|
|
954
954
|
properties: {
|
|
@@ -1529,7 +1529,7 @@ const TOOLS = [
|
|
|
1529
1529
|
{
|
|
1530
1530
|
name: "li_scheduled_posts",
|
|
1531
1531
|
path: "/li/scheduled_posts",
|
|
1532
|
-
description: "
|
|
1532
|
+
description: "Read the shared LinkedIn content calendar from SignalDash and the configured Buffer channel. Always inspect completeness and per-source state. Native LinkedIn scheduled posts and drafts are NOT visible because Unipile has no documented read route for them, and SignalDash does not use raw Voyager routes or linkedin.com browser access. An empty items array is never proof that the native LinkedIn calendar is empty.",
|
|
1533
1533
|
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
1534
1534
|
},
|
|
1535
1535
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@floomhq/signaldash",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.37.0",
|
|
4
4
|
"description": "Secure LinkedIn, WhatsApp, and email access for AI agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
|
20
20
|
"test": "node --test",
|
|
21
|
-
"check": "node --check bin/sd.mjs && node --check server/server.cjs && node --check server/composio-email.cjs && node --check server/attachments.cjs && node --check server/write-control.cjs && node --check server/secretary-store.cjs && node --check server/secretary-collector.cjs && node --check server/secretary-latest.cjs && node --check server/secretary-approvals.cjs && node --check server/secretary-push.cjs && node --check server/secretary-rules.cjs && node --check server/secretary-shadow-gate.cjs && node --check server/secretary-vault-importer.cjs && node --check server/secretary-inspiration.cjs && node --check server/linkedin-archive-importer.cjs && node --check server/voice-profile.cjs && node --check server/campaign-store.cjs && node --check server/campaign-runner.cjs && node --check server/withdrawal-store.cjs && node --check server/post-scheduler.cjs && node --check server/message-scheduler.cjs && node --check scripts/import-linkedin-archive.mjs && node --check scripts/import-secretary-vault-snapshot.mjs && node --check scripts/rebuild-secretary-actors.mjs && node --check bin/signaldash.js && node --check lib/cli.js && node --check lib/config-file.js && node --check lib/mcp.js && node --check lib/rate-guard.js && node --check lib/secrets.js && node --check lib/unipile.js"
|
|
21
|
+
"check": "node --check bin/sd.mjs && node --check server/server.cjs && node --check server/buffer-calendar.cjs && node --check server/composio-email.cjs && node --check server/attachments.cjs && node --check server/write-control.cjs && node --check server/secretary-store.cjs && node --check server/secretary-collector.cjs && node --check server/secretary-latest.cjs && node --check server/secretary-approvals.cjs && node --check server/secretary-push.cjs && node --check server/secretary-rules.cjs && node --check server/secretary-shadow-gate.cjs && node --check server/secretary-vault-importer.cjs && node --check server/secretary-inspiration.cjs && node --check server/linkedin-archive-importer.cjs && node --check server/voice-profile.cjs && node --check server/campaign-store.cjs && node --check server/campaign-runner.cjs && node --check server/withdrawal-store.cjs && node --check server/post-scheduler.cjs && node --check server/message-scheduler.cjs && node --check scripts/import-linkedin-archive.mjs && node --check scripts/import-secretary-vault-snapshot.mjs && node --check scripts/rebuild-secretary-actors.mjs && node --check scripts/extract-conversation-inspiration.mjs && node --check bin/signaldash.js && node --check lib/cli.js && node --check lib/config-file.js && node --check lib/mcp.js && node --check lib/rate-guard.js && node --check lib/secrets.js && node --check lib/unipile.js"
|
|
22
22
|
},
|
|
23
23
|
"keywords": [
|
|
24
24
|
"mcp",
|
|
@@ -365,7 +365,7 @@ Use the exact tool names and argument keys below. Limits are optional.
|
|
|
365
365
|
| `sd_version` | no arguments | Read the backend commit, dirty-at-start state, process start time, and package version captured when the serving process started. Use it to distinguish stale deployment from a code failure. |
|
|
366
366
|
| `sd_secretary_latest` | `limit` optional integer 1-100, default 50; `continuation` optional signed token; `ack_token` optional signed token from the previous successful response | Read the stored Secretary inbox with zero provider calls. Render its rows plus the ignored aggregate as one table. Preserve the prior tokens after an error; on the next successful call pass its acknowledgement and continuation exactly as returned. |
|
|
367
367
|
| `sd_secretary_push_set` | `enabled` boolean and `confirm:true` required | Enable or disable change-only hourly notifications to Federico's exact verified Secretary WhatsApp group. Enabling re-proves the account and group from the live chat list and starts from that instant. Disabling is an immediate database kill switch and needs no deploy or restart. |
|
|
368
|
-
| `sd_inspiration_list` | `limit` optional 1-100, default 20; `status` optional `offen`, `in arbeit`, `genutzt`, or `alle`; `content_kind` optional `post_format`, `business_idea`, or `all` | Read stored inspiration ranked by source engagement with zero provider calls. Defaults exclude genutzt entries and business ideas. Preserve every row's `draft_provenance`, and add credit when `credit_required` is true or recognisable framing or wording is reused. |
|
|
368
|
+
| `sd_inspiration_list` | `limit` optional 1-100, default 20; `status` optional `offen`, `in arbeit`, `genutzt`, or `alle`; `content_kind` optional `post_format`, `business_idea`, or `all` | Read stored inspiration ranked by source engagement with zero provider calls. Defaults exclude genutzt entries and business ideas. `conversation_sources` distinguishes who shared a stored post, in which thread, and when; unresolved short links remain visible by raw URL. Preserve every row's `draft_provenance`, and add credit when `credit_required` is true or recognisable framing or wording is reused. |
|
|
369
369
|
| `sd_inspiration_status` | `id`, `status`, and `confirm:true` required; `resulting_post_urn` required exactly when status is `genutzt` | Record offen, in arbeit, or genutzt state. Genutzt is terminal and the resulting own-post URN prevents the source from ever being proposed again. |
|
|
370
370
|
| `sd_inspiration_import` | `source` exact LinkedIn post URL or URN; optional source author, Federico note, purpose, content kind, credit fields, and format description | Migration/manual capture through Unipile's documented post retrieval endpoint. The primary capture path remains pasting a URL into the verified Secretary WhatsApp group. |
|
|
371
371
|
| `sd_inspiration_channel_configure` | exact `chat_id`, `provider_id`, `chat_name`, and `confirm:true` | Re-prove the connected WhatsApp account and exact group in the live chat list, then enable automatic URL capture and same-group acknowledgements. Never substitute a self-chat. |
|
|
@@ -382,7 +382,7 @@ Use the exact tool names and argument keys below. Limits are optional.
|
|
|
382
382
|
| `li_invitations_sent` | `limit` integer 1-100, default 50; `cursor` optional | List one bounded page of sent invitations. This read authorizes only the exact returned invitation IDs for a later withdrawal. |
|
|
383
383
|
| `li_withdraw_invitation` | `invitation_id` required; `confirm:true` required | Withdraw one exact currently pending sent invitation after a fresh `li_invitations_sent` read and approval. |
|
|
384
384
|
| `sd_contact_state` | `channel` required (`linkedin`, `whatsapp`, or `email`); `identifiers` required array of 1-8 exact `{kind,value}` objects; `action` optional (`get` default or `suppress`); suppression also requires an allowed `reason` and `confirm:true` | Inspect exact tenant/channel-scoped contact history or add a protective suppression. It never infers that identifiers on different channels belong to one person. |
|
|
385
|
-
| `sd_budget_status` | no arguments | Read the current sender binding,
|
|
385
|
+
| `sd_budget_status` | no arguments | Read the current sender binding, separate invitation, existing-thread message, and own-post engagement daily lanes, the aggregate emergency brake, weekly invitation usage, lock state, and UTC resets from the authoritative server ledger. |
|
|
386
386
|
| `sd_settings_get` | no arguments | Read the authenticated user's persistent SignalDash settings. Auto-accept is the first supported setting and is false for every existing user until explicitly changed. |
|
|
387
387
|
| `sd_settings_set` | `auto_accept_linkedin` required boolean; `auto_accept_linkedin_filters` optional object with `public_identifiers` and `description_keywords`; `confirm:true` required | Update the general per-user settings surface after exact human approval. This changes no future or unknown setting implicitly. |
|
|
388
388
|
| `sd_auto_accept_status` | no arguments | Inspect whether auto-accept is enabled, its exact filters, accepted today and this week, failed attempts today, dedicated and shared capacity, repeated-error stop state, and sanitized unparseable invitation records. |
|
|
@@ -393,7 +393,7 @@ Use the exact tool names and argument keys below. Limits are optional.
|
|
|
393
393
|
| `li_get_invitation_batch` | `batch_id` required | Inspect every stored target, exact note, exclusion, hash, timing, capacity, and result. Use the returned browser review path for human approval. This read also authorizes a later exact cancel. |
|
|
394
394
|
| `li_cancel_invitation_batch` | `batch_id` required; `approval_view_hash` required string or null exactly as inspected; `confirm:true` required | Permanently cancel unstarted targets in one freshly inspected batch. It cannot recall an executing invitation, and restarting requires a new preview and approval. |
|
|
395
395
|
| `sd_campaign_create` | `source_label` required, max 120 code points; `time_zone` required IANA timezone; `messages` required array of 1-5 exact `{text,after_days?}` objects, text max 1200 code points; `target_source` optional (`explicit` default or `post_engagers`); `targets` array of up to 150 `{profile_url?,provider_id?,inclusion_reason,note?,display_name?,headline?,adopt_existing_invitation?}` for `explicit` (at most 10 adopted targets per campaign, and an adopted target may not carry a `note`); `engagers` object with `post_limit` 1-10, `max_targets` 1-150, `inclusion_reason`, `note` for `post_engagers`; `invite_ttl_days` optional 1-60, default 21 | Create one campaign: a connection request to each exact person, then the exact approved message(s) once that person is proven to have accepted, then an optional follow-up that stops on any reply. The server never generates a target or a word of text. Nothing is sent before human approval. |
|
|
396
|
-
| `sd_campaign_preview` | `campaign_id` required | Inspect every exact recipient, every exclusion and reason, the exact text of every message step, the timing, the
|
|
396
|
+
| `sd_campaign_preview` | `campaign_id` required | Inspect every exact recipient, every exclusion and reason, the exact text of every message step, the timing, the invitation and existing-thread message lanes, the aggregate brake, and the `approval_url` to hand the human. This read also authorizes a later exact cancel. |
|
|
397
397
|
| `sd_campaign_approve` | `campaign_id` required; `confirm_token` required in the exact `sd-xxxx-xxxx-xxxx` form the human read off the approval page | Record the human's approval using the single-use code that authenticated page minted for them. An agent cannot mint, guess, or bypass that code. |
|
|
398
398
|
| `sd_campaign_status` | `campaign_id` required | Monitor per person: invited, acceptance proven, messaged, replied and halted, expired, or excluded, plus every message step and any provider response SignalDash could not parse. |
|
|
399
399
|
| `sd_campaign_cancel` | `campaign_id` required; `approval_view_hash` required string or null exactly as inspected; `confirm:true` required | Revoke the approval and stop every unsent invitation and unsent message. It cannot recall an executing write, and restarting requires a new preview and approval. |
|
|
@@ -421,7 +421,7 @@ Use the exact tool names and argument keys below. Limits are optional.
|
|
|
421
421
|
| `li_delete_comment` | `post_id`, `comment_id`, and `confirm:true` required | Currently unavailable: the fixture-tested Unipile v2 wrapper is held at database capability state `untested` until live compatibility is proved against Federico's own removable comment. When enabled it proves own comment identity and readback. Deletion is remediation, not rollback. |
|
|
422
422
|
| `li_draft_post` | `text` required, max 3000; `publish` optional; `scheduled_at` optional offset-qualified ISO date-time; `mentions` optional array of up to 20 exact `{name,profile_id}` objects; `attachments` optional array of up to 4 exact `{filename,content_type,content_base64}` images; `first_comment` optional, max 1250 | Create a server-confirmed draft, publish now, or persist an exact future LinkedIn post and its approved first comment. A schedule is stored only with `publish:true` after approval of the exact text, time, mentions, images, and comment. |
|
|
423
423
|
| `li_set_scheduled_post_first_comment` | `id` required UUID; `first_comment` required, max 1250; `confirm:true` required | Attach one exact approved first comment to a scheduled post. SignalDash publishes it through the same connected account after the post and never republishes the post if the comment fails. |
|
|
424
|
-
| `li_scheduled_posts` | no arguments |
|
|
424
|
+
| `li_scheduled_posts` | no arguments | Read one shared content-calendar view across SignalDash and the configured Buffer LinkedIn channel. Inspect `completeness` and every `sources.*.state` before treating absence as an empty calendar. Native LinkedIn scheduled posts and drafts are invisible because Unipile has no documented read route for them; SignalDash does not use raw Voyager routes or linkedin.com browser access. An empty `items` array proves only that the visible sources returned no entries. |
|
|
425
425
|
| `li_cancel_scheduled_post` | `id` required UUID; `confirm:true` required | Cancel one exact post while it is still scheduled. It cannot recall an executing or published post. |
|
|
426
426
|
| `sd_schedule_message` | `channel` required, `whatsapp` or `linkedin`; `chat_id` required, max 500; `text` required, max 5000; `scheduled_at` required offset-qualified ISO date-time from 60 seconds to 365 days ahead; `confirm:true` required | Schedule one exact message into one chat you have already read. Read that exact chat first, at `limit` 10 or more on LinkedIn: SignalDash records what the thread looked like and refuses at send time if the conversation moved. Text only; attachments are refused rather than dropped. One message at one time, never a sequence. |
|
|
427
427
|
| `sd_scheduled_messages` | `state` optional, one of `scheduled`, `executing`, `sent`, `cancelled`, `failed`, `needs_review`; `channel` optional | List only this authenticated user's scheduled messages and their durable states. Returns every matching row, unpaginated, and always reports `needs_review_count` outside your filter. |
|
|
@@ -510,7 +510,11 @@ permission to publish or schedule. For a future post, first call
|
|
|
510
510
|
offset-qualified UTC instant, mentions, attachment count, and first comment.
|
|
511
511
|
After explicit
|
|
512
512
|
approval, repeat the identical payload with `publish:true`. Verify the stored
|
|
513
|
-
record with `li_scheduled_posts`.
|
|
513
|
+
record with `li_scheduled_posts`. Before scheduling, read that shared view and
|
|
514
|
+
inspect its `completeness` plus the SignalDash, Buffer, and native LinkedIn
|
|
515
|
+
source states. A date conflict in either visible source blocks planning until
|
|
516
|
+
the human resolves it. Native LinkedIn remains explicitly blind, so never call
|
|
517
|
+
an empty result an empty calendar. For an existing scheduled post, use
|
|
514
518
|
`li_set_scheduled_post_first_comment` only after approval of the exact comment.
|
|
515
519
|
SignalDash persists the published post ID before sending the comment, so a
|
|
516
520
|
comment failure never republishes the post. It fails interrupted or ambiguous
|
|
@@ -553,14 +557,24 @@ with `confirm:true`. Allowed reasons are `opt_out`, `not_interested`,
|
|
|
553
557
|
manual LinkedIn work or any campaign action. It reports attempts that
|
|
554
558
|
SignalDash has committed in its authoritative SQLite ledger:
|
|
555
559
|
|
|
556
|
-
-
|
|
560
|
+
- invitations, including accept and single-object withdrawal maintenance;
|
|
561
|
+
- messages into existing threads;
|
|
562
|
+
- replies, reactions, publishing, and first comments on the sender's own posts;
|
|
563
|
+
- the aggregate daily emergency brake (`H`);
|
|
557
564
|
- the campaign-excluded portion (`R = min(4, H)`);
|
|
558
565
|
- the combined ceiling across all campaigns (`C = H - R`);
|
|
559
566
|
- total, manual, campaign, and unknown attempts for the UTC policy day;
|
|
560
|
-
- raw
|
|
567
|
+
- raw per-lane, aggregate, and combined-campaign capacity remaining;
|
|
561
568
|
- actions available now after connection and sender-lock state;
|
|
562
569
|
- weekly LinkedIn invitation usage and its Monday 00:00 UTC reset.
|
|
563
570
|
|
|
571
|
+
The code defaults are 20 invitation actions, 30 existing-thread messages, and
|
|
572
|
+
50 own-post engagement actions per UTC day. A separate aggregate cap of 75 is
|
|
573
|
+
the emergency brake across them. The three lane caps do not add into a promise
|
|
574
|
+
of 100 actions. Every lane still uses the same serialized provider queue and
|
|
575
|
+
its existing action-specific randomized pacing. The default 100-attempt UTC
|
|
576
|
+
week for sent invitations remains separate and unchanged.
|
|
577
|
+
|
|
564
578
|
`R` is capacity campaigns cannot consume. It is not a reserve or guaranteed
|
|
565
579
|
manual allowance: manual activity can consume the total cap first, and a later
|
|
566
580
|
manual action can still be rejected at `H`. Campaign capacity is shared across
|
|
@@ -1270,10 +1284,14 @@ public LinkedIn posts.
|
|
|
1270
1284
|
9. Confirm delivery by reading the thread after the action.
|
|
1271
1285
|
10. Account health outranks throughput and task completion.
|
|
1272
1286
|
|
|
1273
|
-
The hosted backend defaults to
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
100-attempt
|
|
1287
|
+
The hosted backend defaults to three LinkedIn lanes per stable logical sender
|
|
1288
|
+
and UTC day: 20 invitation actions, 30 messages in existing threads, and 50
|
|
1289
|
+
own-post engagement actions. An aggregate 75-attempt emergency brake bounds the
|
|
1290
|
+
combined lanes. Invitation sends also use the unchanged default 100-attempt
|
|
1291
|
+
weekly policy. Separate counters do not alter randomized action spacing, the
|
|
1292
|
+
single serialized provider queue, duplicate protection, or provider-warning
|
|
1293
|
+
locks. An exact comment reply text already submitted by that sender on the same
|
|
1294
|
+
UTC day is refused as `duplicate_comment_text`.
|
|
1277
1295
|
|
|
1278
1296
|
WhatsApp and email share ONE separate daily bucket, and it is independent of
|
|
1279
1297
|
the LinkedIn one: a WhatsApp message never spends LinkedIn capacity and a
|
|
@@ -1750,8 +1768,10 @@ Before reporting completion, verify:
|
|
|
1750
1768
|
- No sender lock or `outcome_unknown` result was retried.
|
|
1751
1769
|
- A send was confirmed by a post-send read.
|
|
1752
1770
|
- A post draft remained unpublished and unscheduled unless `publish:true` was
|
|
1753
|
-
explicitly approved.
|
|
1754
|
-
|
|
1771
|
+
explicitly approved. The shared calendar was read first, its source-specific
|
|
1772
|
+
completeness was reported, and every visible scheduled post was read back
|
|
1773
|
+
with its exact UTC instant, source, and durable state. Native LinkedIn
|
|
1774
|
+
blindness was never represented as an empty calendar.
|
|
1755
1775
|
- An export ended with `+ saved` and a non-empty CSV.
|
|
1756
1776
|
|
|
1757
1777
|
If any item is unverified, state exactly what remains incomplete.
|
|
@@ -77,15 +77,20 @@ On no, call `sd_secretary_reject` for that exact disposition and send nothing.
|
|
|
77
77
|
Inspect `already_in_contact`, `contact_state`, and `blocking_reasons`.
|
|
78
78
|
Resolve, review, and approve every later action through its one-object flow.
|
|
79
79
|
- Read `sd_budget_status` before planning multiple LinkedIn actions. Treat its
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
attempts, not all
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
80
|
+
invitation, existing-thread message, and own-post engagement lanes
|
|
81
|
+
separately. Treat the aggregate cap and campaign-excluded portion as brakes,
|
|
82
|
+
never as a promised allowance. Its counts cover SignalDash attempts, not all
|
|
83
|
+
native LinkedIn activity.
|
|
84
|
+
- Keep normal messaging at human volume. Code defaults are 20 invitation
|
|
85
|
+
actions, 30 existing-thread messages, 50 own-post engagement actions, and a
|
|
86
|
+
75-attempt aggregate brake per UTC day. The unchanged sent-invitation policy
|
|
87
|
+
also caps attempts at 100 per UTC week.
|
|
86
88
|
- Let SignalDash serialize LinkedIn writes and apply action-specific jitter. Do
|
|
87
89
|
not parallelize write calls or bypass the guard. Invitation jitter completes
|
|
88
90
|
before the server's final provider preflight and action reservation.
|
|
91
|
+
- Never reuse exact comment reply text during the same UTC day. SignalDash
|
|
92
|
+
refuses it as `duplicate_comment_text`; changing punctuation only to evade
|
|
93
|
+
that guard is prohibited.
|
|
89
94
|
- Campaign invitations use a sender-local Monday-Friday 09:00-17:00 work
|
|
90
95
|
window and a durable 90-180 second per-sender pacing interval. Timing is
|
|
91
96
|
checked before final preflight and atomically during action reservation.
|