specfact-cli 0.35.0__tar.gz → 0.36.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (385) hide show
  1. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/.gitignore +6 -0
  2. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/PKG-INFO +5 -45
  3. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/README.md +4 -44
  4. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/pyproject.toml +1 -1
  5. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/__init__.py +1 -1
  6. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/__init__.py +1 -1
  7. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/adapters/ado.py +147 -19
  8. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/adapters/backlog_base.py +71 -0
  9. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/adapters/github.py +263 -12
  10. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/backlog/filters.py +2 -0
  11. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/backlog/mappers/github_mapper.py +47 -20
  12. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/analyze/module-package.yaml +1 -1
  13. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/auth/module-package.yaml +1 -1
  14. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/auth/src/commands.py +2 -2
  15. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/backlog/module-package.yaml +1 -1
  16. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/backlog/src/commands.py +708 -8
  17. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/contract/module-package.yaml +1 -1
  18. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/drift/module-package.yaml +1 -1
  19. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/enforce/module-package.yaml +1 -1
  20. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/generate/module-package.yaml +1 -1
  21. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/import_cmd/module-package.yaml +1 -1
  22. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/init/module-package.yaml +1 -1
  23. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/migrate/module-package.yaml +1 -1
  24. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/module_registry/module-package.yaml +1 -1
  25. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/patch_mode/module-package.yaml +1 -1
  26. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/plan/module-package.yaml +1 -1
  27. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/policy_engine/module-package.yaml +1 -1
  28. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/project/module-package.yaml +1 -1
  29. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/repro/module-package.yaml +1 -1
  30. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/sdd/module-package.yaml +1 -1
  31. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/spec/module-package.yaml +1 -1
  32. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/sync/module-package.yaml +1 -1
  33. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/upgrade/module-package.yaml +1 -1
  34. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/validate/module-package.yaml +1 -1
  35. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/registry/module_packages.py +2 -1
  36. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/LICENSE +0 -0
  37. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/mappings/node-async.yaml +0 -0
  38. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/mappings/python-async.yaml +0 -0
  39. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/mappings/speckit-default.yaml +0 -0
  40. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/prompts/shared/cli-enforcement.md +0 -0
  41. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/prompts/specfact.01-import.md +0 -0
  42. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/prompts/specfact.02-plan.md +0 -0
  43. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/prompts/specfact.03-review.md +0 -0
  44. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/prompts/specfact.04-sdd.md +0 -0
  45. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/prompts/specfact.05-enforce.md +0 -0
  46. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/prompts/specfact.06-sync.md +0 -0
  47. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/prompts/specfact.07-contracts.md +0 -0
  48. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/prompts/specfact.backlog-daily.md +0 -0
  49. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/prompts/specfact.backlog-refine.md +0 -0
  50. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/prompts/specfact.compare.md +0 -0
  51. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/prompts/specfact.sync-backlog.md +0 -0
  52. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/prompts/specfact.validate.md +0 -0
  53. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/schemas/deviation.schema.json +0 -0
  54. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/schemas/plan.schema.json +0 -0
  55. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/schemas/protocol.schema.json +0 -0
  56. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/backlog/defaults/defect_v1.yaml +0 -0
  57. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/backlog/defaults/enabler_v1.yaml +0 -0
  58. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/backlog/defaults/spike_v1.yaml +0 -0
  59. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/backlog/defaults/user_story_v1.yaml +0 -0
  60. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/backlog/field_mappings/ado_agile.yaml +0 -0
  61. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/backlog/field_mappings/ado_default.yaml +0 -0
  62. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/backlog/field_mappings/ado_kanban.yaml +0 -0
  63. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/backlog/field_mappings/ado_safe.yaml +0 -0
  64. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/backlog/field_mappings/ado_scrum.yaml +0 -0
  65. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/backlog/frameworks/safe/safe_feature_v1.yaml +0 -0
  66. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/backlog/frameworks/scrum/user_story_v1.yaml +0 -0
  67. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/backlog/personas/developer/developer_task_v1.yaml +0 -0
  68. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/backlog/personas/product-owner/user_story_v1.yaml +0 -0
  69. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/backlog/providers/ado/work_item_v1.yaml +0 -0
  70. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/github-action.yml.j2 +0 -0
  71. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/persona/architect.md.j2 +0 -0
  72. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/persona/developer.md.j2 +0 -0
  73. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/persona/product-owner.md.j2 +0 -0
  74. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/plan.bundle.yaml.j2 +0 -0
  75. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/policies/kanban.yaml +0 -0
  76. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/policies/mixed.yaml +0 -0
  77. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/policies/safe.yaml +0 -0
  78. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/policies/scrum.yaml +0 -0
  79. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/pr-template.md.j2 +0 -0
  80. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/protocol.yaml.j2 +0 -0
  81. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/resources/templates/telemetry.yaml.example +0 -0
  82. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/__main__.py +0 -0
  83. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/adapters/__init__.py +0 -0
  84. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/adapters/base.py +0 -0
  85. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/adapters/openspec.py +0 -0
  86. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/adapters/openspec_parser.py +0 -0
  87. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/adapters/registry.py +0 -0
  88. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/adapters/speckit.py +0 -0
  89. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/agents/__init__.py +0 -0
  90. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/agents/analyze_agent.py +0 -0
  91. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/agents/base.py +0 -0
  92. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/agents/plan_agent.py +0 -0
  93. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/agents/registry.py +0 -0
  94. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/agents/sync_agent.py +0 -0
  95. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/analyzers/__init__.py +0 -0
  96. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/analyzers/ambiguity_scanner.py +0 -0
  97. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/analyzers/code_analyzer.py +0 -0
  98. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/analyzers/constitution_evidence_extractor.py +0 -0
  99. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/analyzers/contract_extractor.py +0 -0
  100. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/analyzers/control_flow_analyzer.py +0 -0
  101. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/analyzers/graph_analyzer.py +0 -0
  102. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/analyzers/relationship_mapper.py +0 -0
  103. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/analyzers/requirement_extractor.py +0 -0
  104. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/analyzers/test_pattern_extractor.py +0 -0
  105. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/backlog/__init__.py +0 -0
  106. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/backlog/adapters/__init__.py +0 -0
  107. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/backlog/adapters/base.py +0 -0
  108. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/backlog/adapters/local_yaml_adapter.py +0 -0
  109. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/backlog/ai_refiner.py +0 -0
  110. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/backlog/converter.py +0 -0
  111. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/backlog/format_detector.py +0 -0
  112. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/backlog/formats/__init__.py +0 -0
  113. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/backlog/formats/base.py +0 -0
  114. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/backlog/formats/markdown_format.py +0 -0
  115. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/backlog/formats/structured_format.py +0 -0
  116. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/backlog/mappers/__init__.py +0 -0
  117. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/backlog/mappers/ado_mapper.py +0 -0
  118. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/backlog/mappers/base.py +0 -0
  119. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/backlog/mappers/template_config.py +0 -0
  120. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/backlog/template_detector.py +0 -0
  121. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/cli.py +0 -0
  122. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/commands/__init__.py +0 -0
  123. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/commands/analyze.py +0 -0
  124. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/commands/auth.py +0 -0
  125. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/commands/backlog_commands.py +0 -0
  126. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/commands/contract_cmd.py +0 -0
  127. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/commands/drift.py +0 -0
  128. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/commands/enforce.py +0 -0
  129. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/commands/generate.py +0 -0
  130. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/commands/import_cmd.py +0 -0
  131. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/commands/init.py +0 -0
  132. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/commands/migrate.py +0 -0
  133. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/commands/plan.py +0 -0
  134. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/commands/project_cmd.py +0 -0
  135. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/commands/repro.py +0 -0
  136. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/commands/sdd.py +0 -0
  137. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/commands/spec.py +0 -0
  138. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/commands/sync.py +0 -0
  139. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/commands/update.py +0 -0
  140. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/commands/validate.py +0 -0
  141. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/common/__init__.py +0 -0
  142. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/common/logger_setup.py +0 -0
  143. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/common/logging_utils.py +0 -0
  144. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/common/text_utils.py +0 -0
  145. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/common/utils.py +0 -0
  146. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/comparators/__init__.py +0 -0
  147. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/comparators/plan_comparator.py +0 -0
  148. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/contracts/__init__.py +0 -0
  149. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/contracts/crosshair_props.py +0 -0
  150. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/contracts/module_interface.py +0 -0
  151. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/enrichers/constitution_enricher.py +0 -0
  152. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/enrichers/plan_enricher.py +0 -0
  153. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/generators/__init__.py +0 -0
  154. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/generators/contract_generator.py +0 -0
  155. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/generators/openapi_extractor.py +0 -0
  156. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/generators/persona_exporter.py +0 -0
  157. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/generators/plan_generator.py +0 -0
  158. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/generators/protocol_generator.py +0 -0
  159. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/generators/report_generator.py +0 -0
  160. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/generators/task_generator.py +0 -0
  161. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/generators/test_to_openapi.py +0 -0
  162. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/generators/workflow_generator.py +0 -0
  163. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/importers/__init__.py +0 -0
  164. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/importers/speckit_converter.py +0 -0
  165. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/importers/speckit_scanner.py +0 -0
  166. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/integrations/__init__.py +0 -0
  167. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/integrations/specmatic.py +0 -0
  168. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/merge/__init__.py +0 -0
  169. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/merge/resolver.py +0 -0
  170. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/migrations/__init__.py +0 -0
  171. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/migrations/plan_migrator.py +0 -0
  172. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/models/__init__.py +0 -0
  173. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/models/backlog_item.py +0 -0
  174. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/models/bridge.py +0 -0
  175. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/models/capabilities.py +0 -0
  176. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/models/change.py +0 -0
  177. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/models/contract.py +0 -0
  178. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/models/deviation.py +0 -0
  179. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/models/dor_config.py +0 -0
  180. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/models/enforcement.py +0 -0
  181. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/models/module_package.py +0 -0
  182. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/models/persona_template.py +0 -0
  183. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/models/plan.py +0 -0
  184. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/models/project.py +0 -0
  185. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/models/protocol.py +0 -0
  186. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/models/quality.py +0 -0
  187. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/models/sdd.py +0 -0
  188. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/models/source_tracking.py +0 -0
  189. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/models/task.py +0 -0
  190. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/models/validation.py +0 -0
  191. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modes/__init__.py +0 -0
  192. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modes/detector.py +0 -0
  193. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modes/router.py +0 -0
  194. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/__init__.py +0 -0
  195. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/analyze/src/__init__.py +0 -0
  196. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/analyze/src/app.py +0 -0
  197. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/analyze/src/commands.py +0 -0
  198. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/auth/src/__init__.py +0 -0
  199. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/auth/src/app.py +0 -0
  200. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/backlog/src/__init__.py +0 -0
  201. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/backlog/src/adapters/__init__.py +0 -0
  202. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/backlog/src/adapters/ado.py +0 -0
  203. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/backlog/src/adapters/base.py +0 -0
  204. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/backlog/src/adapters/github.py +0 -0
  205. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/backlog/src/adapters/jira.py +0 -0
  206. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/backlog/src/adapters/linear.py +0 -0
  207. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/backlog/src/app.py +0 -0
  208. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/contract/src/__init__.py +0 -0
  209. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/contract/src/app.py +0 -0
  210. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/contract/src/commands.py +0 -0
  211. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/drift/src/__init__.py +0 -0
  212. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/drift/src/app.py +0 -0
  213. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/drift/src/commands.py +0 -0
  214. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/enforce/src/__init__.py +0 -0
  215. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/enforce/src/app.py +0 -0
  216. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/enforce/src/commands.py +0 -0
  217. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/generate/src/__init__.py +0 -0
  218. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/generate/src/app.py +0 -0
  219. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/generate/src/commands.py +0 -0
  220. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/import_cmd/src/__init__.py +0 -0
  221. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/import_cmd/src/app.py +0 -0
  222. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/import_cmd/src/commands.py +0 -0
  223. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/init/src/__init__.py +0 -0
  224. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/init/src/app.py +0 -0
  225. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/init/src/commands.py +0 -0
  226. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/migrate/src/__init__.py +0 -0
  227. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/migrate/src/app.py +0 -0
  228. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/migrate/src/commands.py +0 -0
  229. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/module_io_shim.py +0 -0
  230. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/module_registry/src/__init__.py +0 -0
  231. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/module_registry/src/app.py +0 -0
  232. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/module_registry/src/commands.py +0 -0
  233. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/patch_mode/src/app.py +0 -0
  234. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/patch_mode/src/commands.py +0 -0
  235. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/patch_mode/src/patch_mode/__init__.py +0 -0
  236. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/patch_mode/src/patch_mode/commands/__init__.py +0 -0
  237. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/patch_mode/src/patch_mode/commands/apply.py +0 -0
  238. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/patch_mode/src/patch_mode/pipeline/__init__.py +0 -0
  239. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/patch_mode/src/patch_mode/pipeline/applier.py +0 -0
  240. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/patch_mode/src/patch_mode/pipeline/generator.py +0 -0
  241. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/patch_mode/src/patch_mode/pipeline/idempotency.py +0 -0
  242. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/plan/src/__init__.py +0 -0
  243. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/plan/src/app.py +0 -0
  244. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/plan/src/commands.py +0 -0
  245. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/policy_engine/src/app.py +0 -0
  246. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/policy_engine/src/commands.py +0 -0
  247. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/policy_engine/src/policy_engine/__init__.py +0 -0
  248. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/policy_engine/src/policy_engine/config/__init__.py +0 -0
  249. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/policy_engine/src/policy_engine/config/policy_config.py +0 -0
  250. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/policy_engine/src/policy_engine/config/templates.py +0 -0
  251. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/policy_engine/src/policy_engine/engine/__init__.py +0 -0
  252. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/policy_engine/src/policy_engine/engine/suggester.py +0 -0
  253. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/policy_engine/src/policy_engine/engine/validator.py +0 -0
  254. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/policy_engine/src/policy_engine/main.py +0 -0
  255. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/policy_engine/src/policy_engine/models/__init__.py +0 -0
  256. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/policy_engine/src/policy_engine/models/policy_result.py +0 -0
  257. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/policy_engine/src/policy_engine/policies/__init__.py +0 -0
  258. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/policy_engine/src/policy_engine/policies/kanban.py +0 -0
  259. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/policy_engine/src/policy_engine/policies/safe.py +0 -0
  260. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/policy_engine/src/policy_engine/policies/scrum.py +0 -0
  261. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/policy_engine/src/policy_engine/registry/__init__.py +0 -0
  262. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/policy_engine/src/policy_engine/registry/policy_registry.py +0 -0
  263. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/project/src/__init__.py +0 -0
  264. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/project/src/app.py +0 -0
  265. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/project/src/commands.py +0 -0
  266. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/repro/src/__init__.py +0 -0
  267. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/repro/src/app.py +0 -0
  268. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/repro/src/commands.py +0 -0
  269. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/sdd/src/__init__.py +0 -0
  270. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/sdd/src/app.py +0 -0
  271. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/sdd/src/commands.py +0 -0
  272. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/spec/src/__init__.py +0 -0
  273. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/spec/src/app.py +0 -0
  274. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/spec/src/commands.py +0 -0
  275. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/sync/src/__init__.py +0 -0
  276. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/sync/src/app.py +0 -0
  277. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/sync/src/commands.py +0 -0
  278. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/upgrade/src/__init__.py +0 -0
  279. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/upgrade/src/app.py +0 -0
  280. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/upgrade/src/commands.py +0 -0
  281. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/validate/src/__init__.py +0 -0
  282. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/validate/src/app.py +0 -0
  283. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/modules/validate/src/commands.py +0 -0
  284. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/parsers/__init__.py +0 -0
  285. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/parsers/persona_importer.py +0 -0
  286. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/registry/__init__.py +0 -0
  287. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/registry/bootstrap.py +0 -0
  288. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/registry/bridge_registry.py +0 -0
  289. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/registry/crypto_validator.py +0 -0
  290. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/registry/extension_registry.py +0 -0
  291. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/registry/help_cache.py +0 -0
  292. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/registry/marketplace_client.py +0 -0
  293. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/registry/metadata.py +0 -0
  294. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/registry/module_discovery.py +0 -0
  295. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/registry/module_installer.py +0 -0
  296. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/registry/module_lifecycle.py +0 -0
  297. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/registry/module_state.py +0 -0
  298. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/registry/registry.py +0 -0
  299. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/resources/semgrep/async.yml +0 -0
  300. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/resources/semgrep/code-quality.yml +0 -0
  301. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/resources/semgrep/feature-detection.yml +0 -0
  302. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/runtime.py +0 -0
  303. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/sync/__init__.py +0 -0
  304. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/sync/bridge_probe.py +0 -0
  305. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/sync/bridge_sync.py +0 -0
  306. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/sync/bridge_watch.py +0 -0
  307. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/sync/change_detector.py +0 -0
  308. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/sync/code_to_spec.py +0 -0
  309. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/sync/drift_detector.py +0 -0
  310. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/sync/repository_sync.py +0 -0
  311. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/sync/spec_to_code.py +0 -0
  312. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/sync/spec_to_tests.py +0 -0
  313. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/sync/watcher.py +0 -0
  314. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/sync/watcher_enhanced.py +0 -0
  315. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/telemetry.py +0 -0
  316. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/templates/__init__.py +0 -0
  317. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/templates/bridge_templates.py +0 -0
  318. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/templates/defaults/defect_v1.yaml +0 -0
  319. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/templates/defaults/enabler_v1.yaml +0 -0
  320. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/templates/defaults/spike_v1.yaml +0 -0
  321. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/templates/defaults/user_story_v1.yaml +0 -0
  322. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/templates/frameworks/scrum/user_story_v1.yaml +0 -0
  323. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/templates/personas/product-owner/user_story_v1.yaml +0 -0
  324. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/templates/providers/ado/work_item_v1.yaml +0 -0
  325. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/templates/registry.py +0 -0
  326. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/templates/specification_templates.py +0 -0
  327. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/__init__.py +0 -0
  328. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/acceptance_criteria.py +0 -0
  329. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/auth_tokens.py +0 -0
  330. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/bundle_converters.py +0 -0
  331. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/bundle_loader.py +0 -0
  332. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/code_change_detector.py +0 -0
  333. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/console.py +0 -0
  334. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/content_sanitizer.py +0 -0
  335. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/context_detection.py +0 -0
  336. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/enrichment_context.py +0 -0
  337. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/enrichment_parser.py +0 -0
  338. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/env_manager.py +0 -0
  339. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/feature_keys.py +0 -0
  340. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/git.py +0 -0
  341. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/github_annotations.py +0 -0
  342. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/ide_setup.py +0 -0
  343. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/incremental_check.py +0 -0
  344. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/metadata.py +0 -0
  345. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/optional_deps.py +0 -0
  346. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/performance.py +0 -0
  347. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/persona_ownership.py +0 -0
  348. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/progress.py +0 -0
  349. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/progressive_disclosure.py +0 -0
  350. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/prompts.py +0 -0
  351. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/sdd_discovery.py +0 -0
  352. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/source_scanner.py +0 -0
  353. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/startup_checks.py +0 -0
  354. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/structure.py +0 -0
  355. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/structured_io.py +0 -0
  356. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/suggestions.py +0 -0
  357. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/terminal.py +0 -0
  358. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/utils/yaml_utils.py +0 -0
  359. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/__init__.py +0 -0
  360. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/agile_validation.py +0 -0
  361. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/change_proposal_integration.py +0 -0
  362. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/cli_first_validator.py +0 -0
  363. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/contract_validator.py +0 -0
  364. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/fsm.py +0 -0
  365. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/repro_checker.py +0 -0
  366. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/schema.py +0 -0
  367. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/sidecar/__init__.py +0 -0
  368. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/sidecar/contract_populator.py +0 -0
  369. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/sidecar/crosshair_runner.py +0 -0
  370. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/sidecar/crosshair_summary.py +0 -0
  371. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/sidecar/dependency_installer.py +0 -0
  372. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/sidecar/framework_detector.py +0 -0
  373. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/sidecar/frameworks/__init__.py +0 -0
  374. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/sidecar/frameworks/base.py +0 -0
  375. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/sidecar/frameworks/django.py +0 -0
  376. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/sidecar/frameworks/drf.py +0 -0
  377. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/sidecar/frameworks/fastapi.py +0 -0
  378. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/sidecar/frameworks/flask.py +0 -0
  379. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/sidecar/harness_generator.py +0 -0
  380. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/sidecar/models.py +0 -0
  381. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/sidecar/orchestrator.py +0 -0
  382. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/sidecar/specmatic_runner.py +0 -0
  383. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/validators/sidecar/unannotated_detector.py +0 -0
  384. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/versioning/__init__.py +0 -0
  385. {specfact_cli-0.35.0 → specfact_cli-0.36.0}/src/specfact_cli/versioning/analyzer.py +0 -0
