Skip to content

BARRYPMARSHALL/triad-core-framework

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Triad Core Framework

A2A Agent Acquisition Architecture — Autonomous Mesh of OSINT Scouts, Deterministic Gatekeepers, and Decentralized Revenue Settlement

Version License Architecture

⚠️ DISCLAIMER: This repository is a white-label multi-agent infrastructure framework designed for academic research, data collection engineering, and sovereign machine-to-machine telemetry testing. It contains no pre-packaged alpha generation strategies, deployment parameters, or quantitative trade indicators. Users must explicitly code their own algorithmic modules. Use at your own risk.


Table of Contents


Philosophy: Separation of Powers

The Triad Core Framework is built on a strict Separation of Powers architecture — the single most important design decision in the system.

┌─────────────────────────────────────────────────────────────┐
│                     SEPARATION OF POWERS                     │
├────────────────────────┬────────────────────────────────────┤
│    SCOUT AGENT         │         GATEKEEPER AGENT           │
│    (Secondary Node)    │         (Primary Node)             │
├────────────────────────┼────────────────────────────────────┤
│ Unstructured heuristics│  Deterministic mathematics         │
│ LLM text parsing       │  No LLM inference                  │
│ Probabilistic signals  │  Hard numerical validation         │
│ Web scraping / OSINT   │  Revenue settlement                │
│ Creative data sources  │  Exclusive vault control           │
│                        │  Mesh authentication               │
├────────────────────────┴────────────────────────────────────┤
│                    LAN Mesh (HTTP/JSON)                      │
│         scout:8877 → POST telemetry → gatekeeper:8877        │
└─────────────────────────────────────────────────────────────┘

Why this matters:

The Scout Agent can hallucinate, speculate, and scrape creatively — that's its job. But the Gatekeeper Agent never interprets natural language, never runs an LLM, and never makes probabilistic judgments. It receives only mathematically validated numerical vectors and enforces rigid statistical hurdles before any data enters the revenue pipeline.

This means a broken or compromised scout cannot corrupt the gatekeeper's decision engine or divert revenue. The vault address is loaded dynamically from the USER_METAMASK_ADDRESS environment variable — no hardcoded strings, no runtime overrides. Every deployer defines their own.


Architecture Overview

                    ┌──────────────────────────────────┐
                    │         EXTERNAL WORLD            │
                    │  (Buying Agents / Web3 Wallets)   │
                    └──────────────┬───────────────────┘
                                   │
                    Paying agents  │  POL/USDC → vault
                    GET /get-alpha │  (from .env config)
                                   │
                    ┌──────────────▼───────────────────┐
                    │        GATEKEEPER AGENT           │
                    │    Flask IPC — 0.0.0.0:8877      │
                    │                                   │
                    │  ┌───────────────────────────┐    │
                    │  │  Mathematical Hurdles      │    │
                    │  │  • Z-score bounds [-4, 4]  │    │
                    │  │  • Finite real check       │    │
                    │  │  • Confidence [0, 1] clamp │    │
                    │  │  • Composite alpha score   │    │
                    │  └───────────────────────────┘    │
                    │                                   │
                    │  ┌───────────────────────────┐    │
                    │  │  Revenue Engine            │    │
                    │  │  • Micro-fee: 0.001 POL    │    │
                    │  │  • Vault from env → locked │    │
                    │  └───────────────────────────┘    │
                    └──────────────┬───────────────────┘
                                   │
               LAN Mesh (Wi-Fi)   │  HTTP POST
                                   │
                    ┌──────────────▼───────────────────┐
                    │         SCOUT AGENT               │
                    │   Python stdlib — no Flask       │
                    │                                   │
                    │  Sources:                         │
                    │  • SEC EDGAR 8-K filings          │
                    │  • IR transcripts                 │
                    │  • Threat feeds (OSINT)            │
                    │  • Geopolitical signals           │
                    │                                   │
                    │  Output: minified JSON telemetry  │
                    └──────────────────────────────────┘
                                   │
                    ┌──────────────▼───────────────────┐
                    │         REDIS MESSAGE BROKER      │
                    │   Optional — stream buffering    │
                    └──────────────────────────────────┘

