Commit graph naco-api/internal/server/analytics.go
Author SHA1 Message Date
7a21437120
docs: tidy stale comments in analytics, cache version, and style profile test
Some checks failed
Test Every Endpoint on Base Sepolia / test_endpoints (push) Failing after 6m33s
CI/CD Go Verification / build_and_test (push) Successful in 1m32s
2026-09-13 22:24:45 +00:00
e68e02bf20
feat: data-driven upto scheme registration for twitter-enabled tools
Extend x402 actual-cost settlement beyond getStyleProfile to every
Twitter-capable tool (findSimilarUsers, getEngagementMetrics,
getPostingPatterns, getTopicModeling, getSentimentTrends,
getEngagementDrivers). Each carries a twitterPostCount (or source
platform + post count) in its response so settlement passes on the
realized Twitter API lookup and per-post costs.

- tools: payableDef uses UsesTwitter + TwitterPostCap instead of a
  fixed Scheme; registerTools advertises upto at the cap-derived
  maximum when Twitter is enabled, otherwise exact at the flat base
  price.
- x402: export pricing constants and MaxTwitterCostMicro /
  FormatPriceMicro / MicroFromPriceString helpers; add
  AddPayableToolWithResolver and a per-tool settleResolvers map used
  by both the MCP wrapper and REST override; buildSchemeConfigs
  registers only the schemes declared in a tool's requirements.
- analytics: default aggregates include Twitter only when enabled;
  result count recorded before caching and returned as twitterPostCount.
- server/twitterEnabled gates the upto switch (config bearer token).
2026-09-09 13:27:17 +00:00
debd49d6f6
chore: quiet errcheck/staticcheck across server, platform, and test clients 2026-09-08 01:29:28 +00:00
a218b8fbf5
refactor(server): split server.go into focused modules (phases 1-4)
Phase 1: mechanical splits
- platform.go: determinePlatform
- settlement.go: settleHook, buildRequirements, parseActiveNetworks
- posts_convert.go: bsky/ap/nostr/twitter single converters
- actors.go: searchActorsAll, dedupeActors, normalizeHandle
- posts.go: fetchSinglePost/fetchLatestPosts/fetchPostsInTime/fetchFeed
- style.go: getStyleProfile, requestStyleProfile*, enrichCrossPlatform,
  getSimilarProfiles, buildStyleProfile, fetchProfilePosts, toItems
- prewarm.go: StartPrewarm, discoverInterestingAuthors, prewarmOne, startPostPruner

Phase 2: deduplicate registerTools
- tools.go: table-driven payableDef + schemaExtra helper, analyticsInput reuse
- server.go 1814 -> 180 lines, registerTools 470 -> 150 lines

Phase 3: unify platform dispatch
- cache.go: generic cachedFetch[T]
- posts_convert.go: batch converters (blueskyFeedViewsToResponses,
  apPosts*ToResponses, nostr/twitter variants) and clustering Item
  variants (blueskyFeedViewsToAnalyticsItems etc.)
- posts.go: use cachedFetch + batch helpers, fetchFeed via helper
- style.go: fetchProfilePosts via *ToItems helpers
- analytics.go: fetchPostsInTimeForAnalytics/fetchTwitterFromAPI via analytics helpers

Phase 4: slim bootstrap
- server_init.go: buildMiddleware, resolveActiveNetworks, newX402Server,
  persistSettlement, sendSettlementWebhook (deduplicate settleHook)
- server.go: New 120 -> 32 lines, grouped Server fields by
  Transport/Dependencies/Cache/Payments, keep struct compat for tests
- verified: gofmt clean, go build/vet pass, go test ./... pass
2026-09-03 23:59:16 +00:00
90af0ec4fc refactor(server): split mcp_test into focused suites with fakeStore/fakeOllama
- extract analytics, searchactors, styleprofile, twitter_analytics, validation, storefake from mcp_test
- add fakeStore/fakeOllama harnesses, lastLimit tracking, sql.NullTime staleness
- expand mcp_test with per-platform GetPost/Latest/PostsInTime, actor and cache tests
- touch analytics/backends/cache_version/metrics/server for coverage
2026-09-03 17:00:32 +00:00
0dcb74675e fix(analytics,x402): fix coverage gaps, engagement drivers, and Twitter cost passing
Analytics review fixes:
- Store Twitter analytics coverage as discrete intervals instead of a single
  contiguous window so disjoint fetch ranges no longer mask inner gaps as
  covered (fetch per uncovered range, add gap regression tests)
- Compute real AvgEngagement/Correlation in getEngagementDrivers instead of
  all-zero placeholders
- Make parseAnalyticsTimeRange surface invalid timestamps, cap merged analytics
  posts at limit, and normalize sentiment by timestamped posts only
- gofmt: fix misalignment in config.go and types.go
- Include Twitter in the default aggregate analytics scope; its API costs are
  passed to the caller through paid tool pricing

x402 cost passing:
- computeTwitterStyleProfileCost now charges base cost ($0.10) + user lookup
  ($0.01) + $0.005 per Twitter post, guaranteeing the charge always clears the
  underlying API cost (never break-even or loss)
- Return a $-prefixed dollar string for the settlement override, fixing the
  previously off-by-factor-100 raw-atomic-unit amount
- Raise getStyleProfile base registration to $0.36 to authorize the max Twitter
  charge
- Add tests for the cost formula, profitable floor, and dollar formatting
2026-09-02 22:44:02 +00:00
c6b73cba1f feat: add analytics tools with real engagement, pattern, topic and sentiment computation
Register five payable analytics MCP tools (engagement metrics, posting
patterns, topic modeling, sentiment trends, engagement drivers).

- Thread real post timestamps and engagement metrics through the compute
  functions instead of time.Now()/zero placeholders (enabled by the
  enriched clustering.Item).
- Report the requested author (args.Author) instead of a literal string.
- Implement sentiment shift detection (from/to/magnitude) ordered by time.
- Cache analytics results keyed by scope: a single "all" key for
  cross-platform aggregates and per-platform keys for single-platform
  queries, so aggregate results are not mixed with partial data.
- Use configurable per-tool cache TTLs stored on the Server.

Also cache Twitter post data permanently to avoid repeat paid API calls:
newly fetched posts are persisted, and a coverage watermark (analytics
coverage table) ensures the paid Twitter API is only called for time
ranges not already retrieved.
2026-09-02 23:49:54 +02:00