-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Describe the Bug
When running SpecFact backlog refinement writeback against Azure DevOps (specfact backlog refine ado ... --import-from-tmp --write), SpecFact may attempt to PATCH the field System.AcceptanceCriteria even when the target ADO project’s process template does not contain that field. Azure DevOps rejects the request with HTTP 400:
TF51535: Cannot find field System.AcceptanceCriteria.
This is particularly likely in organizations using a customized/non-standard ADO process template where acceptance criteria exists under a different reference name (e.g. Microsoft.VSTS.Common.AcceptanceCriteria) or is not present at all.
A second UX issue: even with --debug, the initial logs did not include the ADO response body and did not clearly identify which JSON Patch operation (which field) caused the failure. We had to locally instrument specfact_cli/adapters/ado.py to make the root cause visible.
To Reproduce
Steps to reproduce the behavior:
# 1) Export an item to a known file (Windows-friendly path)
specfact backlog refine ado \
--ado-org myorg \
--ado-project myproject \
--state "New" \
--iteration "myproject\2026\Sprint 2026-02" \
--assignee "Dominikus Nold" \
--limit 1 \
--export-to-tmp \
--tmp-file "C:\path\to\specfact-backlog-refine-YYYYMMDD-HHMM.md"
# 2) Optionally refine/edit the markdown content (description, acceptance criteria, metrics)
# 3) Import + write back (this triggers the ADO PATCH)
specfact --debug backlog refine ado \
--ado-org myorg \
--ado-project myproject \
--state "New" \
--iteration "myproject\2026\Sprint 2026-02" \
--assignee "Dominikus Nold" \
--limit 1 \
--import-from-tmp \
--tmp-file "C:\path\to\specfact-backlog-refine-YYYYMMDD-HHMM.md" \
--writeImportant prerequisite for reproducing the failure: the ADO project must not have the field System.AcceptanceCriteria in its process template. In our case, ADO returned TF51535 complaining that this field cannot be found.
Expected Behavior
- SpecFact should not attempt to update ADO fields that do not exist in the target project/process template.
- If a mapped ADO field does not exist, SpecFact should:
- fall back to an available equivalent reference name (where possible), or
- skip that field and warn clearly, or
- fail fast with a clear, actionable error message.
- When writeback fails,
--debugshould log the ADO response body and the JSON Patch operations/paths so users can quickly identify the failing field mapping.
Actual Behavior
- Writeback fails with HTTP 400 and ADO error
TF51535: Cannot find field System.AcceptanceCriteria. - Without additional instrumentation, the debug log did not make it obvious which patch operation/field caused the failure.
Environment
- OS: Windows (PowerShell)
- Python Version: (fill in; e.g.
3.11.x) - SpecFact CLI Version:
0.26.13 - Installation Method: pip into a virtualenv (local venv)
Command Output
Include the full command output (with --verbose if applicable):
400 Client Error: Bad Request for url: https://dev.azure.com/<org>/<project>/_apis/wit/workitems/<id>?api-version=7.1
TF51535: Cannot find field System.AcceptanceCriteria.(Exact URL/work item ID will differ per environment.)
Codebase Context (for brownfield issues)
Not applicable (this occurs in the Azure DevOps adapter writeback path).
Additional Context
Root cause / why this is confusing
Many ADO organizations use customized process templates. In such templates, some “common” fields (by reference name) may be missing. SpecFact’s mapping/preference behavior can result in attempting to write to a System.* field that isn’t present, even when a Microsoft.VSTS.* alternative exists.
In our case, the writeback patch included /fields/System.AcceptanceCriteria, which caused the 400.
Workaround that resolved the issue
Add a custom mapping in the repo (or user config) to prevent SpecFact from attempting to write to System.AcceptanceCriteria when it doesn’t exist.
Example approach used successfully:
- In ado_custom.yaml, remap:
System.AcceptanceCriteria→ a “sink”/ignored canonical key (so it won’t be selected for writeback)- ensure acceptance criteria maps to
Microsoft.VSTS.Common.AcceptanceCriteriainstead - similarly, override story points field selection if your process template differs
After applying this mapping, running the same refine/writeback without any temporary “mapping hack” succeeded, implying SpecFact correctly loaded the repo-level mapping.
Local debug modifications we made (for maintainers / proposed improvement)
To diagnose the failure, we locally modified specfact_cli/adapters/ado.py (installed package in our venv) to log more details when the ADO PATCH fails.
What we added (high-level):
- On HTTP error during the PATCH request, log:
response.status_code- a safe/truncated portion of
response.text(ADO error body, which contains the missing field message) - the JSON Patch operation paths being attempted (e.g.
replace /fields/System.AcceptanceCriteria)
This immediately revealed the root cause and would significantly reduce time-to-diagnosis for others.
Suggested product improvements
- Pre-flight field existence validation: Query ADO field metadata and validate that all
/fields/<referenceName>exist before PATCHing. - Mapping fallback behavior: If multiple candidate ADO reference names exist for a canonical field, prefer the one that exists in the current project.
- Better error surface by default: When ADO returns 400, print the ADO response message and list the JSON patch paths/fields being written (at least under
--debug). - Windows temp directory handling: Ensure default temp output uses a platform-correct temp directory (or auto-creates the directory), rather than assuming
/tmpexists.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status