System Components

1. Scout Agent

Location: scout_agent/scout.py Runtime: Python 3.11 (stdlib only — no Flask, no web3) Node: Secondary Ubuntu laptop

The Scout Agent performs unstructured web scraping and OSINT gathering from configurable sources. It:

  • Scrapes SEC EDGAR for 8-K filings, IR transcripts, and regulatory disclosures
  • Computes Z-score deltas from raw numerical data
  • Packages findings into standardised JSON telemetry packets
  • POSTs packets to the Gatekeeper over the local LAN mesh
  • Sends periodic heartbeats to verify connectivity

Modes:

  • python scout.py --once — single pass (cron-friendly)
  • python scout.py --daemon — continuous loop with configurable interval
  • python scout.py --once --verbose — debug single pass with full output

Design principle: The Scout contains no business logic for revenue, settlement, or authentication. It is a pure data collection and forwarding layer.

2. Gatekeeper Agent

Location: gatekeeper_agent/gatekeeper.py Runtime: Python 3.11 + Flask + Gunicorn Node: Primary Ubuntu workstation (this machine) Port: 8877 (bound to 0.0.0.0)

The Gatekeeper Agent is the core of the system. It:

  • Listens for scout telemetry on /alphafeed/scout-stream
  • Runs every incoming data vector through MathHurdles — a strict mathematical validation engine
  • Tracks revenue accrual with the vault address from USER_METAMASK_ADDRESS as the exclusive withdrawal target
  • Serves validated alpha data to paying external agents via /alphafeed/get-alpha
  • Maintains mesh health state via heartbeat monitoring
  • Exposes an A2A discovery manifest at /.well-known/ai-agents.json

Critical invariant: The vault address is populated from the USER_METAMASK_ADDRESS environment variable at runtime. It is never hardcoded in source. Every user must define their own vault address in .env before starting the Gatekeeper. This prevents supply-chain attacks from redirecting revenue — the operating system's env var scope is your security boundary.

3. Redis Message Broker

Location: docker-compose.yml (Redis 7 Alpine container) Port: 6379

Redis provides optional stream buffering between the Scout and Gatekeeper. If the Gatekeeper is temporarily unavailable, scout telemetry is queued in Redis and replayed on reconnection. In dual-node deployments, Redis runs on the primary node only.

4. Mesh Watchdog

Location:

  • mesh/watchdog.py — monitors secondary node freshness
  • mesh/heartbeat_client.py — sends periodic heartbeats from secondary node

The watchdog checks that the secondary node has sent a heartbeat within the last 300 seconds (configurable via STALE_THRESHOLD). If a node goes dark, the watchdog logs an alert and exits non-zero for external monitoring systems to pick up.


Quick Start

Single-Node (Docker Compose)

Run the entire stack on one machine for development and testing:

# 1. Clone the repository
git clone https://github.com/BARRYPMARSHALL/triad-core-framework.git
cd triad-core-framework

# 2. Configure environment
cp .env.example .env
# Edit .env — set USER_METAMASK_ADDRESS to your Polygon wallet address.
# The Gatekeeper will refuse to start without it.

# 3. Launch all services
docker compose up -d

# 4. Verify everything is running
docker compose ps
curl http://localhost:8877/alphafeed/health

# 5. Watch the revenue log
tail -f /tmp/gatekeeper_revenue.log

# 6. View service logs
docker compose logs -f scout
docker compose logs -f gatekeeper

Dual-Node (Bare Metal)

Deploy across two physical Ubuntu laptops connected via the same local LAN (Wi-Fi or ethernet). This section walks you through every command necessary.

Step 0 — Find Your Local IP Addresses

On both nodes, run one of these to find the LAN IP (typically starts with 192.168.x.x, 10.x.x.x, or 172.16.x.x):

