stemedb/community/scripts/seed-all.ts
jordan 1cc453c97b feat: Aphoria policy source tracking + claim extraction pipeline
- Add PolicySourceStore for tracking where policies come from
- Implement claim extraction skill and API endpoints
- Add community UI text selection extractor component
- Create Go SDK aphoria client for policy operations
- Document patent specifications and legal disclosures
- Add guides: golden path loop, policy audit trails, pre-flight checks
- Expand Unreal Engine config extractor with source tracking
- Add UAT reports for policy source tracking validation
- Refactor tests.rs into modular test files

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 02:35:02 -07:00

287 lines
8.0 KiB
TypeScript

#!/usr/bin/env npx tsx
/**
* Orchestrate the full seed pipeline for StemeDB demo.
*
* This script:
* 1. Waits for API health
* 2. Runs whitepaper seed script
* 3. Runs external sources seed script
* 4. Verifies key claims via SkepticLens
*
* Usage:
* npx tsx scripts/seed-all.ts
* npx tsx scripts/seed-all.ts --dry-run
* npx tsx scripts/seed-all.ts --verify-only
*
* Environment:
* STEMEDB_API_URL - API base URL (default: http://127.0.0.1:18180)
*/
import { execSync } from "child_process";
const API_URL = process.env.STEMEDB_API_URL || "http://127.0.0.1:18180";
// ============================================================================
// Types
// ============================================================================
interface SkepticResponse {
subject: string;
predicate: string;
status: "Unanimous" | "Agreed" | "Contested";
conflict_score: number;
claims: Array<{
value: { type: string; value: string | number | boolean };
weight_share: number;
assertion_count: number;
}>;
candidates_count: number;
}
// ============================================================================
// Health Check
// ============================================================================
async function waitForHealth(maxRetries = 30, delayMs = 2000): Promise<boolean> {
console.log(`Waiting for API at ${API_URL}...`);
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(`${API_URL}/v1/health`);
if (response.ok) {
const data = await response.json();
console.log(`API is healthy: v${data.version}, ${data.assertions_count} assertions`);
return true;
}
} catch {
// Retry
}
if (i < maxRetries - 1) {
console.log(` Retry ${i + 1}/${maxRetries}...`);
await new Promise((resolve) => setTimeout(resolve, delayMs));
}
}
console.error(`API not healthy after ${maxRetries} retries`);
return false;
}
// ============================================================================
// Verification
// ============================================================================
interface VerificationTarget {
subject: string;
predicate: string;
expectedStatus?: "Unanimous" | "Agreed" | "Contested";
description: string;
}
const VERIFICATION_TARGETS: VerificationTarget[] = [
// Core StemeDB claims
{
subject: "StemeDB",
predicate: "hash_algorithm",
expectedStatus: "Unanimous",
description: "BLAKE3 hash algorithm",
},
{
subject: "StemeDB",
predicate: "storage_model",
expectedStatus: "Agreed",
description: "Append-only Merkle DAG",
},
{
subject: "RecencyLens",
predicate: "time_complexity",
expectedStatus: "Unanimous",
description: "O(n) complexity",
},
// Cryptography claims
{
subject: "BLAKE3",
predicate: "output_size",
expectedStatus: "Unanimous",
description: "256-bit output",
},
{
subject: "Ed25519",
predicate: "signature_size",
expectedStatus: "Unanimous",
description: "64 bytes",
},
// Potential conflicts
{
subject: "CRDT",
predicate: "preserves_disagreement",
description: "CRDT disagreement preservation (potential conflict)",
},
{
subject: "PostgreSQL",
predicate: "conflict_resolution",
description: "PostgreSQL conflict handling (potential conflict)",
},
{
subject: "EigenTrust",
predicate: "initial_trust_score",
description: "Trust score initialization (potential conflict)",
},
// Database comparisons
{
subject: "PostgreSQL",
predicate: "storage_model",
description: "PostgreSQL storage model",
},
{
subject: "MongoDB",
predicate: "storage_model",
description: "MongoDB storage model",
},
];
async function verifySkeptic(target: VerificationTarget): Promise<boolean> {
const url = `${API_URL}/v1/skeptic?subject=${encodeURIComponent(target.subject)}&predicate=${encodeURIComponent(target.predicate)}&include_source_metadata=true`;
try {
const response = await fetch(url);
if (!response.ok) {
console.log(` [SKIP] ${target.subject}/${target.predicate}: No data`);
return true; // Not a failure, just no data
}
const data: SkepticResponse = await response.json();
const statusIcon =
data.status === "Unanimous" ? "[UNANIMOUS]" :
data.status === "Agreed" ? "[AGREED] " :
"[CONTESTED]";
const expectedMatch = !target.expectedStatus || data.status === target.expectedStatus;
const icon = expectedMatch ? "OK" : "!!";
console.log(
` [${icon}] ${statusIcon} ${target.subject}/${target.predicate}: ` +
`${data.claims.length} claims, conflict=${data.conflict_score.toFixed(2)}`
);
if (data.claims.length > 0) {
const topClaim = data.claims[0];
console.log(` Top: "${String(topClaim.value.value).slice(0, 40)}..." (${(topClaim.weight_share * 100).toFixed(0)}%)`);
}
return expectedMatch;
} catch (error) {
console.error(` [ERR] ${target.subject}/${target.predicate}: ${error}`);
return false;
}
}
async function runVerification(): Promise<boolean> {
console.log("\n=== Verification via SkepticLens ===\n");
let passed = 0;
let failed = 0;
let skipped = 0;
for (const target of VERIFICATION_TARGETS) {
const result = await verifySkeptic(target);
if (result) {
passed++;
} else {
failed++;
}
}
console.log(`\nVerification: ${passed} passed, ${failed} failed, ${skipped} skipped`);
return failed === 0;
}
// ============================================================================
// Script Execution
// ============================================================================
function runScript(scriptName: string, dryRun: boolean): void {
const args = dryRun ? "--dry-run" : "";
const command = `npx tsx scripts/${scriptName} ${args}`;
console.log(`\n${"=".repeat(60)}`);
console.log(`Running: ${scriptName}${dryRun ? " (dry run)" : ""}`);
console.log("=".repeat(60) + "\n");
try {
execSync(command, {
stdio: "inherit",
cwd: process.cwd(),
env: { ...process.env, STEMEDB_API_URL: API_URL },
});
} catch (error) {
console.error(`Script ${scriptName} failed:`, error);
throw error;
}
}
// ============================================================================
// Main
// ============================================================================
async function main(): Promise<void> {
const args = process.argv.slice(2);
const dryRun = args.includes("--dry-run") || args.includes("-d");
const verifyOnly = args.includes("--verify-only") || args.includes("-v");
console.log("StemeDB Full Seed Pipeline");
console.log("==========================");
console.log(`API URL: ${API_URL}`);
if (dryRun) console.log("Mode: DRY RUN");
if (verifyOnly) console.log("Mode: VERIFY ONLY");
console.log();
// Health check
const healthy = await waitForHealth();
if (!healthy) {
console.error("\nAPI is not available. Please start stemedb-api first:");
console.error(" cargo run --bin stemedb-api");
process.exit(1);
}
console.log();
if (!verifyOnly) {
// Phase 1: Whitepaper claims
runScript("seed-whitepaper.ts", dryRun);
// Phase 2: External sources
runScript("seed-external.ts", dryRun);
if (!dryRun) {
// Wait for materialization
console.log("\nWaiting for final materialization...");
await new Promise((resolve) => setTimeout(resolve, 3000));
}
}
// Phase 3: Verification
if (!dryRun) {
const verificationPassed = await runVerification();
if (!verificationPassed) {
console.warn("\nSome verifications failed. Check the output above.");
}
}
console.log("\n" + "=".repeat(60));
console.log("Seed pipeline complete!");
console.log("=".repeat(60));
console.log("\nNext steps:");
console.log(" 1. Start the community app: cd community && npm run dev");
console.log(" 2. Visit http://localhost:18187");
console.log(" 3. Click on annotated claims to see conflict analysis");
}
main().catch((error) => {
console.error("Pipeline failed:", error.message);
process.exit(1);
});