@@ -111,6 +111,12 @@ docs/internal/
111
111
  .claude/skills/openspec-*/
112
112
  !.claude/skills/openspec-workflows/
113
113
 
114
+ .codex/skills/openspec-*/
115
+ !.codex/skills/openspec-workflows/
116
+
117
+ .vibe/skills/openspec-*/
118
+ !.vibe/skills/openspec-workflows/
119
+
114
120
  # Semgrep rules (generated from tools/semgrep/ - source rules are versioned)
115
121
  .semgrep/
116
122
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specfact-cli
3
- Version: 0.35.0
3
+ Version: 0.36.0
4
4
  Summary: The swiss knife CLI for agile DevOps teams. Keep backlog, specs, tests, and code in sync with validation and contract enforcement for new projects and long-lived codebases.
5
5
  Project-URL: Homepage, https://github.com/nold-ai/specfact-cli
6
6
  Project-URL: Repository, https://github.com/nold-ai/specfact-cli.git
@@ -431,51 +431,11 @@ Start with:
431
431
  - **Backlogs**: GitHub Issues, Azure DevOps, Jira, Linear
432
432
  - **Contracts**: Specmatic, OpenAPI
433
433
 
434
- ### Module Lifecycle Baseline
434
+ For technical architecture details (module lifecycle, registry internals, adapters, and implementation status), use:
435
435
 