# Option A — modern Linux
ip route show | grep -oP 'src \K[0-9.]+'

# Option B — fallback
hostname -I | awk '{print $1}'

# Option C — legacy systems
ifconfig | grep -E 'inet ' | grep -v '127.0.0.1' | awk '{print $2}'

Make a note of both IPs. For this guide:

  • Primary (Gatekeeper) node: 192.168.1.75
  • Secondary (Scout) node: 192.168.1.100

Replace these with your actual IPs throughout.


Primary Node — Gatekeeper Setup

# On the primary workstation (192.168.1.75):

# 1. Install system dependencies
sudo apt update && sudo apt install -y python3-pip git redis-server ufw

# 2. Clone the repository
git clone https://github.com/BARRYPMARSHALL/triad-core-framework.git
cd triad-core-framework

# 3. Install Python dependencies
pip install -r gatekeeper_agent/requirements.txt

# 4. Configure UFW firewall — allow only the scout node on port 8877
#    Replace <scout_ip> with the actual IP of the secondary laptop
sudo ufw allow from 192.168.1.100 to any port 8877 proto tcp
#    Also allow SSH if you manage remotely
# sudo ufw allow ssh
sudo ufw enable
sudo ufw status  # verify: 8877 ALLOW FROM 192.168.1.100

# 5. Set your vault address and start the Gatekeeper
cd gatekeeper_agent
USER_METAMASK_ADDRESS="0xYourMetaMaskWalletAddress" \
  MESH_KEY="your-strong-mesh-key" \
  python3 gatekeeper.py

# 6. (Optional) Start Redis for stream buffering
sudo systemctl start redis-server

Secondary Node — Scout Agent Setup

# On the secondary laptop (192.168.1.100):

# 1. Install Python 3.11
sudo apt update && sudo apt install -y python3 ufw

# 2. Clone the repository
git clone https://github.com/BARRYPMARSHALL/triad-core-framework.git
cd triad-core-framework

# 3. Verify the network socket to the Gatekeeper BEFORE launching
#    Replace <gatekeeper_ip> with the primary node's LAN IP
nc -zv 192.168.1.75 8877
# Expected output:
#   Connection to 192.168.1.75 port 8877 [tcp/*] succeeded!
# If you see "Connection refused", troubleshoot before proceeding:
#   - Is the Gatekeeper running on the primary node?
#   - Is UFW allowing traffic from this IP?
#   - Are both machines on the same subnet?

# 4. Run the Scout Agent pointing at the Gatekeeper's LAN IP
cd scout_agent
GATEKEEPER_URL=http://192.168.1.75:8877 \
  MESH_KEY="your-strong-mesh-key" \
  SCOUT_NODE_ID="tigerwolf-laptop" \
  python3 scout.py --daemon

# 5. In a separate terminal, start the heartbeat client
cd ../mesh
GATEKEEPER_URL=http://192.168.1.75:8877 \
  MESH_KEY="your-strong-mesh-key" \
  python3 heartbeat_client.py

Verify the Mesh

# From any machine on the LAN:
curl -s http://192.168.1.75:8877/alphafeed/mesh/status \
  -H "X-Mesh-Key: your-strong-mesh-key" | python3 -m json.tool

Expected output:

{
    "mesh_id": "triad-core-alpha-feed",
    "nodes": {
        "tigerwolf-laptop": {
            "last_seen": "2026-06-04T08:55:31",
            "ip": "192.168.1.100",
            "status": "online"
        }
    },
    "metrics": {
        "heartbeats_received": 12,
        "scout_packets_ingested": 5,
        "scout_errors": 0
    },
    "revenue": {
        "vault": "0xYourMetaMaskWalletAddress",
        "total_pol": 0.005
    }
}

Environment Variables

All configuration is done through environment variables. The vault address is loaded dynamically from .env — no hardcoded wallet strings exist in the source code.

Variable Default Description
PORT 8877 Gatekeeper listening port
MESH_KEY triad-mesh-key-2026 Shared secret for inter-agent auth
REDIS_URL redis://redis:6379/0 Redis connection string
USER_METAMASK_ADDRESS (required — no default) Required. Your MetaMask vault address on Polygon. All A2A revenue is settled exclusively to this address. Set this in your .env file before starting the Gatekeeper. The Gatekeeper exits immediately at startup if this is missing.
GATEKEEPER_URL http://192.168.1.75:8877 Scout → Gatekeeper endpoint
SCOUT_NODE_ID tigerwolf-node Scout node identifier
SCOUT_INTERVAL 60 Scout pass interval in seconds
HEARTBEAT_INTERVAL 60 Heartbeat interval in seconds
STALE_THRESHOLD 300 Seconds before a node is considered stale
TELEGRAM_BOT_TOKEN Telegram bot token for outbound notifications only
TELEGRAM_ALLOWED_USERS Comma-separated Telegram user IDs
TELEGRAM_GROUP_ALLOWED_CHATS Comma-separated chat IDs (group mode)
WEB3_RPC_URL https://polygon-rpc.com Polygon RPC for on-chain verification

Important: USER_METAMASK_ADDRESS is required. The Gatekeeper will exit with a startup error if this variable is not set. There is no fallback address in the source code — every deployer must define their own Polygon wallet before starting the Gatekeeper. Copy .env.example.env, set USER_METAMASK_ADDRESS=0xYourMetaMaskWalletAddress, then launch.


JSON Schemas

Telemetry Packet (Scout → Gatekeeper)

Every scout data transmission follows this exact schema:

{
    "$schema": "https://schemas.triad-core.io/telemetry-v1.json",
    "type": "object",
    "required": [
        "node_id", "scout_id", "payload_type", "data", "timestamp"
    ],
    "properties": {
        "node_id": {
            "type": "string",
            "description": "Identifies the sending scout node"
        },
        "scout_id": {
            "type": "string",
            "description": "Unique per-packet identifier (UUID4 hex)"
        },
        "payload_type": {
            "type": "string",
            "enum": [
                "zscore_delta",
                "market_calc",
                "osint_alert",
                "threat_signal"
            ],
            "description": "Type of telemetry payload"
        },
        "data": {
            "type": "object",
            "required": ["threat", "oracle", "military"],
            "properties": {
                "threat": {
                    "type": "number",
                    "description": "Threat Z-score delta",
                    "minimum": -4.0,
                    "maximum": 4.0
                },
                "oracle": {
                    "type": "number",
                    "description": "Oracle prediction delta",
                    "minimum": -4.0,
                    "maximum": 4.0
                },
                "military": {
                    "type": "number",
                    "description": "Military intelligence delta",
                    "minimum": -4.0,
                    "maximum": 4.0
                },
                "markets_tracked": {
                    "type": "integer",
                    "minimum": 0
                },
                "edge_pp": {
                    "type": "number",
                    "description": "Computed edge in percentage points"
                },
                "confidence": {
                    "type": "number",
                    "minimum": 0.0,
                    "maximum": 1.0,
                    "description": "Signal confidence score"
                }
            }
        },
        "sequence": {
            "type": "integer",
            "description": "Monotonic counter for ordering"
        },
        "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 UTC timestamp"
        },
        "mesh_version": {
            "type": "string",
            "description": "Protocol version"
        }
    }
}

Example packet:

{
    "node_id": "tigerwolf-node",
    "scout_id": "sct_0ea0c852d3",
    "payload_type": "zscore_delta",
    "data": {
        "threat": -0.76,
        "oracle": 0.13,
        "military": -1.55,
        "markets_tracked": 7,
        "edge_pp": 13.3,
        "confidence": 0.72
    },
    "sequence": 42,
    "timestamp": "2026-06-04T08:55:00Z",
    "mesh_version": "2.0.0"
}

A2A Discovery Manifest

The full manifest is auto-served at http://<gatekeeper>:8877/.well-known/ai-agents.json:

