From b8c816592675a259139c3face7c0a4849b86cc5f Mon Sep 17 00:00:00 2001 From: Ruben Romero Montes Date: Wed, 27 May 2026 17:16:30 +0200 Subject: [PATCH 1/2] feat(implement-task): add description digest verification step Add Step 1.5 to verify description integrity by checking the SHA-256 digest posted by plan-feature against the current description content. Handles three scenarios: no digest (warn and proceed), matching digest (proceed silently), and mismatched digest (alert user and pause). Also adds REST API fallback for comment retrieval and three new eval assertions covering all digest verification scenarios. Implements TC-4286 Assisted-by: Claude Code --- evals/implement-task/evals.json | 28 ++++++++++- .../skills/implement-task/SKILL.md | 49 ++++++++++++++++++- 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/evals/implement-task/evals.json b/evals/implement-task/evals.json index 5e63d6bb..7f5afd8b 100644 --- a/evals/implement-task/evals.json +++ b/evals/implement-task/evals.json @@ -15,7 +15,8 @@ "The plan mentions using --trailer='Assisted-by: Claude Code' in the commit (constraint 2.3)", "The plan references creating a branch named TC-9201 or notes the branch naming convention (constraint 3.1), and references the Target Branch value from the task description", "The conventions analysis identifies at least 2 patterns from sibling code: error handling with Result and .context(), and the model/service/endpoints module structure", - "The plan extracts and references the Target Branch section from the task description, identifying 'main' as the target branch" + "The plan extracts and references the Target Branch section from the task description, identifying 'main' as the target branch", + "The plan mentions checking for a description digest comment (Step 1.5) and notes that when no digest is found, it proceeds with a warning rather than blocking execution (backward compatibility per shared/description-digest-protocol.md)" ] }, { @@ -73,6 +74,31 @@ "The planned commit message follows Conventional Commits format (type(scope): description) and references TC-9205 in the footer (constraint 2.1, 2.2)", "The plan extracts and references the Target Branch section from the task description, identifying TC-9005 as the target branch" ] + }, + { + "id": 6, + "prompt": "Implement task TC-9201. The task description is in task-standard.md, the target repository structure is in repo-backend.md, and the project CLAUDE.md is in claude-md-mock.md. The Jira issue has one comment posted by a previous plan-feature run with the body: '[sdlc-workflow] Description digest: sha256:a1b2c3d4e5f67890a1b2c3d4e5f67890a1b2c3d4e5f67890a1b2c3d4e5f67890'. Assume this digest MATCHES the SHA-256 hash of the current task description. The comment's created and updated timestamps are identical. Do NOT actually modify repository files or call external tools (Jira, git, Serena). Instead, write your response to outputs/digest-match.md describing how you would handle the description integrity verification in Step 1.5, and then write outputs/plan.md with the full implementation plan.", + "expected_output": "The response should describe verifying the description digest in Step 1.5: locating the digest comment by its marker string, comparing the stored hash with the computed hash of the current description, finding a match, and proceeding silently without any additional user prompt. The implementation plan should continue to Step 2 and beyond without interruption.", + "files": ["files/task-standard.md", "files/repo-backend.md", "files/claude-md-mock.md"], + "assertions": [ + "The response describes locating the digest comment using the marker string '[sdlc-workflow] Description digest:' from shared/description-digest-protocol.md", + "The response describes computing a SHA-256 hash of the current description and comparing it with the stored digest", + "The response confirms the digests match and states it will proceed silently without prompting the user — no additional latency for the happy path", + "The response does not alert the user or pause execution due to the digest check — it proceeds directly to subsequent steps" + ] + }, + { + "id": 7, + "prompt": "Implement task TC-9201. The task description is in task-standard.md, the target repository structure is in repo-backend.md, and the project CLAUDE.md is in claude-md-mock.md. The Jira issue has one comment posted by a previous plan-feature run with the body: '[sdlc-workflow] Description digest: sha256:0000000000000000000000000000000000000000000000000000000000000000'. Assume this digest does NOT match the SHA-256 hash of the current task description — the description was modified after plan-feature created it. The comment's created and updated timestamps are identical. Do NOT actually modify repository files or call external tools (Jira, git, Serena). Instead, write your response to outputs/digest-mismatch.md describing how you would handle the description integrity verification in Step 1.5.", + "expected_output": "The response should describe detecting a digest mismatch in Step 1.5: the stored hash does not match the computed hash of the current description. The skill should alert the user that the description was modified since plan-feature created the task, display the expected vs actual digest values, and pause execution — asking the user whether to proceed with the current description or stop to re-run plan-feature. The skill should NOT proceed to Step 2 or beyond without the user's explicit decision.", + "files": ["files/task-standard.md", "files/repo-backend.md", "files/claude-md-mock.md"], + "assertions": [ + "The response describes locating the digest comment using the marker string '[sdlc-workflow] Description digest:' from shared/description-digest-protocol.md", + "The response describes detecting a mismatch between the stored digest and the computed SHA-256 hash of the current description", + "The response alerts the user that the description was modified after plan-feature created the task and displays the expected vs actual digest values", + "The response offers the user a choice: (1) proceed with the current description, or (2) stop so they can re-run plan-feature", + "The response stops execution and does not proceed to Step 2 or implementation planning until the user responds — following the same pause-and-ask pattern as the incomplete description handling" + ] } ] } diff --git a/plugins/sdlc-workflow/skills/implement-task/SKILL.md b/plugins/sdlc-workflow/skills/implement-task/SKILL.md index c2a07444..54254fcb 100644 --- a/plugins/sdlc-workflow/skills/implement-task/SKILL.md +++ b/plugins/sdlc-workflow/skills/implement-task/SKILL.md @@ -25,7 +25,7 @@ If any of these sections are missing or incomplete, inform the user: ## Step 0.5 – JIRA Access Initialization -Before attempting any JIRA operations (Steps 1, 2, 3, 11), determine the access method. +Before attempting any JIRA operations (Steps 1, 1.5, 2, 3, 11), determine the access method. **For every JIRA operation:** 1. **Attempt MCP first** (preferred method) @@ -49,6 +49,7 @@ Before attempting any JIRA operations (Steps 1, 2, 3, 11), determine the access **REST API equivalents for this skill's operations:** - `jira.get_issue(id)` → `python3 scripts/jira-client.py get_issue --fields "*all"` +- `jira.get_issue_comments(id)` → `python3 scripts/jira-client.py get_comments ` - `jira.user_info()` → `python3 scripts/jira-client.py get_user_info` - `jira.edit_issue(id, assignee=accountId)` → `python3 scripts/jira-client.py update_issue --fields-json '{"assignee": {"id": ""}}'` - `jira.transition_issue(id, status)` → First get transitions with `get_transitions `, find ID for target status, then `transition_issue --transition-id ` @@ -177,6 +178,52 @@ section in CLAUDE.md (the field is listed as `GitHub Issue custom field: /#` for use in Step 10. - **If not configured or the field is empty**, skip silently — this is optional. +## Step 1.5 – Verify Description Integrity + +After fetching the task, verify that the description has not been modified since +plan-feature created it. This uses the digest protocol defined in +`shared/description-digest-protocol.md`. + +1. **Retrieve issue comments**: fetch all comments on the Jira issue: + + ``` + jira.get_issue_comments() + ``` + +2. **Locate the digest comment**: search for a comment whose body starts with the + marker string `[sdlc-workflow] Description digest:`. This marker is defined in + `shared/description-digest-protocol.md`. + +3. **If no digest comment found**: log a warning and proceed normally — do not block + execution: + + > "No description digest found — skipping integrity check. This task may have + > been created before digest tracking was introduced." + +4. **If digest comment found**: + a. **Check for comment editing**: if the comment's `created` and `updated` + timestamps are available, compare them. If `updated` is later than `created`, + warn: "Digest comment was edited after initial posting — integrity cannot be + fully guaranteed." Proceed with digest comparison regardless. If timestamps + are not available in the API response, skip this check silently. + b. **Extract the stored digest**: parse the `sha256:` value from the + comment body. + c. **Compute the current digest**: hash the current description field text using + SHA-256, following the same normalization as the protocol (strip + leading/trailing whitespace before hashing). Output a lowercase 64-character + hexadecimal digest. + d. **Compare digests**: + - **Match**: proceed silently — no additional user prompt, no added latency. + - **Mismatch**: alert the user that the task description was modified after + plan-feature created it. Display the expected digest (from the comment) and + the actual digest (computed from the current description). Ask the user + whether to: + 1. **Proceed** with the current description as-is + 2. **Stop** so they can re-run plan-feature to regenerate tasks + + **Stop execution immediately** — do not proceed with any subsequent steps + until the user responds. + ## Step 2 – Verify Dependencies If the task has Dependencies, check each one: From d3e603046f261ef16cea7330dafdf34894e6a7d1 Mon Sep 17 00:00:00 2001 From: Ruben Romero Montes Date: Wed, 27 May 2026 21:23:05 +0200 Subject: [PATCH 2/2] fix(implement-task): disambiguate multiple digest comment handling Specify that when multiple digest comments match the marker string, the consumer selects the most recent one by created timestamp. Also document this edge case in the shared protocol. Implements TC-4566 Assisted-by: Claude Code --- .../shared/description-digest-protocol.md | 13 +++++++++++-- .../sdlc-workflow/skills/implement-task/SKILL.md | 5 +++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/plugins/sdlc-workflow/shared/description-digest-protocol.md b/plugins/sdlc-workflow/shared/description-digest-protocol.md index 799d1b76..e2eaeab6 100644 --- a/plugins/sdlc-workflow/shared/description-digest-protocol.md +++ b/plugins/sdlc-workflow/shared/description-digest-protocol.md @@ -91,8 +91,17 @@ comment. ## Consumer Verification -The consumer (implement-task) retrieves issue comments and searches for one whose -body starts with the marker string `[sdlc-workflow] Description digest:`. If found: +The consumer (implement-task) retrieves issue comments and searches for those whose +body starts with the marker string `[sdlc-workflow] Description digest:`. + +### Multiple Digest Comments + +If multiple comments match the marker string (e.g., from plan-feature re-runs or +manual postings), the consumer must select the most recent one by `created` +timestamp. This ensures deterministic behavior without rejecting valid re-planning +scenarios. + +If found: 1. Extract the `sha256:` value 2. Compute SHA-256 of the current description field (same normalization as producer) diff --git a/plugins/sdlc-workflow/skills/implement-task/SKILL.md b/plugins/sdlc-workflow/skills/implement-task/SKILL.md index 54254fcb..b79bbfbb 100644 --- a/plugins/sdlc-workflow/skills/implement-task/SKILL.md +++ b/plugins/sdlc-workflow/skills/implement-task/SKILL.md @@ -190,9 +190,10 @@ plan-feature created it. This uses the digest protocol defined in jira.get_issue_comments() ``` -2. **Locate the digest comment**: search for a comment whose body starts with the +2. **Locate the digest comment**: search for all comments whose body starts with the marker string `[sdlc-workflow] Description digest:`. This marker is defined in - `shared/description-digest-protocol.md`. + `shared/description-digest-protocol.md`. If multiple comments match (e.g., from + plan-feature re-runs), select the most recent one by `created` timestamp. 3. **If no digest comment found**: log a warning and proceed normally — do not block execution: