specfact-cli 0.48.2__tar.gz → 0.50.1__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 (281) hide show
  1. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/PKG-INFO +1 -1
  2. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/pyproject.toml +1 -1
  3. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/__init__.py +1 -1
  4. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/__init__.py +1 -1
  5. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/analyzers/code_analyzer.py +3 -2
  6. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/models/__init__.py +30 -0
  7. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/models/project.py +10 -1
  8. specfact_cli-0.50.1/src/specfact_cli/models/requirements.py +183 -0
  9. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/registry/module_discovery.py +16 -2
  10. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/registry/module_grouping.py +8 -1
  11. specfact_cli-0.50.1/src/specfact_cli/requirements/__init__.py +28 -0
  12. specfact_cli-0.50.1/src/specfact_cli/requirements/context.py +330 -0
  13. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/.gitignore +0 -0
  14. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/LICENSE +0 -0
  15. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/README.md +0 -0
  16. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/resources/bundled-module-registry/index.json +0 -0
  17. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/resources/keys/README.md +0 -0
  18. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/resources/keys/module-signing-public.pem +0 -0
  19. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/resources/mappings/node-async.yaml +0 -0
  20. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/resources/mappings/python-async.yaml +0 -0
  21. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/resources/mappings/speckit-default.yaml +0 -0
  22. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/resources/schemas/deviation.schema.json +0 -0
  23. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/resources/schemas/plan.schema.json +0 -0
  24. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/resources/schemas/protocol.schema.json +0 -0
  25. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/resources/templates/github-action.yml.j2 +0 -0
  26. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/resources/templates/persona/architect.md.j2 +0 -0
  27. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/resources/templates/persona/developer.md.j2 +0 -0
  28. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/resources/templates/persona/product-owner.md.j2 +0 -0
  29. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/resources/templates/plan.bundle.yaml.j2 +0 -0
  30. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/resources/templates/policies/kanban.yaml +0 -0
  31. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/resources/templates/policies/mixed.yaml +0 -0
  32. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/resources/templates/policies/safe.yaml +0 -0
  33. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/resources/templates/policies/scrum.yaml +0 -0
  34. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/resources/templates/pr-template.md.j2 +0 -0
  35. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/resources/templates/protocol.yaml.j2 +0 -0
  36. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/resources/templates/telemetry.yaml.example +0 -0
  37. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/__main__.py +0 -0
  38. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/adapters/__init__.py +0 -0
  39. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/adapters/ado.py +0 -0
  40. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/adapters/backlog_base.py +0 -0
  41. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/adapters/base.py +0 -0
  42. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/adapters/github.py +0 -0
  43. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/adapters/openspec.py +0 -0
  44. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/adapters/openspec_parser.py +0 -0
  45. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/adapters/registry.py +0 -0
  46. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/adapters/speckit.py +0 -0
  47. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/agents/__init__.py +0 -0
  48. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/agents/analyze_agent.py +0 -0
  49. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/agents/base.py +0 -0
  50. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/agents/plan_agent.py +0 -0
  51. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/agents/registry.py +0 -0
  52. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/agents/sync_agent.py +0 -0
  53. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/analyzers/__init__.py +0 -0
  54. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/analyzers/ambiguity_scanner.py +0 -0
  55. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/analyzers/constitution_evidence_extractor.py +0 -0
  56. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/analyzers/contract_extractor.py +0 -0
  57. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/analyzers/control_flow_analyzer.py +0 -0
  58. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/analyzers/graph_analyzer.py +0 -0
  59. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/analyzers/relationship_mapper.py +0 -0
  60. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/analyzers/requirement_extractor.py +0 -0
  61. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/analyzers/test_pattern_extractor.py +0 -0
  62. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/backlog/__init__.py +0 -0
  63. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/backlog/adapters/__init__.py +0 -0
  64. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/backlog/adapters/base.py +0 -0
  65. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/backlog/converter.py +0 -0
  66. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/backlog/filters.py +0 -0
  67. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/backlog/mappers/__init__.py +0 -0
  68. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/backlog/mappers/ado_mapper.py +0 -0
  69. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/backlog/mappers/base.py +0 -0
  70. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/backlog/mappers/github_mapper.py +0 -0
  71. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/backlog/mappers/template_config.py +0 -0
  72. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/cli.py +0 -0
  73. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/commands/__init__.py +0 -0
  74. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/commands/_bundle_shim.py +0 -0
  75. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/commands/analyze.py +0 -0
  76. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/commands/contract_cmd.py +0 -0
  77. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/commands/drift.py +0 -0
  78. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/commands/enforce.py +0 -0
  79. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/commands/generate.py +0 -0
  80. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/commands/import_cmd.py +0 -0
  81. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/commands/init.py +0 -0
  82. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/commands/migrate.py +0 -0
  83. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/commands/plan.py +0 -0
  84. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/commands/project_cmd.py +0 -0
  85. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/commands/repro.py +0 -0
  86. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/commands/sdd.py +0 -0
  87. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/commands/spec.py +0 -0
  88. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/commands/sync.py +0 -0
  89. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/commands/update.py +0 -0
  90. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/commands/validate.py +0 -0
  91. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/common/__init__.py +0 -0
  92. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/common/bundle_factory.py +0 -0
  93. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/common/logger_setup.py +0 -0
  94. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/common/logging_utils.py +0 -0
  95. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/common/text_utils.py +0 -0
  96. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/common/utils.py +0 -0
  97. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/comparators/__init__.py +0 -0
  98. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/comparators/plan_comparator.py +0 -0
  99. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/contracts/__init__.py +0 -0
  100. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/contracts/crosshair_props.py +0 -0
  101. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/contracts/module_interface.py +0 -0
  102. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/enrichers/constitution_enricher.py +0 -0
  103. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/enrichers/plan_enricher.py +0 -0
  104. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/generators/__init__.py +0 -0
  105. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/generators/contract_generator.py +0 -0
  106. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/generators/openapi_extractor.py +0 -0
  107. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/generators/persona_exporter.py +0 -0
  108. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/generators/plan_generator.py +0 -0
  109. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/generators/protocol_generator.py +0 -0
  110. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/generators/report_generator.py +0 -0
  111. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/generators/task_generator.py +0 -0
  112. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/generators/test_to_openapi.py +0 -0
  113. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/generators/workflow_generator.py +0 -0
  114. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/groups/__init__.py +0 -0
  115. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/groups/codebase_group.py +0 -0
  116. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/groups/govern_group.py +0 -0
  117. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/groups/member_group.py +0 -0
  118. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/groups/project_group.py +0 -0
  119. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/groups/spec_group.py +0 -0
  120. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/importers/__init__.py +0 -0
  121. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/importers/speckit_converter.py +0 -0
  122. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/importers/speckit_scanner.py +0 -0
  123. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/integrations/__init__.py +0 -0
  124. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/integrations/specmatic.py +0 -0
  125. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/merge/__init__.py +0 -0
  126. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/merge/resolver.py +0 -0
  127. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/migrations/__init__.py +0 -0
  128. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/migrations/plan_migrator.py +0 -0
  129. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/models/backlog_item.py +0 -0
  130. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/models/bridge.py +0 -0
  131. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/models/capabilities.py +0 -0
  132. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/models/change.py +0 -0
  133. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/models/contract.py +0 -0
  134. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/models/deviation.py +0 -0
  135. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/models/dor_config.py +0 -0
  136. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/models/enforcement.py +0 -0
  137. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/models/module_package.py +0 -0
  138. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/models/persona_template.py +0 -0
  139. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/models/plan.py +0 -0
  140. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/models/protocol.py +0 -0
  141. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/models/quality.py +0 -0
  142. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/models/sdd.py +0 -0
  143. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/models/source_tracking.py +0 -0
  144. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/models/task.py +0 -0
  145. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/models/validation.py +0 -0
  146. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/modes/__init__.py +0 -0
  147. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/modes/detector.py +0 -0
  148. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/modes/router.py +0 -0
  149. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/modules/__init__.py +0 -0
  150. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/modules/_bundle_import.py +0 -0
  151. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/modules/init/module-package.yaml +0 -0
  152. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/modules/init/src/__init__.py +0 -0
  153. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/modules/init/src/app.py +0 -0
  154. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/modules/init/src/commands.py +0 -0
  155. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/modules/init/src/first_run_selection.py +0 -0
  156. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/modules/module_io_shim.py +0 -0
  157. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/modules/module_registry/module-package.yaml +0 -0
  158. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/modules/module_registry/src/__init__.py +0 -0
  159. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/modules/module_registry/src/app.py +0 -0
  160. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/modules/module_registry/src/commands.py +0 -0
  161. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/modules/upgrade/module-package.yaml +0 -0
  162. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/modules/upgrade/src/__init__.py +0 -0
  163. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/modules/upgrade/src/app.py +0 -0
  164. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/modules/upgrade/src/commands.py +0 -0
  165. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/parsers/__init__.py +0 -0
  166. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/parsers/persona_importer.py +0 -0
  167. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/registry/__init__.py +0 -0
  168. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/registry/alias_manager.py +0 -0
  169. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/registry/bootstrap.py +0 -0
  170. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/registry/bridge_registry.py +0 -0
  171. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/registry/crypto_validator.py +0 -0
  172. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/registry/custom_registries.py +0 -0
  173. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/registry/dependency_resolver.py +0 -0
  174. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/registry/extension_registry.py +0 -0
  175. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/registry/help_cache.py +0 -0
  176. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/registry/marketplace_client.py +0 -0
  177. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/registry/metadata.py +0 -0
  178. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/registry/module_availability.py +0 -0
  179. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/registry/module_installer.py +0 -0
  180. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/registry/module_lifecycle.py +0 -0
  181. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/registry/module_packages.py +0 -0
  182. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/registry/module_security.py +0 -0
  183. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/registry/module_state.py +0 -0
  184. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/registry/registry.py +0 -0
  185. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/resources/semgrep/async.yml +0 -0
  186. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/resources/semgrep/code-quality.yml +0 -0
  187. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/resources/semgrep/feature-detection.yml +0 -0
  188. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/runtime.py +0 -0
  189. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/sync/__init__.py +0 -0
  190. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/sync/bridge_probe.py +0 -0
  191. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/sync/bridge_sync.py +0 -0
  192. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/sync/bridge_sync_openspec_md_parse.py +0 -0
  193. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/sync/bridge_sync_requirement_from_proposal.py +0 -0
  194. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/sync/bridge_sync_requirement_helpers.py +0 -0
  195. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/sync/bridge_sync_tasks_from_proposal.py +0 -0
  196. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/sync/bridge_sync_what_changes_format.py +0 -0
  197. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/sync/bridge_sync_write_openspec_from_proposal.py +0 -0
  198. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/sync/bridge_watch.py +0 -0
  199. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/sync/change_detector.py +0 -0
  200. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/sync/code_to_spec.py +0 -0
  201. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/sync/drift_detector.py +0 -0
  202. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/sync/repository_sync.py +0 -0
  203. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/sync/spec_to_code.py +0 -0
  204. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/sync/spec_to_tests.py +0 -0
  205. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/sync/watcher.py +0 -0
  206. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/sync/watcher_enhanced.py +0 -0
  207. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/telemetry.py +0 -0
  208. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/templates/__init__.py +0 -0
  209. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/templates/defaults/defect_v1.yaml +0 -0
  210. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/templates/defaults/enabler_v1.yaml +0 -0
  211. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/templates/defaults/spike_v1.yaml +0 -0
  212. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/templates/defaults/user_story_v1.yaml +0 -0
  213. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/templates/frameworks/scrum/user_story_v1.yaml +0 -0
  214. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/templates/personas/product-owner/user_story_v1.yaml +0 -0
  215. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/templates/providers/ado/work_item_v1.yaml +0 -0
  216. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/templates/registry.py +0 -0
  217. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/templates/specification_templates.py +0 -0
  218. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/__init__.py +0 -0
  219. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/acceptance_criteria.py +0 -0
  220. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/auth_tokens.py +0 -0
  221. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/bundle_converters.py +0 -0
  222. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/bundle_loader.py +0 -0
  223. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/code_change_detector.py +0 -0
  224. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/console.py +0 -0
  225. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/content_sanitizer.py +0 -0
  226. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/context_detection.py +0 -0
  227. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/contract_predicates.py +0 -0
  228. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/enrichment_context.py +0 -0
  229. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/enrichment_parser.py +0 -0
  230. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/env_manager.py +0 -0
  231. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/feature_keys.py +0 -0
  232. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/git.py +0 -0
  233. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/github_annotations.py +0 -0
  234. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/icontract_helpers.py +0 -0
  235. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/ide_setup.py +0 -0
  236. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/incremental_check.py +0 -0
  237. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/metadata.py +0 -0
  238. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/optional_deps.py +0 -0
  239. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/performance.py +0 -0
  240. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/persona_ownership.py +0 -0
  241. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/progress.py +0 -0
  242. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/progressive_disclosure.py +0 -0
  243. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/project_artifact_write.py +0 -0
  244. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/prompts.py +0 -0
  245. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/sdd_discovery.py +0 -0
  246. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/source_scanner.py +0 -0
  247. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/startup_checks.py +0 -0
  248. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/structure.py +0 -0
  249. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/structured_io.py +0 -0
  250. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/suggestions.py +0 -0
  251. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/terminal.py +0 -0
  252. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/utils/yaml_utils.py +0 -0
  253. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validation/__init__.py +0 -0
  254. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validation/command_audit.py +0 -0
  255. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/__init__.py +0 -0
  256. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/agile_validation.py +0 -0
  257. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/change_proposal_integration.py +0 -0
  258. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/cli_first_validator.py +0 -0
  259. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/contract_validator.py +0 -0
  260. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/fsm.py +0 -0
  261. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/repro_checker.py +0 -0
  262. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/schema.py +0 -0
  263. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/sidecar/__init__.py +0 -0
  264. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/sidecar/contract_populator.py +0 -0
  265. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/sidecar/crosshair_runner.py +0 -0
  266. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/sidecar/crosshair_summary.py +0 -0
  267. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/sidecar/dependency_installer.py +0 -0
  268. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/sidecar/framework_detector.py +0 -0
  269. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/sidecar/frameworks/__init__.py +0 -0
  270. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/sidecar/frameworks/base.py +0 -0
  271. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/sidecar/frameworks/django.py +0 -0
  272. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/sidecar/frameworks/drf.py +0 -0
  273. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/sidecar/frameworks/fastapi.py +0 -0
  274. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/sidecar/frameworks/flask.py +0 -0
  275. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/sidecar/harness_generator.py +0 -0
  276. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/sidecar/models.py +0 -0
  277. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/sidecar/orchestrator.py +0 -0
  278. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/sidecar/specmatic_runner.py +0 -0
  279. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/validators/sidecar/unannotated_detector.py +0 -0
  280. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/versioning/__init__.py +0 -0
  281. {specfact_cli-0.48.2 → specfact_cli-0.50.1}/src/specfact_cli/versioning/analyzer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: specfact-cli
