- 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>
287 lines
8.0 KiB
TypeScript
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);
|
|
});
|