stemedb/applications/aphoria/src/cli/mod.rs
jml 65065f3d8f feat(aphoria): implement community corpus with wiki import and pattern aggregation
Implements Phase 4 (A4) - Community corpus as first-class citizens:

- **Community Corpus Builder** - Queries StemeDB pattern aggregates
- **Wiki Import** - Bootstrap corpus from markdown docs (aphoria corpus import wiki)
- **Pattern Aggregation** - Automatic learning from local scans (--sync flag)
- **Storage Layer** - StemeDBPatternStore with content-addressed deduplication
- **Promotion Logic** - Multi-tier thresholds (95%/80%/50% adoption rates)
- **Corpus Build** - Unified registry for RFC/OWASP/Vendor/Community sources
- **Trust Packs** - Export corpus as signed, distributable artifacts
- **Documentation** - bootstrap-corpus.md guide + CLI reference updates

Technical details:
- Pattern aggregates stored as assertions with predicate "pattern_aggregate"
- Content-addressed subjects via BLAKE3(subject:predicate:value)
- PatternAggregator handles write path (observations → patterns)
- StemeDBPatternStore handles read path (pattern queries)
- Integration tests + fixtures in tests/wiki_import_test.rs

Deleted hardcoded.rs (368 lines) - corpus now fully emergent from StemeDB.
Deleted enriched-corpus-patterns.md (677 lines) - feature shipped.

Closes VG-026 (community corpus), part of A4 milestone.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-09 00:12:31 +00:00

471 lines
12 KiB
Rust

