stemedb/.claude/guides/services/aphoria-hosted-mode.md
jordan 422e2d4416 feat(aphoria): wire claims through StemeDB — Gap Closure Phase 1
Claims now flow through StemeDB's append-only knowledge graph instead of
mutable TOML files. This resolves all 6 critical claim-bypass code paths:

- Bridge: lossless AuthoredClaim ↔ Assertion round-trip (comparison, status, lifecycle mapping)
- LocalEpisteme: ingest_authored_claim() and fetch_authored_claims() with AUTHORED_CLAIM predicate index
- EpistemeClaimStore: ClaimStore trait backed by StemeDB (append-only delete via deprecation)
- CLI handlers: all claim commands read/write through StemeDB
- Scanner: loads claims from StemeDB with auto-migration fallback to TOML
- Export: new `aphoria claims export` serializes StemeDB claims to TOML/JSON

Also cleans up dead code (EpistemeConfig.url), renames ingest_claims→ingest_observations,
fixes ClaimFilter.authority_tier type, adds Draft variant to ClaimStatus, and fixes
pre-existing clippy warnings (too_many_arguments, filter_next→rfind).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 02:02:51 -07:00

5.1 KiB

Configure Aphoria Hosted Mode

When to use: Setting up Aphoria for team-wide observation aggregation via a central StemeDB server.

What syncs today vs what doesn't:

  • Observations -- synced to hosted StemeDB via push_observations(). Working.
  • Patterns -- synced to hosted StemeDB via push_patterns(). Working.
  • Claims -- stored locally in claims.toml only. No push_claims() exists. Claims never leave the local machine.
  • Extractors -- stored locally in .aphoria/extractors/*.toml only. No push_extractors() exists.

Claim and extractor sync are tracked in the gap closure roadmap (Phases 1-3).

Prerequisites

  • Aphoria installed (cargo install --path applications/aphoria)
  • A running StemeDB server (for the team)
  • Network access to the server

Quick Start

# aphoria.toml
[hosted]
url = "https://episteme.acme.corp"

That's it. Observations now sync automatically on every scan.

Architecture

┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│ Developer A  │  │ Developer B  │  │ Developer C  │
│ aphoria scan │  │ aphoria scan │  │ aphoria scan │
└──────┬───────┘  └──────┬───────┘  └──────┬───────┘
       │                 │                 │
       └─────────────────┼─────────────────┘
                         ▼
              ┌─────────────────────┐
              │ Team StemeDB Server │
              │ POST /v1/aphoria/   │
              │      observations   │
              └─────────────────────┘

Configuration Options

[project]
name = "billing-service"

[hosted]
url = "https://episteme.acme.corp"

Full Configuration

[project]
name = "billing-service"

[hosted]
url = "https://episteme.acme.corp"    # Required: enables hosted mode
project_id = "billing-api"             # Optional: defaults to [project.name]
team_id = "platform-team"              # Optional: for multi-team servers
sync_mode = "remote-only"              # "remote-only" | "local-and-remote"
offline_fallback = "skip"              # "skip" | "fail" | "queue"
api_key_env = "APHORIA_API_KEY"        # Env var containing auth token
max_retries = 3                        # Retry attempts on failure
retry_delay_ms = 1000                  # Delay between retries

Sync Modes

Mode Description When to Use
remote-only Only push to server, no local storage Single source of truth (default)
local-and-remote Store locally AND push to server Need local history for debugging

Offline Handling

Mode Behavior When to Use
skip Warn and continue scan Don't block developers (default)
fail Abort scan with error CI/CD where sync is mandatory
queue Queue for later (not implemented) Future offline support

Authentication

If your server requires authentication:

# Set the API key
export APHORIA_API_KEY="your-secret-token"
[hosted]
url = "https://episteme.acme.corp"
api_key_env = "APHORIA_API_KEY"  # Reads from this env var

The client sends Authorization: Bearer <token> header.

CI/CD Integration

GitHub Actions

- name: Aphoria Scan
  env:
    APHORIA_API_KEY: ${{ secrets.APHORIA_API_KEY }}
  run: aphoria scan --staged --exit-code

Pre-commit Hook

#!/bin/sh
# .git/hooks/pre-commit
aphoria scan --staged --exit-code

With hosted mode configured, observations sync automatically.

Verifying Setup

# Check config is loaded
aphoria status

# Test with verbose output
RUST_LOG=aphoria=debug aphoria scan --persist --sync

# Expected log: "Pushed N observations to hosted server"

Server Setup

Start a StemeDB server:

# Local testing
cargo run -p stemedb-api -- --bind 127.0.0.1:18180

# Production (with persistence)
stemedb-api --bind 0.0.0.0:18180 --data-dir /var/lib/stemedb

The server exposes POST /v1/aphoria/observations for receiving observations.

Troubleshooting

"Hosted sync failed, continuing"

Server is unreachable. Check:

  • URL is correct
  • Server is running
  • Network/firewall allows connection

"Failed to sync to hosted server" (error)

You have offline_fallback = "fail". Either:

  • Fix the connection issue
  • Change to offline_fallback = "skip" temporarily

Observations not appearing on server

Check:

  1. url is set in [hosted] section
  2. Scan finds novel claims (no authority conflicts)
  3. Server logs show incoming requests