436
- SpecFact now has a lifecycle-managed module system:
437
-
438
- - `specfact init` is bootstrap-first: initializes local CLI state and reports prompt status.
439
- - `specfact init ide` handles IDE prompt/template sync and IDE settings updates.
440
- - `specfact module` is the canonical lifecycle surface:
441
- - `specfact module install <namespace/name>` installs marketplace modules into `~/.specfact/marketplace-modules/`.
442
- - `specfact module list [--source builtin|marketplace|custom]` shows multi-source discovery state.
443
- - `specfact module enable <id>` / `specfact module disable <id> [--force]` manage enabled state.
444
- - `specfact module uninstall <name>` and `specfact module upgrade <name>` manage marketplace lifecycle.
445
- - `specfact init --list-modules`, `--enable-module`, and `--disable-module` remain supported as compatibility aliases during migration.
446
- - Module lifecycle operations keep dependency-aware safety checks with `--force` cascading behavior.
447
- - Module manifests support dependency and core-version compatibility enforcement at registration time.
448
-
449
- This lifecycle model is the baseline for future granular module updates and enhancements. Module installation from third-party or open-source community providers is planned, but not implemented yet.
450
-
451
- Contract-first module architecture highlights:
452
-
453
- - `ModuleIOContract` formalizes module IO operations (`import`, `export`, `sync`, `validate`) on `ProjectBundle`.
454
- - Core-module isolation is enforced by static analysis (`core` never imports `specfact_cli.modules.*` directly).
455
- - Registration tracks protocol operation coverage and schema compatibility metadata.
456
- - Bridge registry support allows module manifests to declare `service_bridges` converters (for example ADO/Jira/Linear/GitHub) loaded at lifecycle startup without direct core-to-module imports.
457
- - Protocol reporting classifies modules from effective runtime interfaces with a single aggregate summary (`Full/Partial/Legacy`).
458
- - Module manifests support publisher and integrity metadata (arch-06) with optional checksum and signature verification at registration time.
459
-
460
- Why this matters:
461
-
462
- - Feature areas can evolve independently without repeatedly modifying core CLI wiring.
463
- - Module teams can ship at different speeds while preserving stable core behavior.
464
- - Clear IO contracts reduce coupling and make future migrations (e.g., new adapters/modules) lower risk.
465
- - Core remains focused on lifecycle, registry, and validation orchestration rather than tool-specific command logic.
466
-
467
- ---
468
-
469
- ## Developer Note: Command Layout
470
-
471
- - Primary command implementations live in `src/specfact_cli/modules/<module>/src/commands.py`.
472
- - Legacy imports from `src/specfact_cli/commands/*.py` are compatibility shims and only guarantee `app` re-exports.
473
- - Preferred imports for module code:
474
- - `from specfact_cli.modules.<module>.src.commands import app`
475
- - `from specfact_cli.modules.<module>.src.commands import <symbol>`
476
- - Shim deprecation timeline:
477
- - Legacy shim usage is deprecated for non-`app` symbols now.
478
- - Shim removal is planned no earlier than `v0.30` (or the next major migration window).
436
+ - [Architecture Reference](docs/reference/architecture.md)
437
+ - [Architecture Docs Index](docs/architecture/README.md)
438
+ - [Architecture Implementation Status](docs/architecture/implementation-status.md)
479
439
 
