diff --git a/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/integrations/evolution_ui/authorize.rs b/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/integrations/evolution_ui/authorize.rs index dd76838..e4ba89c 100644 --- a/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/integrations/evolution_ui/authorize.rs +++ b/crates/skilllite-assistant/src-tauri/src/skilllite_bridge/integrations/evolution_ui/authorize.rs @@ -2,9 +2,12 @@ use crate::skilllite_bridge::evolution_cli::spawn_skilllite_json; use crate::skilllite_bridge::local::engine_types::AuthorizeCapabilityResponse; -use crate::skilllite_bridge::local::env_keys::evolution as evo_keys; use crate::skilllite_bridge::paths::{find_project_root, load_dotenv_for_child}; +fn authorized_evolution_run_args(proposal_id: &str) -> Vec<&str> { + vec!["evolution", "run", "--json", "--proposal-id", proposal_id] +} + pub fn authorize_capability_evolution( workspace: &str, tool_name: &str, @@ -38,17 +41,33 @@ pub fn authorize_capability_evolution( let root = find_project_root(&workspace_owned); let mut cmd = std::process::Command::new(&skilllite_path_owned); crate::windows_spawn::hide_child_console(&mut cmd); - cmd.arg("evolution") - .arg("run") - .arg("--json") + cmd.args(authorized_evolution_run_args(&proposal_id_owned)) .current_dir(&root) .stdout(std::process::Stdio::piped()) .stderr(std::process::Stdio::piped()); for (k, v) in load_dotenv_for_child(&workspace_owned) { cmd.env(k, v); } - cmd.env(evo_keys::SKILLLITE_EVO_FORCE_PROPOSAL_ID, &proposal_id_owned); let _ = cmd.output(); }); Ok(proposal_id) } + +#[cfg(test)] +mod tests { + use super::authorized_evolution_run_args; + + #[test] + fn authorize_background_run_args_force_proposal() { + assert_eq!( + authorized_evolution_run_args("proposal_20260604_110000.000"), + vec![ + "evolution", + "run", + "--json", + "--proposal-id", + "proposal_20260604_110000.000" + ] + ); + } +} diff --git a/tasks/TASK-2026-067-authorized-evolution-proposal-run/CONTEXT.md b/tasks/TASK-2026-067-authorized-evolution-proposal-run/CONTEXT.md new file mode 100644 index 0000000..cdd5f50 --- /dev/null +++ b/tasks/TASK-2026-067-authorized-evolution-proposal-run/CONTEXT.md @@ -0,0 +1,28 @@ +# Technical Context + +## Current State + +- Relevant crates/files: `crates/skilllite-assistant/src-tauri/src/skilllite_bridge/integrations/evolution_ui/authorize.rs`, `crates/skilllite-commands/src/evolution.rs`, `crates/skilllite-evolution/src/run.rs`. +- Current behavior: `authorize.rs` enqueues a proposal, spawns `skilllite evolution run --json`, sets `SKILLLITE_EVO_FORCE_PROPOSAL_ID`, and discards output. `cmd_run` removes that env var when no `--proposal-id` argument is supplied, so `run_evolution_inner` does not load the authorized proposal. + +## Architecture Fit + +- Layer boundaries involved: desktop assistant UI bridge -> SkillLite CLI -> command crate -> evolution engine. +- Interfaces to preserve: Tauri command shape, `skilllite evolution authorize-capability`, `skilllite evolution run --proposal-id`, and workspace dotenv merging. + +## Dependency and Compatibility + +- New dependencies: none. +- Backward compatibility notes: existing callers that set `--proposal-id` are unchanged; this fix aligns the authorization background caller with the supported CLI argument. + +## Design Decisions + +- Decision: pass `--proposal-id` in the background subprocess argument list and keep env propagation harmless. + - Rationale: `cmd_run` treats the CLI argument as the authoritative way to force a proposal and scopes the environment variable safely around execution. + - Alternatives considered: modify `cmd_run` to preserve a pre-existing env var when no CLI argument is passed. + - Why rejected: preserving ambient env would broaden the force semantics for all CLI callers and risk unexpected forced runs from inherited process environments. + +## Open Questions + +- [x] Is a docs update required? No, this restores the existing documented command behavior and does not change user-facing command syntax. +- [x] Is a database migration required? No. diff --git a/tasks/TASK-2026-067-authorized-evolution-proposal-run/PRD.md b/tasks/TASK-2026-067-authorized-evolution-proposal-run/PRD.md new file mode 100644 index 0000000..121fdf7 --- /dev/null +++ b/tasks/TASK-2026-067-authorized-evolution-proposal-run/PRD.md @@ -0,0 +1,37 @@ +# PRD + +## Background + +Recent desktop split work moved authorized capability evolution to a CLI subprocess. The CLI supports forcing a backlog proposal with `--proposal-id`, and `cmd_run` intentionally scopes the force environment variable around that explicit argument. The desktop authorization path did not pass the argument, so the authorized proposal id could be lost before `run_evolution` selected work. + +## Objective + +When a user starts evolution from the chat capability prompt, the immediately spawned background run must target the exact proposal id returned by `authorize-capability`. + +## Functional Requirements + +- FR-1: The authorization background process must include `--proposal-id` followed by the authorized proposal id. +- FR-2: Existing `.env` and child environment merging must continue to work. +- FR-3: Manual evolution triggering remains unchanged. + +## Non-Functional Requirements + +- Security: Do not bypass coordinator policy runtime or auto-approve dangerous evolution; only preserve target selection. +- Performance: No additional process or database work beyond the existing background run. +- Compatibility: Preserve the existing `skilllite evolution run --proposal-id` CLI contract and current desktop API shape. + +## Constraints + +- Technical: Keep the fix local to the desktop bridge unless runtime evidence shows the CLI contract itself is broken. +- Timeline: N/A for automation execution; complete within this investigation branch. + +## Success Metrics + +- Metric: authorization background run argument list. +- Baseline: `skilllite evolution run --json` with only `SKILLLITE_EVO_FORCE_PROPOSAL_ID`. +- Target: `skilllite evolution run --json --proposal-id `, with optional environment also harmless. + +## Rollout + +- Rollout plan: ship as a focused bug-fix PR. +- Rollback plan: revert the assistant bridge argument helper if unexpected subprocess behavior appears. diff --git a/tasks/TASK-2026-067-authorized-evolution-proposal-run/REVIEW.md b/tasks/TASK-2026-067-authorized-evolution-proposal-run/REVIEW.md new file mode 100644 index 0000000..6478376 --- /dev/null +++ b/tasks/TASK-2026-067-authorized-evolution-proposal-run/REVIEW.md @@ -0,0 +1,29 @@ +# Review Report + +## Scope Reviewed + +- Files/modules: desktop authorized evolution bridge, `skilllite evolution run` proposal forcing, task artifacts. +- Commits/changes: recent P2 desktop/CLI split path and this bug-fix branch. + +## Findings + +- Critical: None. +- Major: Active bug fixed. `skilllite_authorize_capability_evolution` returned a proposal id to the UI, then spawned a background run without `--proposal-id`. `cmd_run` removed `SKILLLITE_EVO_FORCE_PROPOSAL_ID` when no CLI proposal id was present, so the authorized backlog proposal was not forced. +- Minor: Assistant crate still emits pre-existing warnings during plain `cargo test` / `cargo clippy`; they are unrelated to this change. + +## Quality Gates + +- Architecture boundary checks: `pass` +- Security invariants: `pass` +- Required tests executed: `pass` +- Docs sync (EN/ZH): `pass` + +## Test Evidence + +- Commands run: `cargo fmt --check`; `cargo test --manifest-path crates/skilllite-assistant/src-tauri/Cargo.toml authorize_background_run_args_force_proposal`; `cargo test --manifest-path crates/skilllite-assistant/src-tauri/Cargo.toml`; `cargo clippy --manifest-path crates/skilllite-assistant/src-tauri/Cargo.toml --all-targets`; `cargo test -p skilllite-commands`; `cargo clippy --all-targets -- -D warnings`; `cargo test`; `python3 scripts/validate_tasks.py`. +- Key outputs: targeted assistant regression test: `1 passed`; full assistant tests: `51 passed`; `skilllite-commands`: `23 passed`; workspace clippy finished successfully with `-D warnings`; workspace test suite passed; task validation passed for 67 task directories. + +## Decision + +- Merge readiness: `ready` +- Follow-up actions: None for this fix. Existing assistant warnings can be handled separately. diff --git a/tasks/TASK-2026-067-authorized-evolution-proposal-run/STATUS.md b/tasks/TASK-2026-067-authorized-evolution-proposal-run/STATUS.md new file mode 100644 index 0000000..b168b8e --- /dev/null +++ b/tasks/TASK-2026-067-authorized-evolution-proposal-run/STATUS.md @@ -0,0 +1,21 @@ +# Status Journal + +## Timeline + +- 2026-06-04: + - Progress: Identified that desktop authorized capability evolution spawns `skilllite evolution run --json` without `--proposal-id`, while `cmd_run` clears the force env var when the CLI argument is absent. Implemented a minimal fix so the background run passes `--proposal-id ` and added `authorize_background_run_args_force_proposal`. + - Blockers: None. + - Next step: Done after validation. +- 2026-06-04: + - Progress: Validation passed: `cargo fmt --check`; targeted assistant regression test; full assistant tests; assistant clippy; `cargo test -p skilllite-commands`; workspace clippy with `-D warnings`; workspace `cargo test`; task validation. + - Blockers: None. + - Next step: PR ready. + +## Checkpoints + +- [x] PRD drafted before implementation (or `N/A` recorded) +- [x] Context drafted before implementation (or `N/A` recorded) +- [x] Implementation complete +- [x] Tests passed +- [x] Review complete +- [x] Board updated diff --git a/tasks/TASK-2026-067-authorized-evolution-proposal-run/TASK.md b/tasks/TASK-2026-067-authorized-evolution-proposal-run/TASK.md new file mode 100644 index 0000000..a891f09 --- /dev/null +++ b/tasks/TASK-2026-067-authorized-evolution-proposal-run/TASK.md @@ -0,0 +1,51 @@ +# TASK Card + +## Metadata + +- Task ID: `TASK-2026-067` +- Title: Fix authorized evolution proposal run binding +- Status: `done` +- Priority: `P1` +- Owner: `agent` +- Contributors: `automation` +- Created: `2026-06-04` +- Target milestone: recent critical bug investigation + +## Problem + +Desktop chat authorization for capability evolution enqueues a concrete backlog proposal and then starts a background `skilllite evolution run`. The background run only sets `SKILLLITE_EVO_FORCE_PROPOSAL_ID`, but `cmd_run` clears that environment variable whenever no `--proposal-id` CLI argument is present. As a result, the user-authorized proposal may remain queued while the background run sees no forced proposal and either does nothing or selects a different candidate. + +## Scope + +- In scope: bind the authorized background evolution run to the returned proposal id using the existing `--proposal-id` CLI contract. +- In scope: add a focused regression test for the background argument construction. +- Out of scope: changing evolution policy runtime decisions, backlog schema, or LLM synthesis behavior. + +## Acceptance Criteria + +- [x] Background runs started by `skilllite_authorize_capability_evolution` pass `--proposal-id `. +- [x] The forced proposal environment variable is no longer the only binding mechanism for this path. +- [x] Tests cover the argument contract and the affected crates still pass required checks. + +## Risks + +- Risk: argument construction diverges from manual trigger behavior again. + - Impact: authorized proposals can be skipped or unrelated proposals can execute. + - Mitigation: centralize the authorization background run args in a small helper with a regression test. + +## Validation Plan + +- Required tests: targeted Rust tests for the assistant bridge and workspace Rust tests. +- Commands run: `cargo fmt --check`; `cargo test --manifest-path crates/skilllite-assistant/src-tauri/Cargo.toml authorize_background_run_args_force_proposal`; `cargo test --manifest-path crates/skilllite-assistant/src-tauri/Cargo.toml`; `cargo clippy --manifest-path crates/skilllite-assistant/src-tauri/Cargo.toml --all-targets`; `cargo test -p skilllite-commands`; `cargo clippy --all-targets -- -D warnings`; `cargo test`; `python3 scripts/validate_tasks.py`. +- Manual checks: inspected the final `authorize.rs` command chain and confirmed the child receives `--proposal-id`. + +## Regression Scope + +- Areas likely affected: desktop chat "start evolution" action, desktop evolution CLI bridge, `skilllite evolution run` proposal forcing. +- Explicit non-goals: policy runtime thresholds, proposal recovery, queue selection, and UI copy. + +## Links + +- Source TODO section: N/A, triggered by automated recent-commit bug investigation. +- Related PRs/issues: recent P2 desktop/CLI split commits. +- Related docs: N/A, this restores documented CLI behavior without changing user-facing commands. diff --git a/tasks/board.md b/tasks/board.md index 43428f7..6380bea 100644 --- a/tasks/board.md +++ b/tasks/board.md @@ -1,6 +1,6 @@ # Task Board -Last updated: 2026-05-29 (TASK-2026-066 utf8 evolution log truncate done) +Last updated: 2026-06-04 (TASK-2026-067 authorized evolution proposal run done) ## In Progress @@ -17,6 +17,7 @@ Last updated: 2026-05-29 (TASK-2026-066 utf8 evolution log truncate done) ## Done +- `TASK-2026-067-authorized-evolution-proposal-run` - Status: `done` - Owner: `agent` - `TASK-2026-066-utf8-evolution-log-truncate` - Status: `done` - Owner: `agent` - `TASK-2026-064-env-keys-single-source` - Status: `done` - Owner: `agent` - `TASK-2026-063-extension-tool-metadata-dispatch` - Status: `done` - Owner: `agent`