fix(1102): require non-empty origin.id on create_* MCP tools
bug 1102 was created today with origin={kind:user, id:""} because
build_origin silently defaulted id to empty when the caller didn't pass
one — we couldn't tell who filed it. Bug 1088's origin field is useless
as audit if every caller can omit themselves.
Changes:
- build_origin (server/src/http/mcp/story_tools/mod.rs) now returns
Result<String, String> and rejects missing/empty/whitespace-only id
with an instructional error pointing at bug 1102 / story 1104.
- 5 create_* tool handlers (bug, spike, refactor, epic, story) now
resolve origin BEFORE create_*_file so an attribution-less call
leaves no half-state behind.
- 5 tool input schemas now advertise origin as a required object via
a shared origin_schema() helper. The schema description gives every
caller (coder agent, chat bot, user, system) a concrete example so
the LLM populates the field correctly on first sight.
- Test fixtures pass origin = {kind:"test", id:"test-suite"}.
Story 1104 (signed actions) is the longer-term replacement; this is the
quick attribution win agreed for master ahead of that design work.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,10 @@ pub(crate) fn tool_create_bug(args: &Value, ctx: &AppContext) -> Result<String,
|
||||
let acs = req.acceptance_criteria_strings();
|
||||
let depends_on = req.depends_on_ids();
|
||||
|
||||
// Bug 1102: resolve and validate origin BEFORE creating the bug file so a
|
||||
// missing-attribution call leaves no half-state behind.
|
||||
let origin = super::build_origin(args)?;
|
||||
|
||||
let root = ctx.state.get_project_root()?;
|
||||
let bug_id = create_bug_file(
|
||||
&root,
|
||||
@@ -38,7 +42,7 @@ pub(crate) fn tool_create_bug(args: &Value, ctx: &AppContext) -> Result<String,
|
||||
depends_on.as_deref(),
|
||||
)?;
|
||||
|
||||
crate::crdt_state::set_origin(&bug_id, &super::build_origin(args));
|
||||
crate::crdt_state::set_origin(&bug_id, &origin);
|
||||
|
||||
let _ = ctx
|
||||
.watcher_tx
|
||||
@@ -243,7 +247,8 @@ mod tests {
|
||||
"steps_to_reproduce": "1. Open app\n2. Click login",
|
||||
"actual_result": "500 error",
|
||||
"expected_result": "Successful login",
|
||||
"acceptance_criteria": ["Login succeeds without error"]
|
||||
"acceptance_criteria": ["Login succeeds without error"],
|
||||
"origin": {"kind": "test", "id": "test-suite"}
|
||||
}),
|
||||
&ctx,
|
||||
)
|
||||
@@ -364,7 +369,8 @@ mod tests {
|
||||
"steps_to_reproduce": "s",
|
||||
"actual_result": "a",
|
||||
"expected_result": "e",
|
||||
"acceptance_criteria": ["Bug is fixed"]
|
||||
"acceptance_criteria": ["Bug is fixed"],
|
||||
"origin": {"kind": "test", "id": "test-suite"}
|
||||
}),
|
||||
&ctx,
|
||||
);
|
||||
@@ -406,7 +412,8 @@ mod tests {
|
||||
"steps_to_reproduce": "s",
|
||||
"actual_result": "a",
|
||||
"expected_result": "e",
|
||||
"acceptance_criteria": ["TODO", "Real AC"]
|
||||
"acceptance_criteria": ["TODO", "Real AC"],
|
||||
"origin": {"kind": "test", "id": "test-suite"}
|
||||
}),
|
||||
&ctx,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user