480
440
  ---
481
441
 
@@ -154,51 +154,11 @@ Start with:
154
154
  - **Backlogs**: GitHub Issues, Azure DevOps, Jira, Linear
155
155
  - **Contracts**: Specmatic, OpenAPI
156
156
 
157
- ### Module Lifecycle Baseline
157
+ For technical architecture details (module lifecycle, registry internals, adapters, and implementation status), use:
158
158
 
159
- SpecFact now has a lifecycle-managed module system:
160
-
161
- - `specfact init` is bootstrap-first: initializes local CLI state and reports prompt status.
162
- - `specfact init ide` handles IDE prompt/template sync and IDE settings updates.
163
- - `specfact module` is the canonical lifecycle surface:
164
- - `specfact module install <namespace/name>` installs marketplace modules into `~/.specfact/marketplace-modules/`.
165
- - `specfact module list [--source builtin|marketplace|custom]` shows multi-source discovery state.
166
- - `specfact module enable <id>` / `specfact module disable <id> [--force]` manage enabled state.
167
- - `specfact module uninstall <name>` and `specfact module upgrade <name>` manage marketplace lifecycle.
168
- - `specfact init --list-modules`, `--enable-module`, and `--disable-module` remain supported as compatibility aliases during migration.
169
- - Module lifecycle operations keep dependency-aware safety checks with `--force` cascading behavior.
170
- - Module manifests support dependency and core-version compatibility enforcement at registration time.
171
-
172
- This lifecycle model is the baseline for future granular module updates and enhancements. Module installation from third-party or open-source community providers is planned, but not implemented yet.
173
-
174
- Contract-first module architecture highlights:
175
-
176
- - `ModuleIOContract` formalizes module IO operations (`import`, `export`, `sync`, `validate`) on `ProjectBundle`.
177
- - Core-module isolation is enforced by static analysis (`core` never imports `specfact_cli.modules.*` directly).
178
- - Registration tracks protocol operation coverage and schema compatibility metadata.
179
- - Bridge registry support allows module manifests to declare `service_bridges` converters (for example ADO/Jira/Linear/GitHub) loaded at lifecycle startup without direct core-to-module imports.
180
- - Protocol reporting classifies modules from effective runtime interfaces with a single aggregate summary (`Full/Partial/Legacy`).
181
- - Module manifests support publisher and integrity metadata (arch-06) with optional checksum and signature verification at registration time.
182
-
183
- Why this matters:
184
-
185
- - Feature areas can evolve independently without repeatedly modifying core CLI wiring.
186
- - Module teams can ship at different speeds while preserving stable core behavior.
187
- - Clear IO contracts reduce coupling and make future migrations (e.g., new adapters/modules) lower risk.
188
- - Core remains focused on lifecycle, registry, and validation orchestration rather than tool-specific command logic.
189
-
190
- ---
191
-
192
- ## Developer Note: Command Layout
193
-
194
- - Primary command implementations live in `src/specfact_cli/modules/<module>/src/commands.py`.
195
- - Legacy imports from `src/specfact_cli/commands/*.py` are compatibility shims and only guarantee `app` re-exports.
196
- - Preferred imports for module code:
197
- - `from specfact_cli.modules.<module>.src.commands import app`
198
- - `from specfact_cli.modules.<module>.src.commands import <symbol>`
199
- - Shim deprecation timeline:
200
- - Legacy shim usage is deprecated for non-`app` symbols now.
201
- - Shim removal is planned no earlier than `v0.30` (or the next major migration window).
159
+ - [Architecture Reference](docs/reference/architecture.md)
160
+ - [Architecture Docs Index](docs/architecture/README.md)
161
+ - [Architecture Implementation Status](docs/architecture/implementation-status.md)
202
162
 
203
163
  ---
204
164
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "specfact-cli"
7
- version = "0.35.0"
7
+ version = "0.36.0"
8
8
  description = "The swiss knife CLI for agile DevOps teams. Keep backlog, specs, tests, and code in sync with validation and contract enforcement for new projects and long-lived codebases."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -3,4 +3,4 @@ SpecFact CLI - Spec→Contract→Sentinel tool for contract-driven development.
3
3
  """
4
4
 
5
5
  # Package version: keep in sync with pyproject.toml, setup.py, src/specfact_cli/__init__.py
6
- __version__ = "0.35.0"
6
+ __version__ = "0.36.0"
@@ -8,6 +8,6 @@ This package provides command-line tools for:
8
8
  - Supporting agile ceremonies and team workflows
9
9
  """
10
10
 
11
- __version__ = "0.35.0"
11
+ __version__ = "0.36.0"
12
12
 
13
13
  __all__ = ["__version__"]
@@ -1657,7 +1657,10 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin, BacklogAdapter):
1657
1657
  ]
1658
1658
 
1659
1659
  try:
1660
- response = requests.patch(url, json=patch_document, headers=headers, timeout=30)
1660
+ response = self._request_with_retry(
1661
+ lambda: requests.patch(url, json=patch_document, headers=headers, timeout=30),
1662
+ retry_on_ambiguous_transport=False,
1663
+ )
1661
1664
  if is_debug_mode():
1662
1665
  debug_log_operation(
1663
1666
  "ado_patch",
@@ -1800,8 +1803,9 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin, BacklogAdapter):
1800
1803
  patch_document = [{"op": "replace", "path": "/fields/System.State", "value": ado_state}]
1801
1804
 
1802
1805
  try:
1803
- response = requests.patch(url, json=patch_document, headers=headers, timeout=30)
1804
- response.raise_for_status()
1806
+ response = self._request_with_retry(
1807
+ lambda: requests.patch(url, json=patch_document, headers=headers, timeout=30)
1808
+ )
1805
1809
  work_item_data = response.json()
1806
1810
 
1807
1811
  work_item_url = work_item_data.get("_links", {}).get("html", {}).get("href", "")
@@ -1933,8 +1937,9 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin, BacklogAdapter):
1933
1937
  ]
1934
1938
 
1935
1939
  try:
1936
- response = requests.patch(url, json=patch_document, headers=headers, timeout=30)
1937
- response.raise_for_status()
1940
+ response = self._request_with_retry(
1941
+ lambda: requests.patch(url, json=patch_document, headers=headers, timeout=30)
1942
+ )
1938
1943
  work_item_data = response.json()
1939
1944
 
1940
1945
  work_item_url = work_item_data.get("_links", {}).get("html", {}).get("href", "")
@@ -2040,8 +2045,9 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin, BacklogAdapter):
2040
2045
  patch_document = [{"op": "replace", "path": "/fields/System.State", "value": ado_state}]
2041
2046
 
2042
2047
  try:
2043
- response = requests.patch(url, json=patch_document, headers=headers, timeout=30)
2044
- response.raise_for_status()
2048
+ response = self._request_with_retry(
2049
+ lambda: requests.patch(url, json=patch_document, headers=headers, timeout=30)
2050
+ )
2045
2051
  work_item_data = response.json()
2046
2052
 
2047
2053
  work_item_url = work_item_data.get("_links", {}).get("html", {}).get("href", "")
@@ -2442,8 +2448,10 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin, BacklogAdapter):
2442
2448
  comment_body = {"text": comment_text}
2443
2449
 
2444
2450
  try:
2445
- response = requests.post(url, json=comment_body, headers=headers, timeout=30)
2446
- response.raise_for_status()
2451
+ response = self._request_with_retry(
2452
+ lambda: requests.post(url, json=comment_body, headers=headers, timeout=30),
2453
+ retry_on_ambiguous_transport=False,
2454
+ )
2447
2455
  comment_data = response.json()
2448
2456
 
2449
2457
  comment_id = comment_data.get("id")
@@ -2690,6 +2698,7 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin, BacklogAdapter):
2690
2698
  self,
2691
2699
  sprint_filter: str | None,
2692
2700
  items: list[BacklogItem],
2701
+ apply_current_when_missing: bool = True,
2693
2702
  ) -> tuple[str | None, list[BacklogItem]]:
2694
2703
  """
2695
2704
  Resolve sprint filter with path matching and ambiguity detection.
@@ -2705,6 +2714,8 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin, BacklogAdapter):
2705
2714
  ValueError: If ambiguous sprint name match is detected
2706
2715
  """
2707
2716
  if not sprint_filter:
2717
+ if not apply_current_when_missing:
2718
+ return None, items
2708
2719
  # No sprint filter - try to get current iteration
2709
2720
  current_iteration = self._get_current_iteration()
2710
2721
  if current_iteration:
@@ -2859,13 +2870,16 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin, BacklogAdapter):
2859
2870
  # Sprint will be resolved post-fetch to handle ambiguity
2860
2871
  pass
2861
2872
  else:
