5 Commits
Author SHA1 Message Date
viettranx 3b4004946e chore: apply go fix syntax upgrades (min/max, switch patterns)
Apply Go 1.21+ min/max builtins and improved switch pattern matching
across test files and utilities. No functional changes.
2026-04-15 11:24:57 +07:00
53704b1c69 fix(facebook): preserve fb_mode in outbound routing + admin reply detection (#860)
* fix(facebook): preserve fb_mode metadata in outbound routing + admin reply detection

Two issues fixed:

1. Messenger auto-reply never delivered because fb_mode metadata was
   stripped during outbound message construction. The routing whitelist
   in gateway_consumer_normal.go and channels/events.go only copied
   thread_id/local_key/group_id — facebook-specific keys (fb_mode,
   sender_id, page_id, reply_to_comment_id) were dropped, causing
   facebook.Send() to fall into the comment path and fail with
   "reply_to_comment_id missing".

2. Added admin reply detection: before sending a bot reply, check via
   Graph API if the last page message in the conversation was sent by
   an admin (human) rather than the bot itself. Skips bot reply when
   admin already responded, preventing duplicate messages.

   Uses timestamp comparison with bot's own send history to distinguish
   bot-sent vs admin-sent page messages (both have from.id = page_id).

* chore: exclude compiled binary from git

* fix(facebook): ignore bot echoes in messenger cooldown

* fix(facebook): add memory cleanup for admin reply maps and reduce echo window

- Add adminReplied and botSentAt eviction to runDedupCleaner to prevent
  unbounded memory growth on high-traffic pages
- Reduce botEchoWindow from 60s to 15s to avoid misclassifying real admin
  replies as bot echoes
- Restore doc comments on routingMetaKeys and copyRoutingMeta
- Add cross-reference comment between consumer and events routing key lists
- Simplify admin-reply skip log (remove redundant map re-read)

---------

Co-authored-by: khanhtran <>
Co-authored-by: Plateau Nguyen <nguyennlt.ncc@gmail.com>
Co-authored-by: viettranx <viettranx@gmail.com>
2026-04-13 21:13:28 +07:00
viettranx 0c44149fad test: speed up retry/cron/facebook tests, drop coverage ratchet gate
Slow tests were dominating CI feedback time and AI dev loop because they
waited through real exponential backoffs and 1s ticker intervals.
Test-only override pattern keeps production behavior 100% identical.

Speed wins (no-race wall-clock per package):
- internal/vault            16.3s -> 0.6s   (-15.7s)
- internal/cron             11.7s -> 1.5s   (-10.2s)
- internal/channels/facebook 6.3s -> 3.0s   (-3.3s)
- Full -race ./... suite     90s+ -> 51s

Changes:
- vault: new fastBackoffsForTest(t) helper overrides enrichRetryBackoffs
  + enrichRetryTimeouts to 1ms in 3 retry tests; drop 2 duplicate tests
  (FirstAttemptSuccess, MaxRetriesConstant)
- cron: extract runLoopTickInterval as package var (default 1s); test-only
  setFastTick(t) helper shortens to 20ms so 6 scheduler tests no longer
  sleep 1.5s each waiting for a tick
- facebook: extract graphBackoffBase as package var (default 1s); newFakeGraph
  helper shortens to 1ms so HTTP retry tests don't burn 6s of real waits

Coverage ratchet removed:
- Delete scripts/check_coverage.go + scripts/coverage_thresholds.json
- Remove "Coverage ratchet gate" CI step
- Keep coverage profile + go tool cover summary as informational only
- Philosophy: signal over coverage %. Forced tests to bump % were the
  root cause of the slowness this commit unwinds.

Production behavior unchanged. Coverage profile shows isolated package
coverage matches prior thresholds (vault 27.4%, cron 73.7%, facebook 81.9%).
2026-04-11 23:53:07 +07:00
viettranx f2c43c3849 test(facebook,store/pg): wave B coverage push
Phase 03 - facebook 23.1% -> 81.9% (+58.8%, target ≥60%)
  graph_api_test.go: NewGraphClient, VerifyToken, SubscribeApp, GetPost,
  GetComment, GetCommentThread, ReplyToComment, SendMessage, SendTypingOn,
  doRequest retry/backoff matrix (5xx retry, 401 non-retry, 429+Retry-After,
  context cancel during backoff, transport error + retry), 551/subcode 24h
  window non-retry, logRateLimit parse branches.

  handlers_test.go: New required-field validation (4 branches), Factory
  valid+malformed, WebhookHandler single-shot route, handleAPIError health
  state mapping, handleCommentEvent (feature gate, edit/remove drop, page
  routing, self-reply skip, dedup, enriched content path), handleMessagingEvent
  (feature gate, page routing, self skip, receipt drop, text+postback dispatch,
  dedup), Send Messenger+comment paths + missing-metadata error, sendFirstInbox
  one-shot dedup, runDedupCleaner stale eviction, Stop closes deps, webhookRouter
  register/unregister/route-once/ServeHTTP-no-instances, PostFetcher (defaults,
  empty-id, cache hit/miss/expired, error propagation, GetCommentThread
  empty+delegate).

  Minimal refactor: converted package-level graphAPIBase const to var so tests
  can point at httptest server. KISS, zero runtime behavior change.

Phase 04 - store/pg 1.3% -> 3.5% (+2.2%, unit-test-only)
  scan_rows_test.go: pure-logic transformation tests for agentShareRow,
  userInstanceRow, documentInfoRow, documentDetailRow, chunkInfoRow,
  scoredChunkRow, episodicSummaryRow, episodicScoredRow, sessionListRow,
  sessionPagedRow, sessionRichRow, entityRow, entityTemporalRow, relationRow,
  relationExportRow, traversalRow, dedupCandidateRow, mcpAccessRequestRow,
  cronRunLogRow, skillInfoRow+skillInfoRowWithFrontmatter, customSkillExportRow,
  parseDepsColumn, parseFrontmatterAuthor, marshalFrontmatter, buildSkillInfo,
  mergeEpisodicScores, hybridMerge.

  pure_logic_test.go: matchWildcard pattern matching, evalPermRows priority
  resolution (individual deny > individual allow > group deny > group allow),
  contactResolveCache get/set/expired/negative cache.

  Finding: 30% target not reachable with unit tests alone. Store/pg is
  fundamentally DB-bound (~6000 LOC of SQL code vs ~200 LOC pure logic).
  Reaching 30% requires running integration tests with TEST_DATABASE_URL and
  -coverpkg=./internal/store/pg/ — which the current CI ratchet does NOT
  do. Confirmed: integration tests yield 32% coverage on store/pg, but that
  requires a wired-up test database in CI. Deferred as infrastructure change
  outside Phase 04 scope.

Ratchet bumps (scripts/coverage_thresholds.json):
- internal/channels/facebook: 23.08 -> 81.80
- internal/store/pg: 1.28 -> 3.45

Race clean, dual build (default + -tags sqliteonly) clean.
2026-04-11 21:47:22 +07:00
Plateau Nguyen fb8afd41bf feat(channels): add Facebook Messenger and Pancake channel integrations (#731)
Add two new channel implementations for Facebook Fanpage (comment + Messenger
auto-reply, first inbox DM) and Pancake/pages.fm (multi-platform inbox via
Facebook, Zalo, Instagram, TikTok, WhatsApp, LINE).

Key features:
- Facebook: comment auto-reply, Messenger auto-reply, first inbox DM,
  HMAC-SHA256 webhook verification, multi-page webhook routing
- Pancake: multi-platform inbox, outbound echo dedup with HTML normalization,
  race-condition-safe echo fingerprinting, platform-aware formatting
- Bootstrap skip: pre-fill USER.md from channel metadata (Pancake)
- SanitizeDisplayName across all channels (defense in depth)

Code audit fixes:
- Fix truncateForTikTok byte→rune slicing (UTF-8 corruption)
- Fix empty message.ID shared dedup slot (silent message loss)
- Fix DisplayName markdown injection in buildPrefilledUser
- Consolidate duplicate ChannelMeta type (agent→bootstrap)
- Compile-time interface assertions, alphabetical type constants
- Per-message logs demoted to slog.Debug, errors.As for wrapped errors
- UI: alphabetical channel ordering, complete config schemas
- Remove deprecated WhatsApp bridge_url, fix nested error parsing
2026-04-09 23:15:08 +07:00