{
    "$schema": "https://agents.ai/schemas/agent-manifest-v1.json",
    "agent_id": "alpha-feed-gatekeeper",
    "name": "AlphaFeed Gatekeeper — Geopolitical OSINT Alpha Feed",
    "description": "Deterministic mathematical gatekeeper for OSINT Z-score deltas. No LLM text parsing.",
    "endpoints": [
        {
            "path": "/alphafeed/get-alpha",
            "method": "GET",
            "description": "Latest validated alpha signal",
            "auth": "X-Mesh-Key"
        },
        {
            "path": "/alphafeed/revenue",
            "method": "GET",
            "description": "Revenue balance and vault status"
        }
    ],
    "pricing": {
        "model": "per_request",
        "amount_pol": 0.001,
        "vault": "0xYourMetaMaskWalletAddress",
        "vault_locked": true
    },
    "settlement": {
        "network": "polygon",
        "vault_address": "0xYourMetaMaskWalletAddress",
        "method": "direct_wallet_transfer (no middleman)",
        "withdrawal_policy": "exclusive — no alternate addresses accepted"
    }
}

Note: The vault address shown above is a placeholder. The live manifest served by a running Gatekeeper returns the address set in your USER_METAMASK_ADDRESS environment variable.

Heartbeat Packet

{
    "node_id": "tigerwolf-node",
    "node_name": "tigerwolf-ubuntu",
    "ip_address": "192.168.1.100",
    "uptime_seconds": 86400.0,
    "load_avg": [0.5, 0.3, 0.2],
    "memory_pct": 42.1,
    "version": "2.0.0"
}

API Reference

Gatekeeper Endpoints

Method Path Auth Description
GET /alphafeed/health None Liveness check
GET /.well-known/ai-agents.json None A2A discovery manifest
POST /alphafeed/scout-stream X-Mesh-Key Ingest scout telemetry
POST /alphafeed/heartbeat X-Mesh-Key Receive node heartbeat
GET /alphafeed/mesh/status X-Mesh-Key Mesh health dashboard
GET /alphafeed/get-alpha X-Mesh-Key Latest validated alpha signal
GET /alphafeed/revenue X-Mesh-Key Accrued revenue balance

Scout Agent

The Scout Agent exposes no external endpoints. All communication is outbound-only via HTTP POST to the Gatekeeper.


Revenue Model

Micro-Fee Structure

  • Cost: 0.001 POL (Polygon native token) per data pull
  • Accepted tokens: POL (native), USDC (Polygon)
  • Payment: Direct wallet-to-wallet transfer
  • Verification: Submit transaction hash to the Gatekeeper's /pay endpoint

Vault Lock (Strict Mode)

The withdrawal address is read exclusively from the USER_METAMASK_ADDRESS environment variable. There is no fallback — the Gatekeeper exits immediately at startup if this variable is unset:

VAULT = os.getenv("USER_METAMASK_ADDRESS")
if not VAULT:
    sys.exit(1)  # user must set USER_METAMASK_ADDRESS in .env

This is by design. Every deployer must define their own MetaMask address in their .env file before starting the Gatekeeper. There is no built-in default — if you see a startup error, you haven't configured the environment variable yet.

Security invariant: Once set at startup, the vault is locked for the lifetime of the process. No API call, runtime argument, or configuration change can alter the withdrawal target.

Revenue Flow

External Agent → sends POL/USDC to VAULT (from USER_METAMASK_ADDRESS)
               → submits tx_hash to Gatekeeper
               → Gatekeeper credits agent's API key
               → Agent pulls data via GET /get-alpha
               → Fee deducted per pull

Security & Authentication

Mesh Authentication

All inter-agent traffic requires the X-Mesh-Key header:

X-Mesh-Key: <shared-secret>

The mesh key is set via the MESH_KEY environment variable. In production, use a strong random string:

python3 -c "import secrets; print(secrets.token_hex(32))"