2862
- # No sprint/iteration - try current iteration
2863
- current_iteration = self._get_current_iteration()
2864
- if current_iteration:
2865
- resolved_iteration = current_iteration
2866
- conditions.append(f"[System.IterationPath] = '{resolved_iteration}'")
2867
- else:
2868
- console.print("[yellow]⚠ No current iteration found and no sprint/iteration filter provided[/yellow]")
2873
+ # No sprint/iteration - optionally use current iteration default
2874
+ if getattr(filters, "use_current_iteration_default", True):
2875
+ current_iteration = self._get_current_iteration()
2876
+ if current_iteration:
2877
+ resolved_iteration = current_iteration
2878
+ conditions.append(f"[System.IterationPath] = '{resolved_iteration}'")
2879
+ else:
2880
+ console.print(
2881
+ "[yellow]⚠ No current iteration found and no sprint/iteration filter provided[/yellow]"
2882
+ )
2869
2883
 
2870
2884
  if conditions:
2871
2885
  wiql_parts.append("AND " + " AND ".join(conditions))
@@ -3113,7 +3127,11 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin, BacklogAdapter):
3113
3127
  # Sprint filtering with path matching and ambiguity detection
3114
3128
  if filters.sprint:
3115
3129
  try:
3116
- _, filtered_items = self._resolve_sprint_filter(filters.sprint, filtered_items)
3130
+ _, filtered_items = self._resolve_sprint_filter(
3131
+ filters.sprint,
3132
+ filtered_items,
3133
+ apply_current_when_missing=getattr(filters, "use_current_iteration_default", True),
3134
+ )
3117
3135
  except ValueError as e:
3118
3136
  # Ambiguous sprint match - raise with clear error message
3119
3137
  console.print(f"[red]Error:[/red] {e}")
@@ -3137,6 +3155,115 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin, BacklogAdapter):
3137
3155
 
3138
3156
  return filtered_items
3139
3157
 
3158
+ @beartype
3159
+ @require(
3160
+ lambda project_id: isinstance(project_id, str) and len(project_id.strip()) > 0, "project_id must be non-empty"
3161
+ )
3162
+ @require(lambda payload: isinstance(payload, dict), "payload must be dict")
3163
+ @ensure(lambda result: isinstance(result, dict), "Must return dict")
3164
+ def create_issue(self, project_id: str, payload: dict[str, Any]) -> dict[str, Any]:
3165
+ """Create an Azure DevOps work item from provider-agnostic backlog payload."""
3166
+ org, project = self._resolve_graph_project_context(project_id)
3167
+ if not self.api_token:
3168
+ raise ValueError("Azure DevOps API token is required")
3169
+
3170
+ title = str(payload.get("title") or "").strip()
3171
+ if not title:
3172
+ raise ValueError("payload.title is required")
3173
+
3174
+ raw_type = str(payload.get("type") or "task").strip().lower()
3175
+ type_mapping = {
3176
+ "epic": "Epic",
3177
+ "feature": "Feature",
3178
+ "story": "User Story",
3179
+ "user story": "User Story",
3180
+ "task": "Task",
3181
+ "bug": "Bug",
3182
+ "spike": "Task",
3183
+ }
3184
+ work_item_type = type_mapping.get(raw_type, "Task")
3185
+
3186
+ description = str(payload.get("description") or payload.get("body") or "").strip()
3187
+ description_format = str(payload.get("description_format") or "markdown").strip().lower()
3188
+ field_rendering_format = "Markdown" if description_format != "classic" else "Html"
3189
+ patch_document: list[dict[str, Any]] = [
3190
+ {"op": "add", "path": "/fields/System.Title", "value": title},
3191
+ {"op": "add", "path": "/fields/System.Description", "value": description},
3192
+ {"op": "add", "path": "/multilineFieldsFormat/System.Description", "value": field_rendering_format},
3193
+ ]
3194
+
3195
+ acceptance_criteria = str(payload.get("acceptance_criteria") or "").strip()
3196
+ if acceptance_criteria:
3197
+ patch_document.append(
3198
+ {
3199
+ "op": "add",
3200
+ "path": "/fields/Microsoft.VSTS.Common.AcceptanceCriteria",
3201
+ "value": acceptance_criteria,
3202
+ }
3203
+ )
3204
+
3205
+ priority = payload.get("priority")
3206
+ if priority not in (None, ""):
3207
+ patch_document.append(
3208
+ {
3209
+ "op": "add",
3210
+ "path": "/fields/Microsoft.VSTS.Common.Priority",
3211
+ "value": priority,
3212
+ }
3213
+ )
3214
+
3215
+ story_points = payload.get("story_points")
3216
+ if story_points is not None:
3217
+ patch_document.append(
3218
+ {
3219
+ "op": "add",
3220
+ "path": "/fields/Microsoft.VSTS.Scheduling.StoryPoints",
3221
+ "value": story_points,
3222
+ }
3223
+ )
3224
+
3225
+ sprint = str(payload.get("sprint") or "").strip()
3226
+ if sprint:
3227
+ patch_document.append(
3228
+ {
3229
+ "op": "add",
3230
+ "path": "/fields/System.IterationPath",
3231
+ "value": sprint,
3232
+ }
3233
+ )
3234
+
3235
+ parent_id = str(payload.get("parent_id") or "").strip()
3236
+ if parent_id:
3237
+ parent_url = f"{self.base_url}/{org}/{project}/_apis/wit/workItems/{parent_id}"
3238
+ patch_document.append(
3239
+ {
3240
+ "op": "add",
3241
+ "path": "/relations/-",
3242
+ "value": {"rel": "System.LinkTypes.Hierarchy-Reverse", "url": parent_url},
3243
+ }
3244
+ )
3245
+
3246
+ url = f"{self.base_url}/{org}/{project}/_apis/wit/workitems/${work_item_type}?api-version=7.1"
3247
+ headers = {
3248
+ "Content-Type": "application/json-patch+json",
3249
+ **self._auth_headers(),
3250
+ }
3251
+ response = self._request_with_retry(
3252
+ lambda: requests.patch(url, json=patch_document, headers=headers, timeout=30),
3253
+ retry_on_ambiguous_transport=False,
3254
+ )
3255
+ created = response.json()
3256
+
3257
+ created_id = str(created.get("id") or "")
3258
+ html_url = str(created.get("_links", {}).get("html", {}).get("href") or "")
3259
+ fallback_url = str(created.get("url") or "")
3260
+
3261
+ return {
3262
+ "id": created_id,
3263
+ "key": created_id,
3264
+ "url": html_url or fallback_url,
3265
+ }
3266
+
3140
3267
  @beartype
