mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-05 08:10:39 +00:00
parent
6fb4d5968b
commit
468ea5806d
6 changed files with 358 additions and 43 deletions
111
checkpoint.json
111
checkpoint.json
|
|
@ -1,57 +1,94 @@
|
|||
{
|
||||
"timestamp": "2026-04-01T15:53:56.406144Z",
|
||||
"current_node": "implement",
|
||||
"timestamp": "2026-04-01T15:57:43.715411Z",
|
||||
"current_node": "simplify_opus",
|
||||
"completed_nodes": [
|
||||
"start",
|
||||
"toolchain",
|
||||
"preflight_compile",
|
||||
"preflight_lint",
|
||||
"implement"
|
||||
"implement",
|
||||
"simplify_opus"
|
||||
],
|
||||
"node_retries": {},
|
||||
"context_values": {
|
||||
"command.output": "",
|
||||
"outcome": "success",
|
||||
"internal.retry_count.implement": 0,
|
||||
"failure_signature": "",
|
||||
"thread.start.current_node": "toolchain",
|
||||
"thread.preflight_lint.current_node": "implement",
|
||||
"internal.retry_count.preflight_lint": 0,
|
||||
"internal.thread_id": "implement",
|
||||
"thread.implement.current_node": "simplify_opus",
|
||||
"response.simplify_opus": "## Summary\n\n### What was fixed\n\n**Extracted `exec_local_workflow` helper to eliminate copy-paste** (`lib/crates/fabro-cli/tests/it/cmd/support.rs`):\n- The new `setup_failed_run` function duplicated 13 lines of command construction from the existing `run_local_workflow` function (same args, env, timeout, current_dir).\n- Extracted a lower-level `exec_local_workflow` helper that builds and executes the command without asserting success, returning the raw `Output`.\n- Rewired `run_local_workflow` to call `exec_local_workflow` and then assert success (preserving its existing behavior).\n- Simplified `setup_failed_run` to call `exec_local_workflow` in a single line instead of manually rebuilding the command.\n\n### What was already clean (no action needed)\n\n- **`--force` flag** (`args.rs`): Uses `#[arg(short, long)]` giving `-f`/`--force`, consistent with other destructive-override flags like `runs rm --force`. No short-flag conflicts.\n- **Match pattern** (`pr/create.rs`): The guard-based match arm is idiomatic Rust and the `tracing::warn!` follows the project's logging strategy.\n- **Test structure** (`pr_create.rs`): Two focused tests with clear names and expected-output snapshots. Each needs its own `setup_failed_run` call since tests must be independent.\n- **No efficiency concerns**: The production code change adds a trivial match arm with no performance impact. Test helpers appropriately do the minimum work needed.",
|
||||
"internal.retry_count.start": 0,
|
||||
"internal.retry_count.simplify_opus": 0,
|
||||
"command.stderr": "",
|
||||
"failure_class": "",
|
||||
"failure_signature": "",
|
||||
"response.implement": "All changes are clean and focused. Here's a summary of what was implemented:\n\n### Changes Made\n\n1. **`lib/crates/fabro-cli/src/args.rs`** — Added `#[arg(short, long)] pub(crate) force: bool` to `PrCreateArgs`, with help text explaining it bypasses the status check.\n\n2. **`lib/crates/fabro-cli/src/commands/pr/create.rs`** — Updated the status check `match` to include a new arm `status if args.force =>` that logs a warning and continues instead of bailing.\n\n3. **`lib/crates/fabro-cli/tests/it/cmd/support.rs`** — Added `setup_failed_run` helper that creates a workspace with a workflow containing a `shape=parallelogram, script=\"exit 1\", goal_gate=true` node, runs it, and asserts the conclusion status is \"fail\".\n\n4. **`lib/crates/fabro-cli/tests/it/cmd/pr_create.rs`** — Added two integration tests:\n - `pr_create_failed_run_rejects_without_force` — verifies failed runs are rejected with the expected error message\n - `pr_create_failed_run_proceeds_with_force` — verifies `--force` bypasses the status gate and hits the next validation error (\"Run has no run_branch\")\n - Updated the `help` snapshot to include the new `-f, --force` flag\n\n### Verification\n- `cargo clippy -p fabro-cli -- -D warnings` — passes clean\n- `cargo nextest run -p fabro-cli -- pr_create` — all 5 tests pass\n- `./target/debug/fabro pr create --help` — confirms `-f`/`--force` appears",
|
||||
"current.preamble": "Goal: # Add `--force` flag to `fabro pr create`\n\n## Context\n`fabro pr create` rejects runs with non-success status. Users sometimes want to create PRs for failed runs (e.g. partial work worth reviewing). A `--force` flag bypasses the status check.\n\n## Changes\n\n### 1. Add `--force` flag to `PrCreateArgs` (`lib/crates/fabro-cli/src/args.rs:582-588`)\nAdd `#[arg(short, long)] pub(crate) force: bool` to `PrCreateArgs`.\n\n### 2. Pass `force` through and skip status check (`lib/crates/fabro-cli/src/commands/pr/create.rs:76-79`)\nReplace the hard bail with a warning when `--force` is set:\n```rust\nmatch conclusion.status {\n StageStatus::Success | StageStatus::PartialSuccess => {}\n status if args.force => {\n tracing::warn!(\"Run status is '{status}', proceeding because --force was specified\");\n }\n status => bail!(\"Run status is '{status}', expected success or partial_success\"),\n}\n```\n\n### 3. Add `setup_failed_run` helper (`lib/crates/fabro-cli/tests/it/cmd/support.rs`)\nNew helper that runs a real (non-dry-run) workflow with a `shape=parallelogram, script=\"exit 1\"` node. This produces a genuine `conclusion.json` with `status: \"fail\"`. Pattern follows `run_local_workflow` — uses `--sandbox local --provider openai` with `OPENAI_API_KEY=test`. The helper won't assert CLI exit success since the workflow fails; instead it finds the run dir via `only_run`.\n\n### 4. Add integration tests (`lib/crates/fabro-cli/tests/it/cmd/pr_create.rs`)\n\n**a) `pr_create_failed_run_rejects_without_force`** — `setup_failed_run`, run `pr create <run_id>`, assert error \"Run status is 'fail', expected success or partial_success\"\n\n**b) `pr_create_failed_run_proceeds_with_force`** — `setup_failed_run`, run `pr create --force <run_id>`, assert it passes status check and hits next validation error (\"Run has no run_branch\"). Proves `--force` bypassed the status gate.\n\n## Verification\n- `cargo clippy -p fabro-cli -- -D warnings`\n- `cargo nextest run -p fabro-cli`\n- `./target/debug/fabro pr create --help` — confirm `-f`/`--force` appears\n\n\n## Completed stages\n- **toolchain**: success\n - Script: `command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1`\n - Stdout:\n ```\n cargo 1.94.0 (85eff7c80 2026-01-15)\n ```\n - Stderr: (empty)\n- **preflight_compile**: success\n - Script: `cargo check -q --workspace 2>&1`\n - Stdout: (empty)\n - Stderr: (empty)\n- **preflight_lint**: success\n - Script: `cargo clippy -q --workspace -- -D warnings 2>&1`\n - Stdout: (empty)\n - Stderr: (empty)\n- **implement**: success\n - Model: claude-opus-4-6, 51.8k tokens in / 9.9k out\n - Files: /home/daytona/workspace/lib/crates/fabro-cli/src/args.rs, /home/daytona/workspace/lib/crates/fabro-cli/src/commands/pr/create.rs, /home/daytona/workspace/lib/crates/fabro-cli/tests/it/cmd/pr_create.rs, /home/daytona/workspace/lib/crates/fabro-cli/tests/it/cmd/support.rs\n",
|
||||
"internal.fidelity": "compact",
|
||||
"thread.toolchain.current_node": "preflight_compile",
|
||||
"last_stage": "simplify_opus",
|
||||
"thread.preflight_compile.current_node": "preflight_lint",
|
||||
"graph.goal": "# Add `--force` flag to `fabro pr create`\n\n## Context\n`fabro pr create` rejects runs with non-success status. Users sometimes want to create PRs for failed runs (e.g. partial work worth reviewing). A `--force` flag bypasses the status check.\n\n## Changes\n\n### 1. Add `--force` flag to `PrCreateArgs` (`lib/crates/fabro-cli/src/args.rs:582-588`)\nAdd `#[arg(short, long)] pub(crate) force: bool` to `PrCreateArgs`.\n\n### 2. Pass `force` through and skip status check (`lib/crates/fabro-cli/src/commands/pr/create.rs:76-79`)\nReplace the hard bail with a warning when `--force` is set:\n```rust\nmatch conclusion.status {\n StageStatus::Success | StageStatus::PartialSuccess => {}\n status if args.force => {\n tracing::warn!(\"Run status is '{status}', proceeding because --force was specified\");\n }\n status => bail!(\"Run status is '{status}', expected success or partial_success\"),\n}\n```\n\n### 3. Add `setup_failed_run` helper (`lib/crates/fabro-cli/tests/it/cmd/support.rs`)\nNew helper that runs a real (non-dry-run) workflow with a `shape=parallelogram, script=\"exit 1\"` node. This produces a genuine `conclusion.json` with `status: \"fail\"`. Pattern follows `run_local_workflow` — uses `--sandbox local --provider openai` with `OPENAI_API_KEY=test`. The helper won't assert CLI exit success since the workflow fails; instead it finds the run dir via `only_run`.\n\n### 4. Add integration tests (`lib/crates/fabro-cli/tests/it/cmd/pr_create.rs`)\n\n**a) `pr_create_failed_run_rejects_without_force`** — `setup_failed_run`, run `pr create <run_id>`, assert error \"Run status is 'fail', expected success or partial_success\"\n\n**b) `pr_create_failed_run_proceeds_with_force`** — `setup_failed_run`, run `pr create --force <run_id>`, assert it passes status check and hits next validation error (\"Run has no run_branch\"). Proves `--force` bypassed the status gate.\n\n## Verification\n- `cargo clippy -p fabro-cli -- -D warnings`\n- `cargo nextest run -p fabro-cli`\n- `./target/debug/fabro pr create --help` — confirm `-f`/`--force` appears\n",
|
||||
"current.preamble": "Goal: # Add `--force` flag to `fabro pr create`\n\n## Context\n`fabro pr create` rejects runs with non-success status. Users sometimes want to create PRs for failed runs (e.g. partial work worth reviewing). A `--force` flag bypasses the status check.\n\n## Changes\n\n### 1. Add `--force` flag to `PrCreateArgs` (`lib/crates/fabro-cli/src/args.rs:582-588`)\nAdd `#[arg(short, long)] pub(crate) force: bool` to `PrCreateArgs`.\n\n### 2. Pass `force` through and skip status check (`lib/crates/fabro-cli/src/commands/pr/create.rs:76-79`)\nReplace the hard bail with a warning when `--force` is set:\n```rust\nmatch conclusion.status {\n StageStatus::Success | StageStatus::PartialSuccess => {}\n status if args.force => {\n tracing::warn!(\"Run status is '{status}', proceeding because --force was specified\");\n }\n status => bail!(\"Run status is '{status}', expected success or partial_success\"),\n}\n```\n\n### 3. Add `setup_failed_run` helper (`lib/crates/fabro-cli/tests/it/cmd/support.rs`)\nNew helper that runs a real (non-dry-run) workflow with a `shape=parallelogram, script=\"exit 1\"` node. This produces a genuine `conclusion.json` with `status: \"fail\"`. Pattern follows `run_local_workflow` — uses `--sandbox local --provider openai` with `OPENAI_API_KEY=test`. The helper won't assert CLI exit success since the workflow fails; instead it finds the run dir via `only_run`.\n\n### 4. Add integration tests (`lib/crates/fabro-cli/tests/it/cmd/pr_create.rs`)\n\n**a) `pr_create_failed_run_rejects_without_force`** — `setup_failed_run`, run `pr create <run_id>`, assert error \"Run status is 'fail', expected success or partial_success\"\n\n**b) `pr_create_failed_run_proceeds_with_force`** — `setup_failed_run`, run `pr create --force <run_id>`, assert it passes status check and hits next validation error (\"Run has no run_branch\"). Proves `--force` bypassed the status gate.\n\n## Verification\n- `cargo clippy -p fabro-cli -- -D warnings`\n- `cargo nextest run -p fabro-cli`\n- `./target/debug/fabro pr create --help` — confirm `-f`/`--force` appears\n\n\n## Completed stages\n- **toolchain**: success\n - Script: `command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1`\n - Stdout:\n ```\n cargo 1.94.0 (85eff7c80 2026-01-15)\n ```\n - Stderr: (empty)\n- **preflight_compile**: success\n - Script: `cargo check -q --workspace 2>&1`\n - Stdout: (empty)\n - Stderr: (empty)\n- **preflight_lint**: success\n - Script: `cargo clippy -q --workspace -- -D warnings 2>&1`\n - Stdout: (empty)\n - Stderr: (empty)\n",
|
||||
"internal.thread_id": "preflight_lint",
|
||||
"thread.start.current_node": "toolchain",
|
||||
"internal.run_id": "01KN4VB09T999RE1V2DD8Z3YC3",
|
||||
"last_stage": "implement",
|
||||
"internal.node_visit_count": 1,
|
||||
"outcome": "success",
|
||||
"command.output": "",
|
||||
"internal.retry_count.preflight_compile": 0,
|
||||
"internal.retry_count.toolchain": 0,
|
||||
"graph.model_stylesheet": "\n * { model: claude-opus-4-6; }\n ",
|
||||
"response.implement": "All changes are clean and focused. Here's a summary of what was implemented:\n\n### Changes Made\n\n1. **`lib/crates/fabro-cli/src/args.rs`** — Added `#[arg(short, long)] pub(crate) force: bool` to `PrCreateArgs`, with help text explaining it bypasses the status check.\n\n2. **`lib/crates/fabro-cli/src/commands/pr/create.rs`** — Updated the status check `match` to include a new arm `status if args.force =>` that logs a warning and continues instead of bailing.\n\n3. **`lib/crates/fabro-cli/tests/it/cmd/support.rs`** — Added `setup_failed_run` helper that creates a workspace with a workflow containing a `shape=parallelogram, script=\"exit 1\", goal_gate=true` node, runs it, and asserts the conclusion status is \"fail\".\n\n4. **`lib/crates/fabro-cli/tests/it/cmd/pr_create.rs`** — Added two integration tests:\n - `pr_create_failed_run_rejects_without_force` — verifies failed runs are rejected with the expected error message\n - `pr_create_failed_run_proceeds_with_force` — verifies `--force` bypasses the status gate and hits the next validation error (\"Run has no run_branch\")\n - Updated the `help` snapshot to include the new `-f, --force` flag\n\n### Verification\n- `cargo clippy -p fabro-cli -- -D warnings` — passes clean\n- `cargo nextest run -p fabro-cli -- pr_create` — all 5 tests pass\n- `./target/debug/fabro pr create --help` — confirms `-f`/`--force` appears",
|
||||
"internal.retry_count.preflight_compile": 0,
|
||||
"thread.toolchain.current_node": "preflight_compile",
|
||||
"internal.retry_count.start": 0,
|
||||
"last_response": "All changes are clean and focused. Here's a summary of what was implemented:\n\n### Changes Made\n\n1. **`lib/crates/fabro-cli/src/args.rs`** — Added `#[arg(short, long)] pub(crate) force: bool` to `PrC",
|
||||
"internal.fidelity": "compact",
|
||||
"command.stderr": "",
|
||||
"internal.node_visit_count": 1,
|
||||
"thread.preflight_lint.current_node": "implement",
|
||||
"last_response": "## Summary\n\n### What was fixed\n\n**Extracted `exec_local_workflow` helper to eliminate copy-paste** (`lib/crates/fabro-cli/tests/it/cmd/support.rs`):\n- The new `setup_failed_run` function duplicated 13",
|
||||
"graph.rankdir": "LR",
|
||||
"thread.preflight_compile.current_node": "preflight_lint",
|
||||
"current_node": "implement"
|
||||
"internal.retry_count.preflight_lint": 0,
|
||||
"current_node": "simplify_opus",
|
||||
"internal.retry_count.implement": 0
|
||||
},
|
||||
"node_outcomes": {
|
||||
"toolchain": {
|
||||
"status": "success",
|
||||
"context_updates": {
|
||||
"command.output": "cargo 1.94.0 (85eff7c80 2026-01-15)\n",
|
||||
"command.stderr": ""
|
||||
"command.stderr": "",
|
||||
"command.output": "cargo 1.94.0 (85eff7c80 2026-01-15)\n"
|
||||
},
|
||||
"notes": "Script completed: command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1",
|
||||
"usage": null
|
||||
},
|
||||
"preflight_compile": {
|
||||
"status": "success",
|
||||
"context_updates": {
|
||||
"command.output": "",
|
||||
"command.stderr": ""
|
||||
},
|
||||
"notes": "Script completed: cargo check -q --workspace 2>&1",
|
||||
"usage": null
|
||||
},
|
||||
"simplify_opus": {
|
||||
"status": "success",
|
||||
"context_updates": {
|
||||
"last_response": "## Summary\n\n### What was fixed\n\n**Extracted `exec_local_workflow` helper to eliminate copy-paste** (`lib/crates/fabro-cli/tests/it/cmd/support.rs`):\n- The new `setup_failed_run` function duplicated 13",
|
||||
"response.simplify_opus": "## Summary\n\n### What was fixed\n\n**Extracted `exec_local_workflow` helper to eliminate copy-paste** (`lib/crates/fabro-cli/tests/it/cmd/support.rs`):\n- The new `setup_failed_run` function duplicated 13 lines of command construction from the existing `run_local_workflow` function (same args, env, timeout, current_dir).\n- Extracted a lower-level `exec_local_workflow` helper that builds and executes the command without asserting success, returning the raw `Output`.\n- Rewired `run_local_workflow` to call `exec_local_workflow` and then assert success (preserving its existing behavior).\n- Simplified `setup_failed_run` to call `exec_local_workflow` in a single line instead of manually rebuilding the command.\n\n### What was already clean (no action needed)\n\n- **`--force` flag** (`args.rs`): Uses `#[arg(short, long)]` giving `-f`/`--force`, consistent with other destructive-override flags like `runs rm --force`. No short-flag conflicts.\n- **Match pattern** (`pr/create.rs`): The guard-based match arm is idiomatic Rust and the `tracing::warn!` follows the project's logging strategy.\n- **Test structure** (`pr_create.rs`): Two focused tests with clear names and expected-output snapshots. Each needs its own `setup_failed_run` call since tests must be independent.\n- **No efficiency concerns**: The production code change adds a trivial match arm with no performance impact. Test helpers appropriately do the minimum work needed.",
|
||||
"last_stage": "simplify_opus"
|
||||
},
|
||||
"notes": "Stage completed: simplify_opus",
|
||||
"usage": {
|
||||
"model": "claude-opus-4-6",
|
||||
"input_tokens": 38864,
|
||||
"output_tokens": 6181,
|
||||
"cache_read_tokens": 329221,
|
||||
"cache_write_tokens": 44033,
|
||||
"cost": 1.046535
|
||||
},
|
||||
"files_touched": [
|
||||
"/home/daytona/workspace/lib/crates/fabro-cli/tests/it/cmd/support.rs"
|
||||
]
|
||||
},
|
||||
"start": {
|
||||
"status": "success",
|
||||
"usage": null
|
||||
},
|
||||
"implement": {
|
||||
"status": "success",
|
||||
"context_updates": {
|
||||
"last_stage": "implement",
|
||||
"last_response": "All changes are clean and focused. Here's a summary of what was implemented:\n\n### Changes Made\n\n1. **`lib/crates/fabro-cli/src/args.rs`** — Added `#[arg(short, long)] pub(crate) force: bool` to `PrC",
|
||||
"last_stage": "implement",
|
||||
"response.implement": "All changes are clean and focused. Here's a summary of what was implemented:\n\n### Changes Made\n\n1. **`lib/crates/fabro-cli/src/args.rs`** — Added `#[arg(short, long)] pub(crate) force: bool` to `PrCreateArgs`, with help text explaining it bypasses the status check.\n\n2. **`lib/crates/fabro-cli/src/commands/pr/create.rs`** — Updated the status check `match` to include a new arm `status if args.force =>` that logs a warning and continues instead of bailing.\n\n3. **`lib/crates/fabro-cli/tests/it/cmd/support.rs`** — Added `setup_failed_run` helper that creates a workspace with a workflow containing a `shape=parallelogram, script=\"exit 1\", goal_gate=true` node, runs it, and asserts the conclusion status is \"fail\".\n\n4. **`lib/crates/fabro-cli/tests/it/cmd/pr_create.rs`** — Added two integration tests:\n - `pr_create_failed_run_rejects_without_force` — verifies failed runs are rejected with the expected error message\n - `pr_create_failed_run_proceeds_with_force` — verifies `--force` bypasses the status gate and hits the next validation error (\"Run has no run_branch\")\n - Updated the `help` snapshot to include the new `-f, --force` flag\n\n### Verification\n- `cargo clippy -p fabro-cli -- -D warnings` — passes clean\n- `cargo nextest run -p fabro-cli -- pr_create` — all 5 tests pass\n- `./target/debug/fabro pr create --help` — confirms `-f`/`--force` appears"
|
||||
},
|
||||
"notes": "Stage completed: implement",
|
||||
|
|
@ -70,10 +107,6 @@
|
|||
"/home/daytona/workspace/lib/crates/fabro-cli/tests/it/cmd/support.rs"
|
||||
]
|
||||
},
|
||||
"start": {
|
||||
"status": "success",
|
||||
"usage": null
|
||||
},
|
||||
"preflight_lint": {
|
||||
"status": "success",
|
||||
"context_updates": {
|
||||
|
|
@ -82,23 +115,15 @@
|
|||
},
|
||||
"notes": "Script completed: cargo clippy -q --workspace -- -D warnings 2>&1",
|
||||
"usage": null
|
||||
},
|
||||
"preflight_compile": {
|
||||
"status": "success",
|
||||
"context_updates": {
|
||||
"command.output": "",
|
||||
"command.stderr": ""
|
||||
},
|
||||
"notes": "Script completed: cargo check -q --workspace 2>&1",
|
||||
"usage": null
|
||||
}
|
||||
},
|
||||
"next_node_id": "simplify_opus",
|
||||
"next_node_id": "simplify_gpt",
|
||||
"node_visits": {
|
||||
"preflight_lint": 1,
|
||||
"start": 1,
|
||||
"implement": 1,
|
||||
"preflight_lint": 1,
|
||||
"toolchain": 1,
|
||||
"preflight_compile": 1
|
||||
"preflight_compile": 1,
|
||||
"simplify_opus": 1,
|
||||
"toolchain": 1
|
||||
}
|
||||
}
|
||||
155
nodes/implement/diff.patch
Normal file
155
nodes/implement/diff.patch
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
diff --git a/lib/crates/fabro-cli/src/args.rs b/lib/crates/fabro-cli/src/args.rs
|
||||
index 82ba57d9..0cf3ca9f 100644
|
||||
--- a/lib/crates/fabro-cli/src/args.rs
|
||||
+++ b/lib/crates/fabro-cli/src/args.rs
|
||||
@@ -585,6 +585,9 @@ pub(crate) struct PrCreateArgs {
|
||||
/// LLM model for generating PR description
|
||||
#[arg(long)]
|
||||
pub(crate) model: Option<String>,
|
||||
+ /// Create PR even if the run status is not success/partial_success
|
||||
+ #[arg(short, long)]
|
||||
+ pub(crate) force: bool,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
diff --git a/lib/crates/fabro-cli/src/commands/pr/create.rs b/lib/crates/fabro-cli/src/commands/pr/create.rs
|
||||
index 873630cb..7a1fa16e 100644
|
||||
--- a/lib/crates/fabro-cli/src/commands/pr/create.rs
|
||||
+++ b/lib/crates/fabro-cli/src/commands/pr/create.rs
|
||||
@@ -75,6 +75,9 @@ async fn create_from(
|
||||
|
||||
match conclusion.status {
|
||||
StageStatus::Success | StageStatus::PartialSuccess => {}
|
||||
+ status if args.force => {
|
||||
+ tracing::warn!("Run status is '{status}', proceeding because --force was specified");
|
||||
+ }
|
||||
status => bail!("Run status is '{status}', expected success or partial_success"),
|
||||
}
|
||||
|
||||
diff --git a/lib/crates/fabro-cli/tests/it/cmd/pr_create.rs b/lib/crates/fabro-cli/tests/it/cmd/pr_create.rs
|
||||
index 99a468c1..e414f19b 100644
|
||||
--- a/lib/crates/fabro-cli/tests/it/cmd/pr_create.rs
|
||||
+++ b/lib/crates/fabro-cli/tests/it/cmd/pr_create.rs
|
||||
@@ -1,6 +1,6 @@
|
||||
use fabro_test::{fabro_snapshot, test_context};
|
||||
|
||||
-use super::support::{setup_completed_dry_run, setup_created_dry_run};
|
||||
+use super::support::{setup_completed_dry_run, setup_created_dry_run, setup_failed_run};
|
||||
|
||||
#[test]
|
||||
fn help() {
|
||||
@@ -22,6 +22,7 @@ fn help() {
|
||||
--json Output as JSON [env: FABRO_JSON=]
|
||||
--model <MODEL> LLM model for generating PR description
|
||||
--debug Enable DEBUG-level logging (default is INFO) [env: FABRO_DEBUG=]
|
||||
+ -f, --force Create PR even if the run status is not success/partial_success
|
||||
--no-upgrade-check Disable automatic upgrade check [env: FABRO_NO_UPGRADE_CHECK=true]
|
||||
--quiet Suppress non-essential output [env: FABRO_QUIET=]
|
||||
--verbose Enable verbose output [env: FABRO_VERBOSE=]
|
||||
@@ -63,3 +64,35 @@ fn pr_create_completed_dry_run_without_run_branch_errors() {
|
||||
error: Run has no run_branch — was it run with git push enabled?
|
||||
");
|
||||
}
|
||||
+
|
||||
+#[test]
|
||||
+fn pr_create_failed_run_rejects_without_force() {
|
||||
+ let context = test_context!();
|
||||
+ let run = setup_failed_run(&context);
|
||||
+ let mut cmd = context.command();
|
||||
+ cmd.args(["pr", "create", &run.run_id]);
|
||||
+
|
||||
+ fabro_snapshot!(context.filters(), cmd, @"
|
||||
+ success: false
|
||||
+ exit_code: 1
|
||||
+ ----- stdout -----
|
||||
+ ----- stderr -----
|
||||
+ error: Run status is 'fail', expected success or partial_success
|
||||
+ ");
|
||||
+}
|
||||
+
|
||||
+#[test]
|
||||
+fn pr_create_failed_run_proceeds_with_force() {
|
||||
+ let context = test_context!();
|
||||
+ let run = setup_failed_run(&context);
|
||||
+ let mut cmd = context.command();
|
||||
+ cmd.args(["pr", "create", "--force", &run.run_id]);
|
||||
+
|
||||
+ fabro_snapshot!(context.filters(), cmd, @"
|
||||
+ success: false
|
||||
+ exit_code: 1
|
||||
+ ----- stdout -----
|
||||
+ ----- stderr -----
|
||||
+ error: Run has no run_branch — was it run with git push enabled?
|
||||
+ ");
|
||||
+}
|
||||
diff --git a/lib/crates/fabro-cli/tests/it/cmd/support.rs b/lib/crates/fabro-cli/tests/it/cmd/support.rs
|
||||
index 0a6d5ab3..e36b74d6 100644
|
||||
--- a/lib/crates/fabro-cli/tests/it/cmd/support.rs
|
||||
+++ b/lib/crates/fabro-cli/tests/it/cmd/support.rs
|
||||
@@ -288,6 +288,66 @@ worktree_mode = "never"
|
||||
WorkspaceRunSetup { run, workspace_dir }
|
||||
}
|
||||
|
||||
+pub(crate) fn setup_failed_run(context: &TestContext) -> RunSetup {
|
||||
+ let workspace_dir = context.temp_dir.join("failed-run");
|
||||
+ std::fs::create_dir_all(&workspace_dir)
|
||||
+ .unwrap_or_else(|err| panic!("failed to create {}: {err}", workspace_dir.display()));
|
||||
+
|
||||
+ write_text_file(
|
||||
+ &workspace_dir.join("fail.fabro"),
|
||||
+ r#"digraph Fail {
|
||||
+ graph [goal="Always fail", default_max_retries=0]
|
||||
+ start [shape=Mdiamond]
|
||||
+ exit [shape=Msquare]
|
||||
+ boom [shape=parallelogram, script="exit 1", goal_gate=true]
|
||||
+ start -> boom -> exit
|
||||
+}
|
||||
+"#,
|
||||
+ );
|
||||
+ write_text_file(
|
||||
+ &workspace_dir.join("run.toml"),
|
||||
+ r#"version = 1
|
||||
+graph = "fail.fabro"
|
||||
+goal = "Always fail"
|
||||
+
|
||||
+[sandbox]
|
||||
+provider = "local"
|
||||
+
|
||||
+[sandbox.local]
|
||||
+worktree_mode = "never"
|
||||
+"#,
|
||||
+ );
|
||||
+
|
||||
+ let mut cmd = context.command();
|
||||
+ cmd.current_dir(&workspace_dir);
|
||||
+ cmd.timeout(COMMAND_TIMEOUT);
|
||||
+ cmd.env("OPENAI_API_KEY", "test");
|
||||
+ cmd.args([
|
||||
+ "run",
|
||||
+ "--auto-approve",
|
||||
+ "--no-retro",
|
||||
+ "--sandbox",
|
||||
+ "local",
|
||||
+ "--provider",
|
||||
+ "openai",
|
||||
+ "run.toml",
|
||||
+ ]);
|
||||
+ // The workflow is expected to fail (script exits 1), but the CLI may still
|
||||
+ // exit 0. We only care that conclusion.json records a non-success status.
|
||||
+ let _output = cmd.output().expect("command should execute");
|
||||
+
|
||||
+ let run = only_run(context);
|
||||
+ let conclusion = read_json(&run.run_dir.join("conclusion.json"));
|
||||
+ let status = conclusion["status"]
|
||||
+ .as_str()
|
||||
+ .expect("conclusion.json should have a status field");
|
||||
+ assert_eq!(
|
||||
+ status, "fail",
|
||||
+ "setup_failed_run should produce a failed conclusion"
|
||||
+ );
|
||||
+ run
|
||||
+}
|
||||
+
|
||||
fn run_local_workflow(context: &TestContext, workspace_dir: &Path, workflow: &str) -> RunSetup {
|
||||
let mut cmd = context.command();
|
||||
cmd.current_dir(workspace_dir);
|
||||
108
nodes/simplify_opus/prompt.md
Normal file
108
nodes/simplify_opus/prompt.md
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
Goal: # Add `--force` flag to `fabro pr create`
|
||||
|
||||
## Context
|
||||
`fabro pr create` rejects runs with non-success status. Users sometimes want to create PRs for failed runs (e.g. partial work worth reviewing). A `--force` flag bypasses the status check.
|
||||
|
||||
## Changes
|
||||
|
||||
### 1. Add `--force` flag to `PrCreateArgs` (`lib/crates/fabro-cli/src/args.rs:582-588`)
|
||||
Add `#[arg(short, long)] pub(crate) force: bool` to `PrCreateArgs`.
|
||||
|
||||
### 2. Pass `force` through and skip status check (`lib/crates/fabro-cli/src/commands/pr/create.rs:76-79`)
|
||||
Replace the hard bail with a warning when `--force` is set:
|
||||
```rust
|
||||
match conclusion.status {
|
||||
StageStatus::Success | StageStatus::PartialSuccess => {}
|
||||
status if args.force => {
|
||||
tracing::warn!("Run status is '{status}', proceeding because --force was specified");
|
||||
}
|
||||
status => bail!("Run status is '{status}', expected success or partial_success"),
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Add `setup_failed_run` helper (`lib/crates/fabro-cli/tests/it/cmd/support.rs`)
|
||||
New helper that runs a real (non-dry-run) workflow with a `shape=parallelogram, script="exit 1"` node. This produces a genuine `conclusion.json` with `status: "fail"`. Pattern follows `run_local_workflow` — uses `--sandbox local --provider openai` with `OPENAI_API_KEY=test`. The helper won't assert CLI exit success since the workflow fails; instead it finds the run dir via `only_run`.
|
||||
|
||||
### 4. Add integration tests (`lib/crates/fabro-cli/tests/it/cmd/pr_create.rs`)
|
||||
|
||||
**a) `pr_create_failed_run_rejects_without_force`** — `setup_failed_run`, run `pr create <run_id>`, assert error "Run status is 'fail', expected success or partial_success"
|
||||
|
||||
**b) `pr_create_failed_run_proceeds_with_force`** — `setup_failed_run`, run `pr create --force <run_id>`, assert it passes status check and hits next validation error ("Run has no run_branch"). Proves `--force` bypassed the status gate.
|
||||
|
||||
## Verification
|
||||
- `cargo clippy -p fabro-cli -- -D warnings`
|
||||
- `cargo nextest run -p fabro-cli`
|
||||
- `./target/debug/fabro pr create --help` — confirm `-f`/`--force` appears
|
||||
|
||||
|
||||
## Completed stages
|
||||
- **toolchain**: success
|
||||
- Script: `command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1`
|
||||
- Stdout:
|
||||
```
|
||||
cargo 1.94.0 (85eff7c80 2026-01-15)
|
||||
```
|
||||
- Stderr: (empty)
|
||||
- **preflight_compile**: success
|
||||
- Script: `cargo check -q --workspace 2>&1`
|
||||
- Stdout: (empty)
|
||||
- Stderr: (empty)
|
||||
- **preflight_lint**: success
|
||||
- Script: `cargo clippy -q --workspace -- -D warnings 2>&1`
|
||||
- Stdout: (empty)
|
||||
- Stderr: (empty)
|
||||
- **implement**: success
|
||||
- Model: claude-opus-4-6, 51.8k tokens in / 9.9k out
|
||||
- Files: /home/daytona/workspace/lib/crates/fabro-cli/src/args.rs, /home/daytona/workspace/lib/crates/fabro-cli/src/commands/pr/create.rs, /home/daytona/workspace/lib/crates/fabro-cli/tests/it/cmd/pr_create.rs, /home/daytona/workspace/lib/crates/fabro-cli/tests/it/cmd/support.rs
|
||||
|
||||
|
||||
# Simplify: Code Review and Cleanup
|
||||
|
||||
Review all changed files for reuse, quality, and efficiency. Fix any issues found.
|
||||
|
||||
## Phase 1: Identify Changes
|
||||
|
||||
Run git diff (or git diff HEAD if there are staged changes) to see what changed. If there are no git changes, review the most recently modified files that the user mentioned or that you edited earlier in this conversation.
|
||||
|
||||
## Phase 2: Launch Three Review Agents in Parallel
|
||||
|
||||
Use the Agent tool to launch all three agents concurrently in a single message. Pass each agent the full diff so it has the complete context.
|
||||
|
||||
### Agent 1: Code Reuse Review
|
||||
|
||||
For each change:
|
||||
|
||||
1. Search for existing utilities and helpers that could replace newly written code. Use Grep to find similar patterns elsewhere in the codebase — common locations are utility directories, shared modules, and files adjacent to the changed ones.
|
||||
2. Flag any new function that duplicates existing functionality. Suggest the existing function to use instead.
|
||||
3. Flag any inline logic that could use an existing utility — hand-rolled string manipulation, manual path handling, custom environment checks, ad-hoc type guards, and similar patterns are common candidates.
|
||||
|
||||
Note: This is a greenfield app, so focus on maximizing simplicity and don't worry about changing things to achieve it.
|
||||
|
||||
### Agent 2: Code Quality Review
|
||||
|
||||
Review the same changes for hacky patterns:
|
||||
|
||||
1. Redundant state: state that duplicates existing state, cached values that could be derived, observers/effects that could be direct calls
|
||||
2. Parameter sprawl: adding new parameters to a function instead of generalizing or restructuring existing ones
|
||||
3. Copy-paste with slight variation: near-duplicate code blocks that should be unified with a shared abstraction
|
||||
4. Leaky abstractions: exposing internal details that should be encapsulated, or breaking existing abstraction boundaries
|
||||
5. Stringly-typed code: using raw strings where constants, enums (string unions), or branded types already exist in the codebase
|
||||
|
||||
Note: This is a greenfield app, so be aggressive in optimizing quality.
|
||||
|
||||
### Agent 3: Efficiency Review
|
||||
|
||||
Review the same changes for efficiency:
|
||||
|
||||
1. Unnecessary work: redundant computations, repeated file reads, duplicate network/API calls, N+1 patterns
|
||||
2. Missed concurrency: independent operations run sequentially when they could run in parallel
|
||||
3. Hot-path bloat: new blocking work added to startup or per-request/per-render hot paths
|
||||
4. Unnecessary existence checks: pre-checking file/resource existence before operating (TOCTOU anti-pattern) — operate directly and handle the error
|
||||
5. Memory: unbounded data structures, missing cleanup, event listener leaks
|
||||
6. Overly broad operations: reading entire files when only a portion is needed, loading all items when filtering for one
|
||||
|
||||
## Phase 3: Fix Issues
|
||||
|
||||
Wait for all three agents to complete. Aggregate their findings and fix each issue directly. If a finding is a false positive or not worth addressing, note it and move on — do not argue with the finding, just skip it.
|
||||
|
||||
When done, briefly summarize what was fixed (or confirm the code was already clean).
|
||||
5
nodes/simplify_opus/provider_used.json
Normal file
5
nodes/simplify_opus/provider_used.json
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"mode": "agent",
|
||||
"provider": "anthropic",
|
||||
"model": "claude-opus-4-6"
|
||||
}
|
||||
16
nodes/simplify_opus/response.md
Normal file
16
nodes/simplify_opus/response.md
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
## Summary
|
||||
|
||||
### What was fixed
|
||||
|
||||
**Extracted `exec_local_workflow` helper to eliminate copy-paste** (`lib/crates/fabro-cli/tests/it/cmd/support.rs`):
|
||||
- The new `setup_failed_run` function duplicated 13 lines of command construction from the existing `run_local_workflow` function (same args, env, timeout, current_dir).
|
||||
- Extracted a lower-level `exec_local_workflow` helper that builds and executes the command without asserting success, returning the raw `Output`.
|
||||
- Rewired `run_local_workflow` to call `exec_local_workflow` and then assert success (preserving its existing behavior).
|
||||
- Simplified `setup_failed_run` to call `exec_local_workflow` in a single line instead of manually rebuilding the command.
|
||||
|
||||
### What was already clean (no action needed)
|
||||
|
||||
- **`--force` flag** (`args.rs`): Uses `#[arg(short, long)]` giving `-f`/`--force`, consistent with other destructive-override flags like `runs rm --force`. No short-flag conflicts.
|
||||
- **Match pattern** (`pr/create.rs`): The guard-based match arm is idiomatic Rust and the `tracing::warn!` follows the project's logging strategy.
|
||||
- **Test structure** (`pr_create.rs`): Two focused tests with clear names and expected-output snapshots. Each needs its own `setup_failed_run` call since tests must be independent.
|
||||
- **No efficiency concerns**: The production code change adds a trivial match arm with no performance impact. Test helpers appropriately do the minimum work needed.
|
||||
6
nodes/simplify_opus/status.json
Normal file
6
nodes/simplify_opus/status.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"status": "success",
|
||||
"notes": "Stage completed: simplify_opus",
|
||||
"failure_reason": null,
|
||||
"timestamp": "2026-04-01T15:57:43.711795Z"
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue