feat: solo-workflow-tighten — tighten solo dev loop #7
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/solo-workflow-tighten"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Test plan
Code review
Found 3 issues:
lazy_evictalways ignores user session config —lazy_evictpassesassay_dir.join("config.toml")toconfig::load(), butload()expects a project root and internally appends.assay/config.toml. The effective lookup becomes.assay/config.toml/.assay/config.toml, which never exists. TheErris silently swallowed and eviction always runs withSessionsConfig::default(), ignoring any configuredmax_count/max_age_days.fn lazy_evict(assay_dir: &Path) {let config_path = assay_dir.join("config.toml");let sessions_config = if config_path.is_file() {if let Ok(config) = crate::config::load(&config_path) {config.sessions.unwrap_or_default()} else {assay_types::SessionsConfig::default()}} else {assay_types::SessionsConfig::default()};Fix: pass the project root (parent of
assay_dir) toconfig::load, or build the path manually like other call sites.AdvanceChunk.next_chunkpoints to the current chunk, not the next one —spec_nameis set fromchunk.slug(the active chunk). When gates pass and remaining chunks exist,NextAction::AdvanceChunk { next_chunk: spec_name }returns the chunk that just completed rather than the next pending chunk. Any consumer acting on this will re-run the finished chunk. Same bug in theVerifiedstatus branch.let spec_name = chunk.slug.clone();let specs_dir = assay_dir.join("specs");// Try to load the spec entry to check statuslet status = match spec::load_spec_entry(&spec_name, &specs_dir) {Ok(spec::SpecEntry::Directory { gates, .. }) => spec::effective_status(&gates),Ok(spec::SpecEntry::Legacy { .. }) => GateSpecStatus::Draft,Err(_) => GateSpecStatus::Draft,};// Check gate history for this speclet run_ids = crate::history::list(assay_dir, &spec_name).unwrap_or_default();if let Some(latest_run_id) = run_ids.last() {// We have gate history — check the latest resultif let Ok(record) = crate::history::load(assay_dir, &spec_name, latest_run_id) {if record.summary.enforcement.required_failed > 0 {// Gates failedlet failed: Vec<String> = record.summary.results.iter().filter(|r| {r.enforcement == assay_types::Enforcement::Required&& r.result.as_ref().is_some_and(|g| !g.passed)}).map(|r| r.criterion_name.clone()).collect();return Ok(NextAction::FixAndRecheck {spec_name,failed_criteria: failed,});}// Gates passed — check if there are more chunkslet remaining = milestone.chunks.iter().filter(|c| !milestone.completed_chunks.contains(&c.slug) && c.slug != spec_name).count();if remaining > 0 {// More chunks remain after currentreturn Ok(NextAction::AdvanceChunk {milestone_slug: milestone.slug.clone(),next_chunk: spec_name,});evaluate_routed"auto" mode for AgentReport is identical to "manual" — Both branches skip the criterion and pushCriterionResult { result: None }. Required AgentReport criteria appear as "skipped" rather than pass/fail, meaning gates can appear to pass when agent criteria were never evaluated. The two branches (lines 317-335) are identical dead code.Some(CriterionKind::AgentReport) => {if agent_eval_mode == "manual" {// Skip — user handles via gate_report flowskipped += 1;results.push(CriterionResult {criterion_name: gc.name.clone(),result: None,enforcement,source: None,});} else {// Auto mode: skip in this function (evaluator subprocess// is async and handled by the MCP layer's gate_evaluate)skipped += 1;results.push(CriterionResult {criterion_name: gc.name.clone(),result: None,enforcement,source: None,});}}🤖 Generated with Claude Code
- If this code review was useful, please react with 👍. Otherwise, react with 👎.