//! CLI argument definitions for Aphoria
//!
//! This module is split into submodules to keep file sizes manageable:
//! - `extractors`: Extractor and shadow mode commands
//! - `governance`: Governance and Audit commands
//! - `lifecycle`: Lifecycle and Migration commands
//! - `patterns`: Pattern and Eval commands
//! - `scope`: Scope commands
mod claims;
mod extractors;
mod governance;
mod lifecycle;
mod patterns;
mod scope;
mod verify;
pub use claims::ClaimsCommands;
pub use extractors::ExtractorCommands;
pub use governance::{AuditCommands, GovernanceCommands};
pub use lifecycle::{LifecycleCommands, MigrationCommands};
pub use patterns::{EvalCommands, PatternCommands};
pub use scope::ScopeCommands;
pub use verify::VerifyCommands;
use std::path::PathBuf;
use clap::{Parser, Subcommand};
/// A code-level truth linter powered by Episteme.
///
/// Aphoria scans a codebase, extracts the decisions embedded in config and code,
/// and checks them against authoritative sources. It finds the places where what
/// your code *does* contradicts what the specs *say*.
#[derive(Parser)]
#[command(name = "aphoria")]
#[command(version, about, long_about = None)]
#[command(
after_help = "Examples:\n aphoria scan Scan current directory\n aphoria scan --format sarif Output for IDE integration\n aphoria scan --strict Stricter conflict thresholds\n aphoria verify run Check code against claims\n aphoria coverage Show claim density per module\n aphoria explain Onboarding summary"
)]
pub struct Cli {
/// Path to aphoria.toml configuration file
#[arg(short, long, global = true)]
pub config: Option<PathBuf>,
/// Enable verbose logging (shows internal tracing output)
#[arg(short, long, global = true)]
pub verbose: bool,
#[command(subcommand)]
pub command: Commands,
}
#[derive(Subcommand)]
pub enum Commands {
/// Scan a project for epistemic drift
Scan {
/// Path to the project root to scan
#[arg(default_value = ".")]
path: PathBuf,
/// Output format: table, json, sarif, markdown
#[arg(short, long, default_value = "table")]
format: String,
/// Exit with non-zero code if conflicts found
#[arg(long)]
exit_code: bool,
/// Use stricter thresholds (FLAG at 0.3, BLOCK at 0.5)
#[arg(long)]
strict: bool,
/// Persist claims to Episteme storage (enables diff/baseline features).
/// Without this flag, scans are ephemeral and fast.
#[arg(long)]
persist: bool,
/// Enable debug output showing conflict resolution traces.
#[arg(long)]
debug: bool,
/// Enable write-back of observations to local Episteme (requires --persist).
#[arg(long)]
sync: bool,
/// Scan only git-staged files (for pre-commit hooks).
#[arg(long)]
staged: bool,
/// Preview what would be shared with the community corpus.
#[arg(long)]
community_preview: bool,
/// Run performance benchmark with timing breakdown.
#[arg(long)]
benchmark: bool,
/// Show all extracted claims in the output
#[arg(long)]
show_claims: bool,
},
/// Manage acknowledgments (mark conflicts as intentional)
Ack {
#[command(subcommand)]
command: AckCommands,
},
/// Bless a code pattern as the authoritative standard
Bless {
/// The concept path to bless
concept_path: String,
/// The predicate (e.g., "enabled", "min_version")
#[arg(short, long)]
predicate: String,
/// The value (e.g., "true", "1.2")
#[arg(short = 'V', long)]
value: String,
/// Reason/description for this standard
#[arg(short, long)]
reason: String,
},
/// Record an intentional configuration change as a policy update
Update {
/// The concept path being updated
concept_path: String,
/// The new value for this concept
value: String,
/// Reason for the update
#[arg(short, long)]
reason: String,
},
/// Set the current scan as the baseline
Baseline,
/// Show changes since last baseline
Diff,
/// Show current scan status
Status,
/// Initialize Aphoria with authoritative corpus
Init,
/// Manage the authoritative corpus
Corpus {
#[command(subcommand)]
command: CorpusCommands,
},
/// Manage the research agent for filling corpus gaps
Research {
#[command(subcommand)]
command: ResearchCommands,
},
/// Manage federated policies (Trust Packs)
Policy {
#[command(subcommand)]
command: PolicyCommands,
},
/// Manage learned patterns and extractor promotion
Extractors {
#[command(subcommand)]
command: ExtractorCommands,
},
/// Evaluate LLM prompt effectiveness
Eval {
#[command(subcommand)]
command: EvalCommands,
},
/// Manage cross-project pattern learning
Patterns {
#[command(subcommand)]
command: PatternCommands,
},
/// Manage knowledge scopes and inheritance
Scope {
#[command(subcommand)]
command: ScopeCommands,
},
/// Manage knowledge lifecycle (deprecation, archival)
Lifecycle {
#[command(subcommand)]
command: LifecycleCommands,
},
/// Track migration progress for deprecated patterns
Migrations {
#[command(subcommand)]
command: MigrationCommands,
},
/// Manage approval workflows for pattern promotion
Governance {
#[command(subcommand)]
command: GovernanceCommands,
},
/// View and export audit trails for compliance
Audit {
#[command(subcommand)]
command: AuditCommands,
},
/// Manage human-authored claims (create, list, explain, update, supersede, deprecate)
Claims {
#[command(subcommand)]
command: ClaimsCommands,
},
/// Verify code against authored claims
Verify {
#[command(subcommand)]
command: VerifyCommands,
},
/// Show claim coverage metrics per module
Coverage {
/// Path to the project root
#[arg(default_value = ".")]
path: PathBuf,
/// Output format: table, json, markdown
#[arg(short, long, default_value = "table")]
format: String,
/// Sort modules by: name, density, unclaimed, observations
#[arg(long, default_value = "name")]
sort_by: String,
},
/// Generate a narrative explanation of this project's claims (onboarding)
Explain {
/// Path to the project root
#[arg(default_value = ".")]
path: PathBuf,
/// Write output to a file instead of stdout
#[arg(short, long)]
output: Option<PathBuf>,
/// Output format: markdown or json
#[arg(long, default_value = "markdown")]
format: String,
},
/// Generate enhanced documentation from claims + verification
Docs {
#[command(subcommand)]
command: DocsCommands,
},
/// Manage curated Trust Packs (install, list)
TrustPack {
#[command(subcommand)]
command: TrustPackCommands,
},
}
#[derive(Subcommand)]
pub enum TrustPackCommands {
/// Install a curated Trust Pack by name
Install {
/// Pack name (e.g., "security-hardening", "rfc-compliance", "owasp-top10")
name: String,
/// Custom registry URL (overrides built-in registry)
#[arg(long)]
registry: Option<String>,
},
/// List available curated Trust Packs
List,
}
#[derive(Subcommand)]
pub enum DocsCommands {
/// Generate a claims overview document
Generate {
/// Path to the project root
#[arg(default_value = ".")]
path: PathBuf,
/// Output path (default: stdout)
#[arg(short, long)]
output: Option<PathBuf>,
/// Output format: markdown or json
#[arg(long, default_value = "markdown")]
format: String,
},
}
#[derive(Subcommand)]
pub enum AckCommands {
/// Create a new acknowledgment for a conflict
Add {
/// The concept path to acknowledge
concept_path: String,
/// Reason for acknowledgment
#[arg(short, long)]
reason: String,
/// Optional expiry for acknowledgment (e.g., "90d" or "2026-12-31")
#[arg(long, alias = "expires-at")]
expires: Option<String>,
},
/// Export acknowledgments to .aphoria/acks.toml for version control
Export {
/// Output path (default: .aphoria/acks.toml)
#[arg(short, long)]
output: Option<PathBuf>,
},
/// Import acknowledgments from .aphoria/acks.toml
Import {
/// Input path (default: .aphoria/acks.toml)
#[arg(short, long)]
input: Option<PathBuf>,
},
}
#[derive(Subcommand)]
pub enum CorpusCommands {
/// Build the authoritative corpus from configured sources
Build {
/// Only include specific sources (comma-separated)
#[arg(long)]
only: Option<String>,
/// Run in offline mode (skip sources requiring network)
#[arg(long)]
offline: bool,
/// Clear cache before building
#[arg(long)]
clear_cache: bool,
},
/// List available corpus sources
List,
/// Import patterns from external sources to bootstrap the corpus
Import {
#[command(subcommand)]
source: ImportSource,
},
/// Export the corpus as a signed Trust Pack
ExportPack {
/// Name for the exported pack
#[arg(long)]
name: String,
/// Output path for the .pack file
#[arg(short, long)]
output: PathBuf,
/// Only include specific corpus sources (comma-separated)
#[arg(long)]
only: Option<String>,
/// Run in offline mode (skip sources requiring network)
#[arg(long)]
offline: bool,
},
}
#[derive(Subcommand)]
pub enum ImportSource {
/// Import patterns from wiki markdown documentation
Wiki {
/// Path to wiki directory containing markdown files
path: PathBuf,
},
}
#[derive(Subcommand)]
pub enum ResearchCommands {
/// Run the research agent to fill corpus gaps
Run {
/// Minimum projects that must report a gap before researching
#[arg(short, long, default_value = "3")]
threshold: u32,
/// Use strict quality validation
#[arg(long)]
strict: bool,
/// Prune old gaps before researching
#[arg(long)]
prune: bool,
/// Maximum age of gaps to consider in days
#[arg(long, default_value = "90")]
max_age: u64,
},
/// Show research agent status and gap statistics
Status,
/// List gaps eligible for research
Gaps {
/// Minimum projects that must report a gap
#[arg(short, long, default_value = "1")]
threshold: u32,
/// Show only gaps ready for research (seen in 3+ projects)
#[arg(long)]
ready: bool,
},
}
#[derive(Subcommand)]
pub enum PolicyCommands {
/// Export acknowledged conflicts as a Trust Pack
Export {
/// Name of the policy pack
#[arg(long)]
name: String,
/// Output path for the pack file
#[arg(short, long)]
output: PathBuf,
},
/// Import a Trust Pack into the local Episteme
Import {
/// Path to the .pack file
file: PathBuf,
},
/// Re-sign a Trust Pack with a new key
Resign {
/// Path to the .pack file to re-sign
file: PathBuf,
/// Output path for the re-signed pack
#[arg(short, long)]
output: PathBuf,
/// Path to new signing key
#[arg(long)]
key: Option<PathBuf>,
/// Reason for re-signing (for audit trail)
#[arg(long)]
reason: Option<String>,
/// Preserve signature chain for audit trail
#[arg(long, default_value = "true")]
chain_signatures: bool,
},
}