Network Isolation

  • The Gatekeeper binds to 0.0.0.0:8877 — accessible to any machine on the LAN

  • Critical: Restrict access to only known scout nodes via UFW:

    # Allow only the specific scout node
    sudo ufw allow from <scout_ip_address> to any port 8877 proto tcp
    
    # Explicitly block external WAN access to port 8877
    # (UFW default deny incoming covers this, but being explicit helps auditing)
    sudo ufw deny 8877
    
    # Enable the firewall
    sudo ufw enable
    
    # Verify the rules
    sudo ufw status verbose

    Expected ufw status output:

    To                         Action      From
    --                         ------      ----
    8877/tcp                   ALLOW       192.168.1.100
    8877/tcp                   DENY        Anywhere
    8877/tcp (v6)              DENY        Anywhere (v6)
    
  • The Scout Agent makes outbound connections only — no open ports required

  • Always verify the socket before deploying: nc -zv <gatekeeper_ip> 8877

Telegram Security

Telegram is configured as a read-only outbound notification tier:

  • No inbound command processing from Telegram
  • Only settlement confirmations and execution artifacts are posted
  • Bot token has minimal permissions (send messages only in allowed chats)

Telegram Integration

The Telegram interface is intentionally restricted to broadcast-only mode. Configuration is handled via environment variables:

# .env
TELEGRAM_BOT_TOKEN=your_bot_token
TELEGRAM_ALLOWED_USERS=user_id_1,user_id_2
TELEGRAM_GROUP_ALLOWED_CHATS=group_chat_id

What Telegram is used for:

  • ✅ Settlement confirmations (POL/USDC received)
  • ✅ Execution artifacts requiring a signature
  • ❌ Internal mesh chatter
  • ❌ Scout telemetry logs
  • ❌ Debug output

All operational logging routes to local files:

  • /tmp/gatekeeper_revenue.log — revenue events
  • /tmp/scout_agent.log — scout telemetry
  • /tmp/local_mesh_migration.log — mesh connection events
  • /tmp/alphafeed_acquisition.log — agent discovery and acquisition
  • /tmp/github_deployment.log — git deployment log

Monitoring & Logging

Log Files

Log Path Content
Revenue /tmp/gatekeeper_revenue.log Every micro-fee collection and settlement
Scout /tmp/scout_agent.log Telemetry ingestion and scrape results
Mesh /tmp/local_mesh_migration.log Connection handshakes and heartbeat events
Acquisition /tmp/alphafeed_acquisition.log Agent discovery and barter proposals
Deployment /tmp/github_deployment.log Git operations and staging output

Mesh Watchdog

The watchdog (mesh/watchdog.py) runs every 2 minutes and:

  • Checks if the secondary node has sent a heartbeat in the last 300 seconds
  • Silently exits with code 0 on success
  • Exits with code 1 if a node is stale (for cron/systemd alerting)
# Run manually
python3 mesh/watchdog.py
echo $?  # 0 = healthy, 1 = stale node

Health Checks

The Docker Compose deployment includes automatic health checks:

  • Gatekeeper: HTTP GET /alphafeed/health every 15 seconds
  • Scout: Internal process health via Docker HEALTHCHECK
  • Redis: redis-cli ping every 10 seconds

Troubleshooting Runbook

E1 — Gatekeeper won't start: "Connection Refused" on scout node

Symptom: nc -zv 192.168.1.75 8877 returns Connection refused from the secondary node.