3
- Version: 0.48.2
3
+ Version: 0.50.1
4
4
  Summary: AI-bloat defense CLI for Python teams. Run deterministic code review, cleanup forecasts, and spec/contract evidence for AI-assisted and brownfield delivery.
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
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "specfact-cli"
7
- version = "0.48.2"
7
+ version = "0.50.1"
8
8
  description = "AI-bloat defense CLI for Python teams. Run deterministic code review, cleanup forecasts, and spec/contract evidence for AI-assisted and brownfield delivery."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -3,4 +3,4 @@ SpecFact CLI - AI-bloat defense CLI for Python teams.
3
3
  """
4
4
 
5
5
  # Package version: keep in sync with pyproject.toml, setup.py, src/specfact_cli/__init__.py
6
- __version__ = "0.48.2"
6
+ __version__ = "0.50.1"
@@ -76,6 +76,6 @@ def _install_progressive_disclosure() -> None:
76
76
  # keeps missing-command and missing-parameter UX consistent outside the root CLI too.
77
77
  _install_progressive_disclosure()
78
78
 
79
- __version__ = "0.48.2"
79
+ __version__ = "0.50.1"
80
80
 
81
81
  __all__ = ["__version__"]
@@ -128,10 +128,11 @@ class CodeAnalyzer:
128
128
  def _resolve_analyzer_entry_point(repo_path: Path, entry_point: Path | None) -> Path | None:
129
129
  if entry_point is None:
130
130
  return None
131
- resolved = entry_point if entry_point.is_absolute() else (repo_path / entry_point).resolve()
131
+ resolved_repo_path = repo_path.resolve()
132
+ resolved = entry_point.resolve() if entry_point.is_absolute() else (resolved_repo_path / entry_point).resolve()
132
133
  if not resolved.exists():
133
134
  raise ValueError(f"Entry point does not exist: {resolved}")
134
- if not str(resolved).startswith(str(repo_path)):
135
+ if not resolved.is_relative_to(resolved_repo_path):
135
136
  raise ValueError(f"Entry point must be within repository: {resolved}")
136
137
  return resolved
137
138
 
@@ -37,6 +37,22 @@ from specfact_cli.models.project import (
37
37
  SectionLock,
38
38
  )
39
39
  from specfact_cli.models.protocol import Protocol, Transition
40
+ from specfact_cli.models.requirements import (
41
+ REQUIREMENTS_INPUT_SCHEMA_VERSION,
42
+ BusinessRule,
43
+ RequirementCompletenessFinding,
44
+ RequirementCompletenessSeverity,
45
+ RequirementConstraint,
46
+ RequirementConstraintType,
47
+ RequirementEvidenceLink,
48
+ RequirementEvidenceLinkType,
49
+ RequirementInput,
50
+ RequirementsInputExtensionPayload,
51
+ RequirementSourceReference,
52
+ RequirementSourceType,
53
+ load_requirements_input_extension,
54
+ requirements_input_extension_payload,
55
+ )
40
56
  from specfact_cli.models.sdd import (
41
57
  SDDCoverageThresholds,
42
58
  SDDEnforcementBudget,
@@ -49,6 +65,7 @@ from specfact_cli.models.source_tracking import SourceTracking
49
65
 
50
66
 
51
67
  __all__ = [
68
+ "REQUIREMENTS_INPUT_SCHEMA_VERSION",
52
69
  "AdapterType",
53
70
  "ArtifactMapping",
54
71
  "BridgeConfig",
@@ -57,6 +74,7 @@ __all__ = [
57
74
  "BundleManifest",
58
75
  "BundleVersions",
59
76
  "Business",
77
+ "BusinessRule",
60
78
  "ChangeArchive",
61
79
  "ChangeProposal",
62
80
  "ChangeTracking",
@@ -84,6 +102,16 @@ __all__ = [
84
102
  "Protocol",
85
103
  "ProtocolIndex",
86
104
  "Release",
105
+ "RequirementCompletenessFinding",
106
+ "RequirementCompletenessSeverity",
107
+ "RequirementConstraint",
108
+ "RequirementConstraintType",
109
+ "RequirementEvidenceLink",
110
+ "RequirementEvidenceLinkType",
111
+ "RequirementInput",
112
+ "RequirementSourceReference",
113
+ "RequirementSourceType",
114
+ "RequirementsInputExtensionPayload",
87
115
  "SDDCoverageThresholds",
88
116
  "SDDEnforcementBudget",
89
117
  "SDDHow",
@@ -100,4 +128,6 @@ __all__ = [
100
128
  "TemplateSection",
101
129
  "Transition",
102
130
  "ValidationReport",
131
+ "load_requirements_input_extension",
132
+ "requirements_input_extension_payload",
103
133
  ]
@@ -559,7 +559,13 @@ class ProjectBundle(BaseModel):
559
559
  if progress_callback:
560
560
  progress_callback(current + 1, total_artifacts, "bundle.manifest.yaml")
561
561
  manifest_data = load_structured_file(manifest_path)
562
- manifest = BundleManifest.model_validate(manifest_data)
562
+ if not isinstance(manifest_data, dict):
563
+ raise ValueError("Bundle manifest must be a mapping")
564
+ manifest_mapping = cast(dict[str, Any], manifest_data)
565
+ extensions_data = manifest_mapping.get("extensions", {})
566
+ if not isinstance(extensions_data, dict):
567
+ raise ValueError("ProjectBundle extensions must be a mapping")
568
+ manifest = BundleManifest.model_validate(manifest_mapping)
563
569
  current += 1
564
570
 
565
571
  slots = _BundleLoadSlots()
@@ -585,6 +591,7 @@ class ProjectBundle(BaseModel):
585
591
  features=slots.features,
586
592
  clarifications=slots.clarifications,
587
593
  change_tracking=change_tracking,
594
+ extensions=dict(extensions_data),
588
595
  )
589
596
 
590
597
  @beartype
@@ -663,6 +670,8 @@ class ProjectBundle(BaseModel):
663
670
  progress_callback(total_artifacts, total_artifacts, "bundle.manifest.yaml")
664
671
  manifest_path = bundle_dir / "bundle.manifest.yaml"
665
672
  manifest_data = self.manifest.model_dump(mode="json")
673
+ if self.extensions:
674
+ manifest_data["extensions"] = self.extensions
666
675
  if num_features > 1000:
667
676
  import json
668
677
 
@@ -0,0 +1,183 @@
1
+ """Requirement evidence input models.
2
+
3
+ These models normalize upstream requirement context for validation evidence.
4
+ They do not make SpecFact the authoring system or source of truth for
5
+ requirements.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from enum import StrEnum
11
+ from typing import Any, Literal, cast
12
+
13
+ from beartype import beartype
14
+ from icontract import ensure, require
15
+ from pydantic import BaseModel, ConfigDict, Field
16
+
17
+
18
+ REQUIREMENTS_INPUT_SCHEMA_VERSION = "1"
19
+
20
+
21
+ class RequirementSourceType(StrEnum):
22
+ """Supported upstream source reference types."""
23
+
24
+ ISSUE = "issue"
25
+ DOCUMENT = "document"
26
+ OPENSPEC_CHANGE = "openspec_change"
27
+ SPECKIT_SPEC = "speckit_spec"
28
+ FILE = "file"
29
+ BACKLOG_ITEM = "backlog_item"
30
+
31
+
32
+ class RequirementEvidenceLinkType(StrEnum):
33
+ """Kinds of downstream evidence linked from a requirement input."""
34
+
35
+ ARCHITECTURE = "architecture"
36
+ SPEC = "spec"
37
+ CODE = "code"
38
+ TEST = "test"
39
+ VALIDATION = "validation"
40
+ REQUIREMENT = "requirement"
41
+
42
+
43
+ class RequirementConstraintType(StrEnum):
44
+ """Supported requirement constraint categories."""
45
+
46
+ PERFORMANCE = "performance"
47
+ SECURITY = "security"
48
+ INTEGRATION = "integration"
49
+ COMPLIANCE = "compliance"
50
+ UX = "ux"
51
+ OPERATIONAL = "operational"
52
+
53
+
54
+ class RequirementCompletenessSeverity(StrEnum):
55
+ """Advisory completeness finding severity."""
56
+
57
+ INFO = "info"
58
+ WARNING = "warning"
59
+ ERROR = "error"
60
+
61
+
62
+ @beartype
63
+ class RequirementSourceReference(BaseModel):
64
+ """Reference to an upstream requirement source."""
65
+
66
+ model_config = ConfigDict(use_enum_values=True)
67
+
68
+ source_type: RequirementSourceType = Field(..., description="Type of upstream requirement source")
69
+ locator: str = Field(..., min_length=1, description="Source locator such as URL, file path, or change ID")
70
+ title: str | None = Field(default=None, description="Human-readable source title")
71
+ revision: str | None = Field(default=None, description="Optional source revision, commit, or version")
72
+
73
+
74
+ @beartype
75
+ class BusinessRule(BaseModel):
76
+ """Business rule imported from upstream requirement context."""
77
+
78
+ rule_id: str = Field(..., min_length=1, description="Stable business rule identifier")
79
+ name: str = Field(..., min_length=1, description="Rule name")
80
+ given: str = Field(..., min_length=1, description="Given clause for validation scenario context")
81
+ when: str = Field(..., min_length=1, description="When clause for validation scenario context")
82
+ then: str = Field(..., min_length=1, description="Then clause for validation scenario context")
83
+ priority: str | None = Field(default=None, description="Optional upstream priority such as MoSCoW")
84
+
85
+
86
+ @beartype
87
+ class RequirementConstraint(BaseModel):
88
+ """Constraint imported from upstream requirement context."""
89
+
90
+ model_config = ConfigDict(use_enum_values=True)
91
+
92
+ constraint_id: str = Field(..., min_length=1, description="Stable constraint identifier")
93
+ constraint_type: RequirementConstraintType = Field(..., description="Constraint category")
94
+ statement: str = Field(..., min_length=1, description="Constraint statement")
95
+ validation_criteria: list[str] = Field(default_factory=list, description="Criteria used to validate constraint")
96
+
97
+
98
+ @beartype
99
+ class RequirementEvidenceLink(BaseModel):
100
+ """Link from requirement input to downstream validation evidence."""
101
+
102
+ model_config = ConfigDict(use_enum_values=True)
103
+
104
+ link_type: RequirementEvidenceLinkType = Field(..., description="Evidence target category")
105
+ target: str = Field(..., min_length=1, description="Evidence target locator")
106
+ relation: str = Field(default="references", min_length=1, description="Relationship to the target")
107
+
108
+
109
+ @beartype
110
+ class RequirementCompletenessFinding(BaseModel):
111
+ """Profile-aware completeness finding stored as advisory evidence."""
112
+
113
+ model_config = ConfigDict(use_enum_values=True)
114
+
115
+ profile: str = Field(..., min_length=1, description="Profile that produced this finding")
116
+ severity: RequirementCompletenessSeverity = Field(..., description="Finding severity")
117
+ field_path: str = Field(..., min_length=1, description="Requirement field path")
118
+ message: str = Field(..., min_length=1, description="Human-readable completeness guidance")
119
+
120
+
121
+ @beartype
122
+ class RequirementInput(BaseModel):
123
+ """Normalized requirement context consumed by validation evidence."""
124
+
125
+ schema_version: Literal["1"] = Field(..., description="Requirement input schema version")
126
+ requirement_id: str = Field(..., min_length=1, description="Stable requirement identifier")
127
+ title: str = Field(..., min_length=1, description="Requirement title")
128
+ summary: str | None = Field(default=None, description="Optional upstream requirement summary")
129
+ sources: list[RequirementSourceReference] = Field(
130
+ ...,
131
+ min_length=1,
132
+ description="Upstream requirement source references",
133
+ )
134
+ business_rules: list[BusinessRule] = Field(default_factory=list, description="Imported business rules")
135
+ constraints: list[RequirementConstraint] = Field(default_factory=list, description="Imported constraints")
136
+ evidence_links: list[RequirementEvidenceLink] = Field(default_factory=list, description="Evidence target links")
137
+ completeness_findings: list[RequirementCompletenessFinding] = Field(
138
+ default_factory=list,
139
+ description="Profile-aware advisory completeness findings",
140
+ )
141
+
142
+
143
+ @beartype
144
+ class RequirementsInputExtensionPayload(BaseModel):
145
+ """Serializable ProjectBundle extension payload for requirement inputs."""
146
+
147
+ schema_version: Literal["1"] = Field(..., description="Requirements extension payload schema version")
148
+ requirements: list[RequirementInput] = Field(default_factory=list, description="Requirement input records")
149
+
150
+
151
+ def _payload_has_schema_version(result: dict[str, Any]) -> bool:
152
+ return result.get("schema_version") == REQUIREMENTS_INPUT_SCHEMA_VERSION
153
+
154
+
155
+ def _payload_has_requirements_list(result: dict[str, Any]) -> bool:
156
+ return isinstance(result.get("requirements"), list)
157
+
158
+
159
+ def _payload_is_valid_extension(payload: dict[str, Any]) -> bool:
160
+ try:
161
+ RequirementsInputExtensionPayload.model_validate(payload)
162
+ except ValueError:
163
+ return False
164
+ return True
165
+
166
+
167
+ @beartype
168
+ @require(lambda records: all(isinstance(record, RequirementInput) for record in records))
169
+ @ensure(_payload_has_schema_version)
170
+ @ensure(_payload_has_requirements_list)
171
+ def requirements_input_extension_payload(records: list[RequirementInput]) -> dict[str, Any]:
172
+ """Return a JSON-serializable ProjectBundle extension payload."""
173
+ payload = RequirementsInputExtensionPayload(schema_version=REQUIREMENTS_INPUT_SCHEMA_VERSION, requirements=records)
174
+ return cast(dict[str, Any], payload.model_dump(mode="json"))
175
+
176
+
177
+ @beartype
178
+ @require(lambda payload: isinstance(payload, dict))
179
+ @require(_payload_is_valid_extension)
180
+ @ensure(lambda result: all(isinstance(record, RequirementInput) for record in result))
181
+ def load_requirements_input_extension(payload: dict[str, Any]) -> list[RequirementInput]:
182
+ """Load requirement input records from a ProjectBundle extension payload."""
183
+ return RequirementsInputExtensionPayload.model_validate(payload).requirements
@@ -91,11 +91,26 @@ def _append_explicit_module_roots(roots: list[tuple[str, Path]]) -> None:
91
91
  roots.append(("custom", path))
92
92
 
93
93
 
94
+ def _should_include_workspace_project_root(options: _DiscoveryRootOptions, legacy: bool) -> bool:
95
+ only_user_root_is_explicit = (
96
+ options.user_root is not None
97
+ and options.builtin_root is None
98
+ and options.marketplace_root is None
99
+ and options.custom_root is None
100
+ )
101
+ return options.project_base_path is not None or legacy or only_user_root_is_explicit
102
+
103
+
94
104
  def _discovery_root_list(options: _DiscoveryRootOptions) -> list[tuple[str, Path]]:
95
105
  from specfact_cli.registry.module_packages import get_modules_root, get_workspace_modules_root
96
106
 
107
+ legacy = _resolve_include_legacy_roots(options)
97
108
  effective_builtin_root = options.builtin_root or get_modules_root()
98
- effective_project_root = get_workspace_modules_root(options.project_base_path)
109
+ effective_project_root = (
110
+ get_workspace_modules_root(options.project_base_path)
111
+ if _should_include_workspace_project_root(options, legacy)
112
+ else None
113
+ )
99
114
  effective_user_root = options.user_root or USER_MODULES_ROOT
100
115
  effective_marketplace_root = options.marketplace_root or MARKETPLACE_MODULES_ROOT
101
116
  effective_custom_root = options.custom_root or CUSTOM_MODULES_ROOT
@@ -119,7 +134,6 @@ def _discovery_root_list(options: _DiscoveryRootOptions) -> list[tuple[str, Path
119
134
  ]
120
135
  )
121
136
 
122
- legacy = _resolve_include_legacy_roots(options)
123
137
  if legacy:
124
138
  _append_legacy_module_roots(roots)
125
139
  return roots
@@ -8,17 +8,21 @@ from icontract import ensure, require
8
8
  from specfact_cli.models.module_package import ModulePackageMetadata
9
9
 
10
10
 
11
- VALID_CATEGORIES = frozenset({"core", "project", "backlog", "codebase", "spec", "govern"})
11
+ VALID_CATEGORIES = frozenset({"core", "project", "backlog", "codebase", "spec", "govern", "requirements"})
12
12
  CATEGORY_TO_GROUP_COMMAND: dict[str, str] = {
13
13
  "project": "project",
14
14
  "backlog": "backlog",
15
15
  "codebase": "code",
16
16
  "spec": "spec",
17
17
  "govern": "govern",
18
+ "requirements": "requirements",
18
19
  }
19
20
  LEGACY_GROUP_COMMAND_ALIASES: dict[tuple[str, str], str] = {
20
21
  ("codebase", "codebase"): "code",
21
22
  }
23
+ LEGACY_CATEGORY_ALIASES: dict[tuple[str, str], str] = {
24
+ ("project", "requirements"): "requirements",
25
+ }
22
26
 
23
27
 
24
28
  class ModuleManifestError(Exception):
@@ -71,6 +75,9 @@ def normalize_legacy_bundle_group_command(meta: ModulePackageMetadata) -> Module
71
75
  """Normalize known legacy bundle group values to canonical grouped commands."""
72
76
  if meta.category is None or meta.bundle_group_command is None:
73
77
  return meta
78
+ normalized_category = LEGACY_CATEGORY_ALIASES.get((meta.category, meta.bundle_group_command))
79
+ if normalized_category is not None:
80
+ meta.category = normalized_category
74
81
  normalized = LEGACY_GROUP_COMMAND_ALIASES.get((meta.category, meta.bundle_group_command))
75
82
  if normalized is not None:
76
83
  meta.bundle_group_command = normalized
@@ -0,0 +1,28 @@
1
+ """Requirements context adapter helpers."""
2
+
3
+ from specfact_cli.requirements.context import (
4
+ RequirementContextAdapter,
5
+ RequirementContextCoverageSummary,
6
+ RequirementContextDiagnostic,
7
+ RequirementContextDiagnosticSeverity,
8
+ RequirementContextImportResult,
9
+ attach_requirements_to_bundle,
10
+ inspect_requirement_context_coverage,
11
+ load_requirements_from_bundle,
12
+ normalize_requirement_records,
13
+ validate_requirement_context,
14
+ )
15
+
16
+
17
+ __all__ = [
18
+ "RequirementContextAdapter",
19
+ "RequirementContextCoverageSummary",
20
+ "RequirementContextDiagnostic",
21
+ "RequirementContextDiagnosticSeverity",
22
+ "RequirementContextImportResult",
23
+ "attach_requirements_to_bundle",
24
+ "inspect_requirement_context_coverage",
25
+ "load_requirements_from_bundle",
26
+ "normalize_requirement_records",
27
+ "validate_requirement_context",
28
+ ]