Skip to content

[Bug] Provide better error logging on backlog refinement issues with ADO #162

@djm81

Description

@djm81

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" \
  --write

Important 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, --debug should 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.AcceptanceCriteria instead
    • 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

  1. Pre-flight field existence validation: Query ADO field metadata and validate that all /fields/<referenceName> exist before PATCHing.
  2. Mapping fallback behavior: If multiple candidate ADO reference names exist for a canonical field, prefer the one that exists in the current project.
  3. 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).
  4. Windows temp directory handling: Ensure default temp output uses a platform-correct temp directory (or auto-creates the directory), rather than assuming /tmp exists.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions