Annotate test-only fixture enums in jerichoci to exempt them from invariants
Intent: The jerichoci crate contains test-scoped enum types (`StagedLinuxRustTarget`, `StagedLinuxRustLane`) that mirror production catalog shapes for testing. Without explicit annotation, architecture-invariant tooling could flag these as unauthorized catalog definitions. Adding doc-comments makes the exemption intent machine-readable.
Affected files: crates/jerichoci/src/model.rs, crates/jerichoci/src/run.rs
Evidence
@@ -452,6 +452,8 @@ mod tests {
use std::fs;
use std::path::Path;
+ // Test-only fixture catalog for model behavior checks. This is not production
+ // JerichoCI catalog data and should not count against architecture invariants.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum StagedLinuxRustTarget {
@@ -475,6 +477,8 @@ mod tests {
workspace_output_system: &'static str,
}
+ // Test-only fixture catalog for model behavior checks. This is not production
+ // JerichoCI catalog data and should not count against architecture invariants.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum StagedLinuxRustLane {
@@ -4471,6 +4471,8 @@ mod tests {
action()
}
+ // Test-only fixture catalog for run-path checks. This is not production
+ // JerichoCI catalog data and should not count against architecture invariants.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum StagedLinuxRustLane {
Two files in jerichoci define test-only enums that replicate the shape of production staged-Linux catalogs. The project enforces architecture invariants that restrict where catalog definitions may live.
A two-line comment is added above each enum declaration inside #[cfg(test)] mod tests:
// Test-only fixture catalog for model behavior checks. This is not production
// JerichoCI catalog data and should not count against architecture invariants.
This appears in three locations:
model.rs — StagedLinuxRustTarget (line 454)
model.rs — StagedLinuxRustLane (line 479)
run.rs — StagedLinuxRustLane (line 4473)
The comments serve as anchors for the invariant checker's exclusion rules (configured in a later step).
Extract the output module from main.rs
Intent: Move all display, JSON serialization, and human-readable summary functions out of `main.rs` into a dedicated `output.rs` module. This reduces the size of the entrypoint file and groups presentation logic in one place.
Affected files: crates/pikaci/src/main.rs, crates/pikaci/src/output.rs
Evidence
@@ -1,84 +1,24 @@
mod catalog;
mod forge_manifest;
+mod output;
+mod targets;
@@ -374,41 +314,6 @@ fn staged_linux_remote_defaults_json(
-fn print_json(value: &impl serde::Serialize) -> anyhow::Result<()> {
@@ -374,41 +314,6 @@
-fn print_json_line(value: &impl serde::Serialize) -> anyhow::Result<()> {
@@ -374,41 +314,6 @@
-fn print_run_human_summary(run: &RunRecord) {
@@ -1812,15 +525,6 @@
-fn status_text(status: RunStatus) -> &'static str {
The following functions are removed from main.rs and relocated to crates/pikaci/src/output.rs:
| Function | Purpose |
print_json | Pretty-print a serializable value to stdout |
print_json_line | Write a single JSON line to stdout |
print_run_human_summary | Print a human-readable run/job status block |
status_text | Map RunStatus to a static label string |
format_status_lines | Build a Vec<String> of key=value diagnostic lines for a run |
prepared_output_consumer_label | Label for PreparedOutputConsumerKind |
prepared_output_invocation_mode_label | Label for PreparedOutputInvocationMode |
prepared_output_launcher_transport_mode_label | Label for PreparedOutputLauncherTransportMode |
main.rs now imports these through the new module:
use output::{
format_status_lines, prepared_output_consumer_label, print_json, print_json_line,
print_run_human_summary, status_text,
};
The functions are moved verbatim — no signature or logic changes.
Extract the targets module from main.rs
Intent: Move all CI target construction logic — the `TargetSpec` struct, runtime helper constructors, job-base factories, every `*_jobs()` function, and the large `target_spec()` match dispatcher — into a dedicated `targets.rs` module. This is the largest single extraction and removes roughly 700 lines from `main.rs`.
Affected files: crates/pikaci/src/main.rs, crates/pikaci/src/targets.rs
Evidence
@@ -1,84 +1,24 @@
-use catalog::{PikaStagedLinuxLane, PikaStagedLinuxTarget, PikaStagedLinuxTargetInfoJson};
@@ -1,84 +1,24 @@
+use catalog::PikaStagedLinuxTargetInfoJson;
@@ -1,84 +1,24 @@
+use targets::{TargetSpec, staged_linux_target, target_spec};
@@ -462,504 +367,6 @@
-fn staged_linux_target(target_id: &str) -> anyhow::Result<PikaStagedLinuxTarget> {
@@ -462,504 +367,6 @@
-fn target_spec(name: &str) -> anyhow::Result<TargetSpec> {
@@ -462,504 +367,6 @@
-fn agent_contract_jobs() -> Vec<JobSpec> {
@@ -462,504 +367,6 @@
-fn pika_rust_jobs() -> Vec<JobSpec> {
The new crates/pikaci/src/targets.rs receives:
Struct
TargetSpec — the central type describing a CI target (id, description, filters, jobs).
Runtime helpers
remote_incus_runtime() — build an Incus JobRuntimeConfig
tart_runtime() — build a Tart JobRuntimeConfig
remote_incus_job_base(), host_local_job_base(), tart_job_base() — default JobSpec scaffolds
TART_HOST_SETUP_COMMAND constant
Job-group factories (each returns Vec<JobSpec>)
agent_contract_jobs, pika_rust_jobs, notification_jobs, pikachat_rust_jobs, pika_followup_jobs, pikachat_openclaw_e2e_jobs, pikachat_typescript_jobs, fixture_rust_jobs, pikachat_apple_followup_jobs, rmp_jobs
- Individual Tart job builders:
tart_agent_button_job, tart_ios_unit_jobs, tart_ios_unit_suite_job, tart_ios_ui_test_job, tart_ios_ui_note_to_self_job, tart_desktop_package_tests_job
Dispatchers
target_spec(name) -> Result<TargetSpec> — the main match-based target resolver
staged_linux_target(target_id) — parse a target ID into PikaStagedLinuxTarget
staged_linux_target_spec, single_job_target_spec, static_filters — helpers
In main.rs the import list shrinks from pulling individual jerichoci types for job construction to only the types needed for the CLI entrypoint:
use targets::{TargetSpec, staged_linux_target, target_spec};
All call-sites in main.rs that previously referenced these functions now resolve through the module re-export. No behavioral changes are introduced.
Slim down main.rs imports to match the reduced surface
Intent: With output and targets extracted, `main.rs` no longer directly references many jerichoci types. The import block is tightened to only what the remaining CLI orchestration code needs.
Affected files: crates/pikaci/src/main.rs
Evidence
@@ -1,84 +1,24 @@
-use jerichoci::{
- GuestCommand, HostProcessRuntimeConfig, IncusRuntimeConfig, JobExecutionConfig,
- JobRuntimeConfig, JobSpec, LogKind, RunLifecycleEvent, RunMetadata, RunOptions, RunRecord,
- RunStatus, StagedLinuxCommandConfig, StagedLinuxRemoteDefaults, TartRuntimeConfig,
+use jerichoci::{
+ LogKind, RunLifecycleEvent, RunMetadata, RunOptions, RunRecord, RunStatus,
+ StagedLinuxRemoteDefaults, fulfill_prepared_output_request, gc_runs, git_changed_files,
Before the refactor main.rs imported 16 types/functions from jerichoci (including GuestCommand, HostProcessRuntimeConfig, IncusRuntimeConfig, JobExecutionConfig, JobRuntimeConfig, JobSpec, StagedLinuxCommandConfig, TartRuntimeConfig). After extraction, only the types used by CLI dispatch and run lifecycle remain:
use jerichoci::{
LogKind, RunLifecycleEvent, RunMetadata, RunOptions, RunRecord, RunStatus,
StagedLinuxRemoteDefaults, fulfill_prepared_output_request, gc_runs, git_changed_files,
list_runs, load_logs, load_logs_metadata, load_prepared_outputs_record, load_run_record,
record_skipped_run_with_reporter, rerun_jobs_with_metadata_and_reporter,
run_jobs_with_metadata_and_reporter, staged_linux_remote_defaults,
};
The removed imports are now consumed exclusively inside targets.rs.
Update architecture invariants to accommodate the new module layout
Intent: The project's `invariants/invariants.toml` enforces constraints on where certain patterns may appear. The new files and the annotated test fixtures need explicit exclusion entries so the invariant checker does not produce false positives.
Affected files: invariants/invariants.toml
Evidence
@@ -452,6 +452,8 @@ mod tests {
Although the diff for invariants/invariants.toml was truncated in the payload, it is listed as a changed file. Based on the doc-comments added in step 1 and the new module files created in steps 2–3, the invariants file is expected to contain:
- Exclusion entries for
crates/pikaci/src/output.rs and crates/pikaci/src/targets.rs — these files now contain patterns (e.g., catalog lane references, job-spec constructors) that previously lived in the already-exempted main.rs.
- Exclusion entries for test-only fixture enums in
crates/jerichoci/src/model.rs and crates/jerichoci/src/run.rs — keyed on the comment sentinel added in step 1.
Without these updates, the invariant checker would flag the extracted code as violating the architecture rules, since the patterns moved to files not previously in its allow-list.
When reviewing this file, verify that each new exclusion is scoped as narrowly as possible (file path + test module context) rather than blanket-disabling the invariant.