Resolution steps:

  1. Is the Gatekeeper process running?

    # On the primary node:
    ss -tlnp | grep 8877

    If nothing appears, start the Gatekeeper:

    cd gatekeeper_agent
    USER_METAMASK_ADDRESS="0xYourMetaMaskWalletAddress" \
      MESH_KEY="your-mesh-key" \
      python3 gatekeeper.py
  2. Is it bound to the right interface?

    ss -tlnp | grep 8877
    # Expected: LISTEN 0  0.0.0.0:8877
    # If it shows 127.0.0.1:8877, the Gatekeeper is localhost-only —
    # check that it's started with 0.0.0.0 binding.
  3. Is UFW blocking the scout?

    # On the primary node:
    sudo ufw status verbose

    If you see 8877/tcp DENY without an accompanying ALLOW for the scout IP:

    sudo ufw allow from 192.168.1.100 to any port 8877 proto tcp
    sudo ufw reload
  4. Are both nodes on the same subnet?

    # On both nodes:
    ip route show | grep default
    # The gateway IP should match. If they're on different subnets
    # (e.g., 192.168.1.x vs 10.0.0.x), the mesh won't route.
  5. Can the primary node ping the secondary?

    # From primary:
    ping -c 3 192.168.1.100

    If ping fails, check physical connection (Wi-Fi network, ethernet cable).


E2 — Scout sends packets but Gatekeeper logs "SCOUT REJECTED"

Symptom: Scout reports POST scout-stream OK but Gatekeeper logs validation errors.

Resolution steps:

  1. Check the rejection reason in Gatekeeper logs:

    docker compose logs gatekeeper | grep "SCOUT REJECTED"
    # Or if running bare-metal:
    tail -20 /tmp/gatekeeper.log | grep "SCOUT REJECTED"
  2. Common causes and fixes:

    • Z-score out of bounds: All three vector values (threat, oracle, military) must be in [-4.0, 4.0]. Clamp your values before sending.

      # In your scout, add clamping:
      def clamp(v): return max(-4.0, min(4.0, v))
    • Non-finite values: Python float('inf'), float('nan'), or None will be rejected. Use math.isfinite() check before building the packet:

      import math
      assert all(math.isfinite(v) for v in [threat, oracle, military])
    • Missing required fields: Every packet MUST contain node_id, scout_id, payload_type, data, and timestamp. The data object MUST contain threat, oracle, and military keys.

    • Confidence out of range: Must be in [0.0, 1.0]. Clamp before sending.

  3. Test with a known-valid packet:

    curl -s -X POST http://192.168.1.75:8877/alphafeed/scout-stream \
      -H "Content-Type: application/json" \
      -H "X-Mesh-Key: your-mesh-key" \
      -d '{
        "node_id": "test",
        "scout_id": "test_001",
        "payload_type": "zscore_delta",
        "data": {"threat": -0.5, "oracle": 0.3, "military": -1.2, "confidence": 0.8, "markets_tracked": 5},
        "sequence": 1,
        "timestamp": "2026-06-04T12:00:00Z",
        "mesh_version": "2.0.0"
      }'

    If this succeeds, the issue is in your scout's data generation — not the mesh.


E3 — Broken JSON / corrupted packets over noisy Wi-Fi

Symptom: Gatekeeper returns 400 Invalid JSON body sporadically, or telemetry arrives with mangled fields.

Resolution steps:

  1. Is the Wi-Fi link stable? Run a continuous ping test from the scout node:

    # On secondary node, run for 60 seconds:
    ping -c 60 192.168.1.75 | tail -3

    If packet loss > 0.5%, the Wi-Fi link is unreliable. Switch to ethernet or move the nodes closer.

  2. Enable TCP keepalive on the scout's HTTP client: The urllib default timeout is generous but doesn't guarantee packet integrity over flaky links. Add retry logic to the scout:

    # In scout.py post_to_gateway(), wrap with retry:
    import time
    MAX_RETRIES = 3
    for attempt in range(MAX_RETRIES):
        try:
            # ... existing POST code ...
            return True
        except urllib.error.HTTPError as e:
            if attempt < MAX_RETRIES - 1:
                time.sleep(2 ** attempt)  # exponential backoff
                continue
            raise
  3. Validate JSON before sending: In your scout, catch serialization errors:

    try:
        body = json.dumps(payload).encode("utf-8")
    except (TypeError, ValueError) as e:
        logger.error("JSON serialization failed: %s", e)
        # Inspect payload for non-serializable types
        return False
  4. Reduce packet size for noisy networks: If your payload exceeds ~10 KB, truncate or paginate. Noisy Wi-Fi links drop large frames disproportionately.


