huskies: merge 503_bug_depends_on_pointing_at_an_archived_story_is_silently_treated_as_deps_met_surprising_users

This commit is contained in:
dave
2026-04-09 18:27:25 +00:00
parent 8b2e068d3e
commit 41515e3b8f
6 changed files with 393 additions and 3 deletions
+47 -1
View File
@@ -7,7 +7,7 @@ use crate::http::workflow::{
create_spike_file, create_story_file, list_bug_files, list_refactor_files, load_pipeline_state,
load_upcoming_stories, update_story_in_file, validate_story_dirs,
};
use crate::io::story_metadata::{parse_front_matter, parse_unchecked_todos};
use crate::io::story_metadata::{check_archived_deps, check_archived_deps_from_list, parse_front_matter, parse_unchecked_todos};
use crate::slog_warn;
use crate::workflow::{TestCaseResult, TestStatus, evaluate_acceptance_with_coverage};
use serde_json::{Value, json};
@@ -40,6 +40,30 @@ pub(super) fn tool_create_story(args: &Value, ctx: &AppContext) -> Result<String
commit,
)?;
// Bug 503: warn at creation time if any depends_on points at an already-archived story.
// Archived = satisfied semantics: the dep will resolve immediately on the next promotion
// tick, which is surprising if the archived story was abandoned rather than cleanly done.
let archived_deps = depends_on
.as_deref()
.map(|deps| check_archived_deps_from_list(&root, deps))
.unwrap_or_default();
if !archived_deps.is_empty() {
slog_warn!(
"[create-story] Story '{story_id}' depends_on {archived_deps:?} which \
are already in 6_archived. The dep will be treated as satisfied on the \
next promotion tick. If these deps were abandoned (not cleanly completed), \
consider removing the depends_on or keeping the story in backlog manually."
);
return Ok(format!(
"Created story: {story_id}\n\n\
WARNING: depends_on {archived_deps:?} point at stories already in \
6_archived. These deps are treated as satisfied (archived = satisfied \
semantics), so this story may be auto-promoted from backlog immediately. \
If the archived deps were abandoned rather than completed, remove the \
depends_on or move the story back to backlog manually after promotion."
));
}
Ok(format!("Created story: {story_id}"))
}
@@ -320,6 +344,28 @@ pub(super) fn tool_update_story(args: &Value, ctx: &AppContext) -> Result<String
let root = ctx.state.get_project_root()?;
update_story_in_file(&root, story_id, user_story, description, front_matter_opt)?;
// Bug 503: warn if any depends_on in the (now updated) story points at an archived story.
let stage = crate::crdt_state::read_item(story_id)
.map(|i| i.stage)
.unwrap_or_else(|| "1_backlog".to_string());
let archived_deps = check_archived_deps(&root, &stage, story_id);
if !archived_deps.is_empty() {
slog_warn!(
"[update-story] Story '{story_id}' depends_on {archived_deps:?} which \
are already in 6_archived. The dep will be treated as satisfied on the \
next promotion tick. If these deps were abandoned (not cleanly completed), \
consider removing the depends_on or keeping the story in backlog manually."
);
return Ok(format!(
"Updated story '{story_id}'.\n\n\
WARNING: depends_on {archived_deps:?} point at stories already in \
6_archived. These deps are treated as satisfied (archived = satisfied \
semantics), so this story may be auto-promoted from backlog immediately. \
If the archived deps were abandoned rather than completed, remove the \
depends_on or move the story back to backlog manually after promotion."
));
}
Ok(format!("Updated story '{story_id}'."))
}