- Workflow: X402_FACILITATOR_URL -> https://v2.facilitator.mogami.tech/
- start-test-server.sh: same facilitator URL
- check-facilitator: auto-detects facilitator type, skips auth for Mogami
- This unblocks CI testing while CDP facilitator auth is investigated
- New cmd/check-facilitator/main.go uses internal/server auth package (same logic as server)
- CI workflow builds and runs binary instead of inline script
- Ensures auth logic matches server exactly, eliminates drift
- Prints supported networks/kinds from facilitator /supported endpoint
- New step 'Check Facilitator Supported Networks' queries CDP facilitator /supported endpoint with proper auth
- Uses same CDP auth logic as server (JWT with keyName/privateKey)
- Prints supported networks/kinds to verify Base Sepolia (eip155:84532) support
- Runs before starting test server to catch facilitator config issues early
- x402: wrap payment middleware to log verify failures (decoded PAYMENT-REQUIRED with scheme/network/asset/amount/payTo per accept) and settlement errors
- x402: add verifyErrorCapture and decodePaymentRequiredHeader for structured error logging
- start-test-server.sh: build binary first (go build -o /tmp/mcpserver), run with output redirected to log file, wait 2s on shutdown for log flush
- workflow: Cleanup uses kill -TERM + sleep 2 to let server flush logs
- main.go: defer log.Close() to flush slog handlers on shutdown
- All tests pass, gofmt/go vet clean
- x402: add detailed settlement success/error logging per tool (network, tx, payer, amount) and ErrorHandler for settlement failures that currently return a new 402
- server_init: log persisting HTTP and MCP settlements with transaction details
- workflow: dump /tmp/mcpserver-test.log on failure and tail 500 lines on always for debugging Base Sepolia exact/upto flows
The test client now registers both 'exact' and 'upto' EVM payment schemes
for the test network (eip155:84532 / Base Sepolia) to match the server's
scheme registration. This allows the x402 HTTP client wrapper to
automatically handle 402 Payment Required responses by selecting and
paying with a supported scheme, then retrying the request.
The HTTP middleware in AddPayableTool was hardcoded to only register
the exact scheme for eip155:8453 (Base mainnet), while the MCP handler
registered both exact and upto schemes for all networks from ACTIVE_NETWORKS.
This mismatch caused 'no scheme server for exact on eip155:84532' errors
when testing with Sepolia.
Changes:
- Added networks field to X402Server struct to store active networks
- Store networks in NewX402Server constructor
- In AddPayableTool, dynamically register both exact and upto EVM
schemes for all configured networks instead of hardcoding eip155:8453
- Updated tests to pass correct network configuration
callEndpoint now returns error for any HTTP status >= 400 except 402,
which is the expected status for payable endpoints. Previously 500
errors were treated as success, masking server errors like
'no scheme server for exact on eip155:84532'.
- x402.NewX402Server now accepts networks []string parameter to register
exact/upto EVM schemes for each network
- server_init.go passes resolved active networks (from resolveActiveNetworks)
to x402 server - includes eip155:84532 (sepolia), eip155:8453 (base),
and any other configured networks
- Registers both exact and upto schemes per network
- Updates x402_test.go calls to pass []string{}
- Fixes: 'no scheme server for exact on eip155:84532' error
Server was passing only ListenAddress (127.0.0.1) without port to x402.Start,
causing 'listen tcp: address 127.0.0.1: missing port in address'.
Now combines address:port for TCP when no port already present and
not a unix socket. Keeps unix socket paths unchanged.
- config: MATRIX_WEBHOOK_URL / MATRIX_SERVER_ID via os.Getenv (optional),
keep hostname fallback for MatrixServerID, avoid Fatal when webhook
not configured (test-endpoints omits it, webhook.go nil-safe)
- auth: NewCDPAuth converts literal \n to real newlines before
pem.Decode, so Forgejo single-line secret
-----BEGIN EC PRIVATE KEY-----\n... works while malformed
still returns error and CI fails via log.Fatal (as required)
- ollama image takes >60s and healthcheck curl fails inside container
(marking service not healthy and aborting job before steps run).
Remove ollama healthcheck from services, let Wait steps poll.
- Wait for PostgreSQL/Ollama try both localhost and service hostnames
(postgres / ollama) for 60-90 retries, as Act network is
WORKFLOW-* where localhost != service.
- Pull models via HTTP POST /api/pull to whichever host responds
(no docker exec needed for services).
- start-test-server.sh: respect GOOSE_DBSTRING/OLLAMA_HOST from env,
auto-detect postgres/ollama service hostnames if localhost not reachable.
setup-docker-action requires --privileged + iptables + bridge NAT
(failed: Permission denied, nft netlink Operation not permitted,
iptables v1.8.9 nf_tables even as root). Runner job container is
unprivileged, and host dind socket not mounted (/var/run/docker.sock
no such file). Switch to services: postgres pgvector/pg16 and
ollama/ollama:latest as job services on node20 (has node for checkout),
so no docker CLI/daemon needed inside job. Wait via pg_isready
(apt install postgresql-client if missing) and curl /api/tags, pull
models via Ollama HTTP API POST /api/pull (no docker exec). Keeps
manual wallet funding, self-contained via services.
setup-docker-action starts dockerd inside job requiring bridge
NAT chain (iptables) and --privileged. node:20-bookworm has no
sudo/iptables, causing iptables not found / bridge driver failure.
Add apt install sudo+iptables before setup and run job container
privileged so self-contained dockerd can start; keeps host dind
fallback not needed. Host dind socket not mounted (no such file),
so nested daemon is required.
setup-docker-action@v5 starts dockerd via sudo; node:20-bookworm
image runs as root without sudo binary, causing
/bin/sh: 1: sudo: not found / exit 1. Install sudo via apt-get when
missing so self-contained dockerd can start. Keeps runs-on: node20
(has node for checkout) + dind host, no custom image needed.
- runs-on node20 has node for checkout, use docker/setup-docker-action@v5
for self-contained dockerd (no host dind dependency) instead of
setup-compose only
- install: drop foundry/cast and bc (manual funding) -> go mod download only
- remove Fund Test/Server Wallet steps, FUNDING_FAUCET_URL env
- docker-compose -> docker compose via setup-docker, add logs on wait failures
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
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.
Carry post metadata (timestamp, likes, reposts, replies, quotes) through
the clustering pipeline so analytics compute functions can use real values
instead of placeholders. The clustering algorithm only consumes Text and
Embedding, so this is backward-compatible.
Add tables backing the analytics cache, the permanent per-platform post
store, and the coverage watermark used to avoid re-fetching paid Twitter
posts once a time range has already been retrieved.
- Pull Ollama Models step now uses ${EMBEDDING_MODEL} and ${STYLE_MODEL}
- Values sourced from config/models.env in Load model config step
---
- Use $FORGEJO instead of $GITHUB variables
- config/models.env: EMBEDDING_MODEL and STYLE_MODEL defaults
- config.go: loads models.env by finding project root (go.mod), removes hardcoded defaults
- test-endpoints.yaml: sources config/models.env to set env vars for CI
- Works from any working directory (server, tests, CI)
- Instruction-tuned variant for reliable prompt following
- Q4_K_M quantization for CPU latency optimization
- Updated test workflow to pull correct model
- config.go: set EMBEDDING_MODEL=qwen3-embedding:0.6b, STYLE_MODEL=qwen3:4b as defaults
- ollama/client.go: remove hardcoded fallback logic, use passed values directly
- Single source of truth for model defaults in config package
- Migration 002: VECTOR(768) -> VECTOR(1024) to match qwen3-embedding:0.6b default output
- integration_test.go: update test vector from 768 to 1024 dimensions
- schema: add IF NOT EXISTS to CREATE TABLE/INDEX for idempotent migrations
- store: regenerate with sqlc v1.31.1 (adds UserStylePost, interface{} for Embedding)
- webhook: minor formatting cleanup