E4 — Data alignment errors: scout and gatekeeper disagree on values

Symptom: Scout logs one set of z-scores, but the revenue log or /alphafeed/get-alpha shows different values.

Resolution steps:

  1. Check the persisted scout data on the Gatekeeper:

    # On the primary node, examine what the Gatekeeper actually stored:
    cat /app/scout_data/latest_zscore_delta.json | python3 -m json.tool

    Compare the data fields here against what the scout claims to have sent.

  2. Verify the sequence counter is monotonic:

    # Check the scout's state file:
    cat /tmp/scout_state.json
    # The "sequence" field should increment by exactly 1 each pass.
    # If it resets or skips, the scout's state persistence may be corrupted.
  3. Watch for float precision drift: Python's float is IEEE 754 double-precision. Over thousands of packets, tiny rounding differences can accumulate. If your alpha score is computed from scout data and re-computed by the Gatekeeper, ensure both sides use the same rounding:

    • Scout: round(value, 4) before building the packet
    • Gatekeeper: already applies round(composite, 4)
  4. Enable verbose scout logging for a single pass:

    python3 scout.py --once --verbose

    This prints the exact JSON being POSTed. Compare with what arrives at the Gatekeeper.


E5 — Gatekeeper exits immediately on startup

Symptom: Running python3 gatekeeper.py prints an error and exits before the server starts.

Resolution:

FATAL: USER_METAMASK_ADDRESS environment variable is not set.
       Open .env.example, copy it to .env, and set your Polygon
       MetaMask wallet address before starting the Gatekeeper.
       Example: USER_METAMASK_ADDRESS=0xYourMetaMaskWalletAddress

Fix:

# Set the env var inline:
USER_METAMASK_ADDRESS="0xYourMetaMaskWalletAddress" python3 gatekeeper.py

# Or use a .env file (create from example):
cp .env.example .env
nano .env   # set USER_METAMASK_ADDRESS=0xYourMetaMaskWalletAddress

E6 — Mesh node showing as offline for too long

Symptom: The mesh status endpoint shows "status": "online" but the watchdog exits with code 1, or the "last_seen" timestamp is more than 5 minutes old.

Resolution:

# Check recent heartbeats
curl -s http://localhost:8877/alphafeed/mesh/status \
  -H "X-Mesh-Key: your-mesh-key" | python3 -c "
import sys, json
d = json.load(sys.stdin)
for node, info in d['nodes'].items():
    print(f'{node}: {info[\"status\"]} — last seen {info[\"last_seen\"]}')
"

# If stale, check the secondary node:
# - Is the laptop awake? (screen unlocked, not sleeping)
# - Is the heartbeat client running? (ps aux | grep heartbeat)
# - Can it reach the Gatekeeper's IP? (nc -zv 192.168.1.75 8877)
# - Is the heartbeat interval too long? (check HEARTBEAT_INTERVAL vs STALE_THRESHOLD)

E7 — Revenue not accruing

Symptom: Calls to /alphafeed/get-alpha succeed but the revenue balance stays at 0.

Resolution:

# Check the revenue log
cat /tmp/gatekeeper_revenue.log

# Check the Gatekeeper balance endpoint
curl -s http://localhost:8877/alphafeed/revenue \
  -H "X-Mesh-Key: your-mesh-key" | python3 -m json.tool

# Verify USER_METAMASK_ADDRESS is set correctly
# (if it's empty, the Gatekeeper won't even start)
echo $USER_METAMASK_ADDRESS

License

MIT — see LICENSE for details.


Built by FREE33 & tigerwolf33 under the Triad Core directive. Telegram: @freedom33free_bot Endpoint: http://192.168.1.75:8877

About

A2A Agent Acquisition Architecture — autonomous mesh of OSINT scouts, deterministic gatekeepers, and decentralized revenue settlement. Deployable on dual-node LAN or single-host Docker Compose.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors