Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ cargo run -p decodex --bin decodex -- project list
cargo run -p decodex --bin decodex -- status
cargo run -p decodex --bin decodex -- diagnose --json
cargo run -p decodex --bin decodex -- maintenance prune --dry-run
cargo run -p decodex --bin decodex -- radar validate
cargo run -p decodex --bin decodex -- run --dry-run
cargo run -p decodex --bin decodex -- serve --listen-address 127.0.0.1:8912
```
Expand Down Expand Up @@ -212,6 +213,9 @@ Codex automation reviews source evidence:
- `scripts/github/render_signal_entry.py` renders reviewed analysis drafts into site
content.
- `scripts/github/validate_signal_entry.py` validates the published signal collection.
- `decodex radar validate` provides the Rust-owned foundation for validating checked
Radar artifact contracts while the Python scripts remain the active workflow
entrypoints.
- `docs/spec/social-publishing.md` and
`docs/runbook/social-publishing-workflow.md` govern automated low-frequency X
publication for `@decodexspace`.
Expand Down
58 changes: 55 additions & 3 deletions apps/decodex/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use crate::{
self, DiagnoseRequest, EvidenceRequest, IssueDispatchMode, RunOnceRequest, ServeRequest,
},
prelude::{Result, eyre},
radar::{self, RadarValidateRequest},
recovery::{self, ReviewHandoffDiagnoseRequest, ReviewHandoffRebindRequest},
runtime,
};
Expand Down Expand Up @@ -62,6 +63,7 @@ impl Cli {
Command::ArchiveLinear(args) => args.run(),
Command::Maintenance(args) => args.run(),
Command::Account(args) => args.run(),
Command::Radar(args) => args.run(),
Command::Probe(args) => args.run(),
Command::Attempt(args) => args.run(),
}
Expand Down Expand Up @@ -584,6 +586,35 @@ impl MaintenanceCommand {
}
}

#[derive(Debug, Args)]
struct RadarCommand {
#[command(subcommand)]
command: RadarSubcommand,
}
impl RadarCommand {
fn run(&self) -> Result<()> {
match &self.command {
RadarSubcommand::Validate(args) => args.run(),
}
}
}

#[derive(Debug, Args)]
struct RadarValidateCommand {
/// Radar JSON files or directories. Defaults to the checked-in Radar collections.
#[arg(value_name = "PATH")]
paths: Vec<PathBuf>,
}
impl RadarValidateCommand {
fn run(&self) -> Result<()> {
let report = radar::validate(&RadarValidateRequest { paths: self.paths.clone() })?;

println!("OK ({} Radar artifact JSON files validated)", report.checked_files);

Ok(())
}
}

#[derive(Debug, Args)]
struct MaintenancePruneCommand {
/// Report candidates without applying retention changes. This is the default mode.
Expand Down Expand Up @@ -723,6 +754,8 @@ enum Command {
Maintenance(MaintenanceCommand),
/// Manage the global Decodex Codex account pool.
Account(AccountCommand),
/// Inspect and validate Decodex Radar artifacts.
Radar(RadarCommand),
/// Validate the local app-server integration boundary.
Probe(ProbeCommand),
/// Run one daemon-planned attempt from a structured request.
Expand Down Expand Up @@ -782,6 +815,12 @@ enum MaintenanceSubcommand {
Prune(MaintenancePruneCommand),
}

#[derive(Debug, Subcommand)]
enum RadarSubcommand {
/// Validate checked-in Radar artifact JSON contracts.
Validate(RadarValidateCommand),
}

fn read_attempt_request(request: &str) -> Result<AttemptRequest> {
let raw = if request == "-" {
let mut raw = String::new();
Expand Down Expand Up @@ -815,9 +854,10 @@ mod tests {
use crate::cli::{
AccountCommand, AccountSubcommand, AccountUseCommand, AttemptCommand, Cli, Command,
CommitCommand, DiagnoseCommand, EvidenceCommand, LandCommand, ProbeCommand, ProjectCommand,
ProjectConfigArgs, ProjectSubcommand, RecoverCommand, RecoverSubcommand,
ReviewHandoffDiagnoseCommand, ReviewHandoffRebindCommand, ReviewHandoffRecoveryCommand,
ReviewHandoffRecoverySubcommand, RunCommand, ServeCommand, StatusCommand,
ProjectConfigArgs, ProjectSubcommand, RadarCommand, RadarSubcommand, RadarValidateCommand,
RecoverCommand, RecoverSubcommand, ReviewHandoffDiagnoseCommand,
ReviewHandoffRebindCommand, ReviewHandoffRecoveryCommand, ReviewHandoffRecoverySubcommand,
RunCommand, ServeCommand, StatusCommand,
};

#[test]
Expand Down Expand Up @@ -983,6 +1023,18 @@ mod tests {
assert!(matches!(cli.command, Command::Serve(ServeCommand { dev: true, .. })));
}

#[test]
fn parses_radar_validate_paths() {
let cli = Cli::parse_from(["decodex", "radar", "validate", "artifacts/github/bundles"]);

assert!(matches!(
cli.command,
Command::Radar(RadarCommand {
command: RadarSubcommand::Validate(RadarValidateCommand { paths }),
}) if paths == vec![Path::new("artifacts/github/bundles").to_path_buf()]
));
}

#[test]
fn rejects_serve_interval_argument() {
let error = Cli::try_parse_from(["decodex", "serve", "--interval", "30s"])
Expand Down
1 change: 1 addition & 0 deletions apps/decodex/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ mod pull_request;
mod prelude {
pub use color_eyre::{Result, eyre};
}
mod radar;
mod recovery;
mod runtime;
mod tracker;
Expand Down
Loading