3141
3268
  @require(lambda project_id: isinstance(project_id, str) and len(project_id) > 0, "project_id must be non-empty")
3142
3269
  @ensure(lambda result: isinstance(result, list), "Must return list")
@@ -3429,8 +3556,9 @@ class AdoAdapter(BridgeAdapter, BacklogAdapterMixin, BacklogAdapter):
3429
3556
 
3430
3557
  # Update work item
3431
3558
  try:
3432
- response = requests.patch(url, headers=headers, json=operations, timeout=30)
3433
- response.raise_for_status()
3559
+ response = self._request_with_retry(
3560
+ lambda: requests.patch(url, headers=headers, json=operations, timeout=30)
3561
+ )
3434
3562
  except requests.HTTPError as e:
3435
3563
  user_msg = _log_ado_patch_failure(e.response, operations, url)
3436
3564
  e.ado_user_message = user_msg
@@ -11,10 +11,12 @@ functionality for status mapping, metadata extraction, and conflict resolution.
11
11
 
12
12
  from __future__ import annotations
13
13
 
14
+ import time
14
15
  from abc import ABC, abstractmethod
15
16
  from datetime import UTC, datetime
16
17
  from typing import Any
17
18
 
19
+ import requests
18
20
  from beartype import beartype
19
21
  from icontract import ensure, require
20
22
 
@@ -35,6 +37,10 @@ class BacklogAdapterMixin(ABC):
35
37
  and implement the abstract methods to provide tool-specific implementations.
36
38
  """
37
39
 
40
+ RETRYABLE_HTTP_STATUSES: tuple[int, ...] = (429, 500, 502, 503, 504)
41
+ RETRY_DEFAULT_ATTEMPTS: int = 3
42
+ RETRY_BACKOFF_SECONDS: float = 0.5
43
+
38
44
  @abstractmethod
39
45
  @beartype
40
46
  @require(lambda status: isinstance(status, str) and len(status) > 0, "Status must be non-empty string")
@@ -140,6 +146,71 @@ class BacklogAdapterMixin(ABC):
140
146
 
141
147
  return target_state
142
148
 
149
+ @beartype
150
+ @require(lambda attempts: attempts is None or attempts > 0, "attempts must be > 0 when provided")
151
+ @require(
152
+ lambda backoff_seconds: backoff_seconds is None or backoff_seconds >= 0,
153
+ "backoff_seconds must be >= 0 when provided",
154
+ )
155
+ @require(
156
+ lambda retry_on_ambiguous_transport: isinstance(retry_on_ambiguous_transport, bool), "retry flag must be bool"
157
+ )
158
+ @ensure(lambda result: hasattr(result, "raise_for_status"), "Result must support raise_for_status")
159
+ def _request_with_retry(
160
+ self,
161
+ request_callable: Any,
162
+ *,
163
+ attempts: int | None = None,
164
+ backoff_seconds: float | None = None,
165
+ retry_on_ambiguous_transport: bool = True,
166
+ ) -> Any:
167
+ """Execute HTTP request with central retry policy for transient failures.
168
+
169
+ For non-idempotent writes, callers can disable transport-error replay by passing
170
+ retry_on_ambiguous_transport=False to avoid accidental duplicate side effects.
171
+ """
172
+ max_attempts = attempts or self.RETRY_DEFAULT_ATTEMPTS
173
+ delay = backoff_seconds if backoff_seconds is not None else self.RETRY_BACKOFF_SECONDS
174
+
175
+ last_error: Exception | None = None
176
+ for attempt in range(1, max_attempts + 1):
177
+ try:
178
+ response = request_callable()
179
+ status_code = int(getattr(response, "status_code", 0) or 0)
180
+ if status_code in self.RETRYABLE_HTTP_STATUSES and attempt < max_attempts:
181
+ time.sleep(delay * (2 ** (attempt - 1)))
182
+ continue
183
+ response.raise_for_status()
184
+ return response
185
+ except requests.HTTPError as error:
186
+ status_code = int(getattr(error.response, "status_code", 0) or 0)
187
+ is_transient = status_code in self.RETRYABLE_HTTP_STATUSES
188
+ last_error = error
189
+ if is_transient and attempt < max_attempts:
190
+ time.sleep(delay * (2 ** (attempt - 1)))
191
+ continue
192
+ raise
193
+ except (requests.Timeout, requests.ConnectionError) as error:
194
+ last_error = error
195
+ if retry_on_ambiguous_transport and attempt < max_attempts:
196
+ time.sleep(delay * (2 ** (attempt - 1)))
197
+ continue
198
+ raise
199
+
200
+ if last_error is not None:
201
+ raise last_error
202
+ raise RuntimeError("Retry logic failed without response or error")
203
+
204
+ @abstractmethod
205
+ @beartype
206
+ @require(
207
+ lambda project_id: isinstance(project_id, str) and len(project_id.strip()) > 0, "Project ID must be non-empty"
208
+ )
209
+ @require(lambda payload: isinstance(payload, dict), "Payload must be dict")
210
+ @ensure(lambda result: isinstance(result, dict), "Must return created issue metadata dict")
211
+ def create_issue(self, project_id: str, payload: dict[str, Any]) -> dict[str, Any]:
212
+ """Create backlog issue/work item from provider-agnostic payload."""
213
+
143
214
  @abstractmethod
144
215
  @beartype
145
216
  @require(lambda item_data: isinstance(item_data, dict), "Item data must be dict")