specfact-cli 0.47.11__tar.gz → 0.49.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 (279) hide show
  1. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/PKG-INFO +1 -1
  2. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/pyproject.toml +1 -1
  3. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/bundled-module-registry/index.json +3 -3
  4. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/__init__.py +1 -1
  5. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/__init__.py +1 -1
  6. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/analyzers/code_analyzer.py +3 -2
  7. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/__init__.py +30 -0
  8. specfact_cli-0.49.1/src/specfact_cli/models/requirements.py +183 -0
  9. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/init/module-package.yaml +3 -3
  10. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/init/src/commands.py +21 -10
  11. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/init/src/first_run_selection.py +280 -2
  12. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/module_discovery.py +16 -2
  13. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/.gitignore +0 -0
  14. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/LICENSE +0 -0
  15. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/README.md +0 -0
  16. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/keys/README.md +0 -0
  17. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/keys/module-signing-public.pem +0 -0
  18. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/mappings/node-async.yaml +0 -0
  19. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/mappings/python-async.yaml +0 -0
  20. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/mappings/speckit-default.yaml +0 -0
  21. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/schemas/deviation.schema.json +0 -0
  22. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/schemas/plan.schema.json +0 -0
  23. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/schemas/protocol.schema.json +0 -0
  24. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/github-action.yml.j2 +0 -0
  25. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/persona/architect.md.j2 +0 -0
  26. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/persona/developer.md.j2 +0 -0
  27. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/persona/product-owner.md.j2 +0 -0
  28. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/plan.bundle.yaml.j2 +0 -0
  29. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/policies/kanban.yaml +0 -0
  30. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/policies/mixed.yaml +0 -0
  31. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/policies/safe.yaml +0 -0
  32. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/policies/scrum.yaml +0 -0
  33. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/pr-template.md.j2 +0 -0
  34. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/protocol.yaml.j2 +0 -0
  35. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/resources/templates/telemetry.yaml.example +0 -0
  36. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/__main__.py +0 -0
  37. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/adapters/__init__.py +0 -0
  38. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/adapters/ado.py +0 -0
  39. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/adapters/backlog_base.py +0 -0
  40. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/adapters/base.py +0 -0
  41. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/adapters/github.py +0 -0
  42. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/adapters/openspec.py +0 -0
  43. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/adapters/openspec_parser.py +0 -0
  44. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/adapters/registry.py +0 -0
  45. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/adapters/speckit.py +0 -0
  46. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/agents/__init__.py +0 -0
  47. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/agents/analyze_agent.py +0 -0
  48. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/agents/base.py +0 -0
  49. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/agents/plan_agent.py +0 -0
  50. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/agents/registry.py +0 -0
  51. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/agents/sync_agent.py +0 -0
  52. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/analyzers/__init__.py +0 -0
  53. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/analyzers/ambiguity_scanner.py +0 -0
  54. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/analyzers/constitution_evidence_extractor.py +0 -0
  55. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/analyzers/contract_extractor.py +0 -0
  56. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/analyzers/control_flow_analyzer.py +0 -0
  57. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/analyzers/graph_analyzer.py +0 -0
  58. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/analyzers/relationship_mapper.py +0 -0
  59. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/analyzers/requirement_extractor.py +0 -0
  60. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/analyzers/test_pattern_extractor.py +0 -0
  61. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/backlog/__init__.py +0 -0
  62. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/backlog/adapters/__init__.py +0 -0
  63. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/backlog/adapters/base.py +0 -0
  64. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/backlog/converter.py +0 -0
  65. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/backlog/filters.py +0 -0
  66. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/backlog/mappers/__init__.py +0 -0
  67. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/backlog/mappers/ado_mapper.py +0 -0
  68. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/backlog/mappers/base.py +0 -0
  69. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/backlog/mappers/github_mapper.py +0 -0
  70. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/backlog/mappers/template_config.py +0 -0
  71. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/cli.py +0 -0
  72. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/__init__.py +0 -0
  73. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/_bundle_shim.py +0 -0
  74. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/analyze.py +0 -0
  75. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/contract_cmd.py +0 -0
  76. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/drift.py +0 -0
  77. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/enforce.py +0 -0
  78. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/generate.py +0 -0
  79. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/import_cmd.py +0 -0
  80. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/init.py +0 -0
  81. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/migrate.py +0 -0
  82. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/plan.py +0 -0
  83. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/project_cmd.py +0 -0
  84. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/repro.py +0 -0
  85. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/sdd.py +0 -0
  86. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/spec.py +0 -0
  87. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/sync.py +0 -0
  88. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/update.py +0 -0
  89. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/commands/validate.py +0 -0
  90. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/common/__init__.py +0 -0
  91. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/common/bundle_factory.py +0 -0
  92. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/common/logger_setup.py +0 -0
  93. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/common/logging_utils.py +0 -0
  94. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/common/text_utils.py +0 -0
  95. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/common/utils.py +0 -0
  96. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/comparators/__init__.py +0 -0
  97. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/comparators/plan_comparator.py +0 -0
  98. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/contracts/__init__.py +0 -0
  99. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/contracts/crosshair_props.py +0 -0
  100. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/contracts/module_interface.py +0 -0
  101. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/enrichers/constitution_enricher.py +0 -0
  102. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/enrichers/plan_enricher.py +0 -0
  103. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/generators/__init__.py +0 -0
  104. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/generators/contract_generator.py +0 -0
  105. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/generators/openapi_extractor.py +0 -0
  106. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/generators/persona_exporter.py +0 -0
  107. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/generators/plan_generator.py +0 -0
  108. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/generators/protocol_generator.py +0 -0
  109. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/generators/report_generator.py +0 -0
  110. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/generators/task_generator.py +0 -0
  111. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/generators/test_to_openapi.py +0 -0
  112. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/generators/workflow_generator.py +0 -0
  113. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/groups/__init__.py +0 -0
  114. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/groups/codebase_group.py +0 -0
  115. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/groups/govern_group.py +0 -0
  116. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/groups/member_group.py +0 -0
  117. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/groups/project_group.py +0 -0
  118. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/groups/spec_group.py +0 -0
  119. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/importers/__init__.py +0 -0
  120. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/importers/speckit_converter.py +0 -0
  121. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/importers/speckit_scanner.py +0 -0
  122. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/integrations/__init__.py +0 -0
  123. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/integrations/specmatic.py +0 -0
  124. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/merge/__init__.py +0 -0
  125. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/merge/resolver.py +0 -0
  126. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/migrations/__init__.py +0 -0
  127. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/migrations/plan_migrator.py +0 -0
  128. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/backlog_item.py +0 -0
  129. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/bridge.py +0 -0
  130. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/capabilities.py +0 -0
  131. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/change.py +0 -0
  132. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/contract.py +0 -0
  133. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/deviation.py +0 -0
  134. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/dor_config.py +0 -0
  135. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/enforcement.py +0 -0
  136. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/module_package.py +0 -0
  137. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/persona_template.py +0 -0
  138. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/plan.py +0 -0
  139. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/project.py +0 -0
  140. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/protocol.py +0 -0
  141. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/quality.py +0 -0
  142. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/sdd.py +0 -0
  143. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/source_tracking.py +0 -0
  144. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/task.py +0 -0
  145. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/models/validation.py +0 -0
  146. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modes/__init__.py +0 -0
  147. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modes/detector.py +0 -0
  148. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modes/router.py +0 -0
  149. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/__init__.py +0 -0
  150. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/_bundle_import.py +0 -0
  151. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/init/src/__init__.py +0 -0
  152. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/init/src/app.py +0 -0
  153. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/module_io_shim.py +0 -0
  154. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/module_registry/module-package.yaml +0 -0
  155. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/module_registry/src/__init__.py +0 -0
  156. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/module_registry/src/app.py +0 -0
  157. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/module_registry/src/commands.py +0 -0
  158. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/upgrade/module-package.yaml +0 -0
  159. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/upgrade/src/__init__.py +0 -0
  160. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/upgrade/src/app.py +0 -0
  161. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/modules/upgrade/src/commands.py +0 -0
  162. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/parsers/__init__.py +0 -0
  163. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/parsers/persona_importer.py +0 -0
  164. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/__init__.py +0 -0
  165. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/alias_manager.py +0 -0
  166. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/bootstrap.py +0 -0
  167. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/bridge_registry.py +0 -0
  168. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/crypto_validator.py +0 -0
  169. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/custom_registries.py +0 -0
  170. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/dependency_resolver.py +0 -0
  171. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/extension_registry.py +0 -0
  172. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/help_cache.py +0 -0
  173. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/marketplace_client.py +0 -0
  174. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/metadata.py +0 -0
  175. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/module_availability.py +0 -0
  176. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/module_grouping.py +0 -0
  177. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/module_installer.py +0 -0
  178. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/module_lifecycle.py +0 -0
  179. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/module_packages.py +0 -0
  180. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/module_security.py +0 -0
  181. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/module_state.py +0 -0
  182. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/registry/registry.py +0 -0
  183. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/resources/semgrep/async.yml +0 -0
  184. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/resources/semgrep/code-quality.yml +0 -0
  185. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/resources/semgrep/feature-detection.yml +0 -0
  186. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/runtime.py +0 -0
  187. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/__init__.py +0 -0
  188. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/bridge_probe.py +0 -0
  189. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/bridge_sync.py +0 -0
  190. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/bridge_sync_openspec_md_parse.py +0 -0
  191. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/bridge_sync_requirement_from_proposal.py +0 -0
  192. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/bridge_sync_requirement_helpers.py +0 -0
  193. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/bridge_sync_tasks_from_proposal.py +0 -0
  194. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/bridge_sync_what_changes_format.py +0 -0
  195. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/bridge_sync_write_openspec_from_proposal.py +0 -0
  196. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/bridge_watch.py +0 -0
  197. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/change_detector.py +0 -0
  198. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/code_to_spec.py +0 -0
  199. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/drift_detector.py +0 -0
  200. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/repository_sync.py +0 -0
  201. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/spec_to_code.py +0 -0
  202. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/spec_to_tests.py +0 -0
  203. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/watcher.py +0 -0
  204. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/sync/watcher_enhanced.py +0 -0
  205. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/telemetry.py +0 -0
  206. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/templates/__init__.py +0 -0
  207. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/templates/defaults/defect_v1.yaml +0 -0
  208. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/templates/defaults/enabler_v1.yaml +0 -0
  209. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/templates/defaults/spike_v1.yaml +0 -0
  210. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/templates/defaults/user_story_v1.yaml +0 -0
  211. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/templates/frameworks/scrum/user_story_v1.yaml +0 -0
  212. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/templates/personas/product-owner/user_story_v1.yaml +0 -0
  213. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/templates/providers/ado/work_item_v1.yaml +0 -0
  214. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/templates/registry.py +0 -0
  215. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/templates/specification_templates.py +0 -0
  216. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/__init__.py +0 -0
  217. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/acceptance_criteria.py +0 -0
  218. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/auth_tokens.py +0 -0
  219. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/bundle_converters.py +0 -0
  220. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/bundle_loader.py +0 -0
  221. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/code_change_detector.py +0 -0
  222. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/console.py +0 -0
  223. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/content_sanitizer.py +0 -0
  224. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/context_detection.py +0 -0
  225. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/contract_predicates.py +0 -0
  226. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/enrichment_context.py +0 -0
  227. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/enrichment_parser.py +0 -0
  228. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/env_manager.py +0 -0
  229. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/feature_keys.py +0 -0
  230. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/git.py +0 -0
  231. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/github_annotations.py +0 -0
  232. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/icontract_helpers.py +0 -0
  233. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/ide_setup.py +0 -0
  234. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/incremental_check.py +0 -0
  235. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/metadata.py +0 -0
  236. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/optional_deps.py +0 -0
  237. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/performance.py +0 -0
  238. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/persona_ownership.py +0 -0
  239. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/progress.py +0 -0
  240. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/progressive_disclosure.py +0 -0
  241. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/project_artifact_write.py +0 -0
  242. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/prompts.py +0 -0
  243. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/sdd_discovery.py +0 -0
  244. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/source_scanner.py +0 -0
  245. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/startup_checks.py +0 -0
  246. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/structure.py +0 -0
  247. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/structured_io.py +0 -0
  248. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/suggestions.py +0 -0
  249. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/terminal.py +0 -0
  250. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/utils/yaml_utils.py +0 -0
  251. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validation/__init__.py +0 -0
  252. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validation/command_audit.py +0 -0
  253. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/__init__.py +0 -0
  254. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/agile_validation.py +0 -0
  255. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/change_proposal_integration.py +0 -0
  256. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/cli_first_validator.py +0 -0
  257. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/contract_validator.py +0 -0
  258. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/fsm.py +0 -0
  259. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/repro_checker.py +0 -0
  260. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/schema.py +0 -0
  261. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/__init__.py +0 -0
  262. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/contract_populator.py +0 -0
  263. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/crosshair_runner.py +0 -0
  264. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/crosshair_summary.py +0 -0
  265. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/dependency_installer.py +0 -0
  266. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/framework_detector.py +0 -0
  267. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/frameworks/__init__.py +0 -0
  268. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/frameworks/base.py +0 -0
  269. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/frameworks/django.py +0 -0
  270. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/frameworks/drf.py +0 -0
  271. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/frameworks/fastapi.py +0 -0
  272. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/frameworks/flask.py +0 -0
  273. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/harness_generator.py +0 -0
  274. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/models.py +0 -0
  275. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/orchestrator.py +0 -0
  276. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/specmatic_runner.py +0 -0
  277. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/validators/sidecar/unannotated_detector.py +0 -0
  278. {specfact_cli-0.47.11 → specfact_cli-0.49.1}/src/specfact_cli/versioning/__init__.py +0 -0
  279. {specfact_cli-0.47.11 → specfact_cli-0.49.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.47.11
3
+ Version: 0.49.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.47.11"
7
+ version = "0.49.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"
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "modules": [
3
3
  {
4
- "checksum_sha256": "3a563335d7a5e16e6e9ec975d6e5c77ff550d8880474eca03713b43e97d39a4a",
5
- "download_url": "https://github.com/nold-ai/specfact-cli/releases/download/init-0.1.37.tar.gz",
4
+ "checksum_sha256": "2ffe401e068883086f2df2beed8e9d328db9f0802deb3c69212b0594bfa1be75",
5
+ "download_url": "https://github.com/nold-ai/specfact-cli/releases/download/init-0.1.41.tar.gz",
6
6
  "id": "init",
7
- "latest_version": "0.1.37"
7
+ "latest_version": "0.1.41"
8
8
  },
9
9
  {
10
10
  "checksum_sha256": "35c592374b209224af9a826c21efa66947cc16bf680b20ee0463f44bee4f9b59",
@@ -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.47.11"
6
+ __version__ = "0.49.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.47.11"
79
+ __version__ = "0.49.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
  ]
@@ -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
@@ -1,5 +1,5 @@
1
1
  name: init
2
- version: 0.1.37
2
+ version: 0.1.41
3
3
  commands:
4
4
  - init
5
5
  category: core
@@ -17,5 +17,5 @@ publisher:
17
17
  description: Initialize SpecFact workspace and bootstrap local configuration.
18
18
  license: Apache-2.0
19
19
  integrity:
20
- checksum: sha256:8741e8fa3408bd38e7d65d0784a25466369955dd9f16f1981a52c0e1550afbe0
21
- signature: kPAMdqpcAr92gr+DwxWibXfD0mgCLSb78EwGzoXH3fHct7xss8zt/SFvJLVZ0qkYHA8/4Nu6ls0iihRN9DXhCw==
20
+ checksum: sha256:7ad9c0b623f52a55b45f35adf9576bea1fd47edcd3005ed2354188a6a6ea20f5
21
+ signature: 7ED3ulYnu2VsJvPN/rEVLFHdVdBoiqJg1a8kR1FpWTmz9ZILrT/+NYq3CtnwGIvZscD/8CEBLBqKt1+0fCqZCQ==
@@ -48,14 +48,7 @@ from specfact_cli.utils.ide_setup import (
48
48
  )
49
49
 
50
50
 
51
- VALID_PROFILES: frozenset[str] = frozenset(
52
- {
53
- "solo-developer",
54
- "backlog-team",
55
- "api-first-team",
56
- "enterprise-full-stack",
57
- }
58
- )
51
+ VALID_PROFILES: frozenset[str] = frozenset(first_run_selection.get_valid_profile_names())
59
52
  PROFILE_BUNDLES: dict[str, list[str]] = first_run_selection.PROFILE_PRESETS
60
53
 
61
54
  install_bundles_for_init = first_run_selection.install_bundles_for_init
@@ -709,6 +702,21 @@ def init_ide(
709
702
  console.print(f"[green]Updated VS Code settings:[/green] {settings_path}")
710
703
 
711
704
 
705
+ def _write_profile_config_or_exit(repo_path: Path, profile: str) -> None:
706
+ try:
707
+ first_run_selection.write_profile_config(repo_path, profile)
708
+ except ValueError as e:
709
+ console.print(f"[red]Error:[/red] {e}")
710
+ raise typer.Exit(1) from e
711
+
712
+
713
+ def _apply_explicit_profile_or_install(repo_path: Path, profile: str | None, install: str | None) -> list[str]:
714
+ enabled_module_ids = _apply_profile_or_install_bundles(profile, install)
715
+ if profile is not None:
716
+ _write_profile_config_or_exit(repo_path, profile)
717
+ return enabled_module_ids
718
+
719
+
712
720
  @app.callback(invoke_without_command=True)
713
721
  @require(lambda repo: _is_valid_repo_path(repo), "Repo path must exist and be directory")
714
722
  @ensure(lambda result: result is None, "Command should return None")
@@ -725,7 +733,10 @@ def init(
725
733
  profile: str | None = typer.Option(
726
734
  None,
727
735
  "--profile",
728
- help="First-run profile preset: solo-developer, backlog-team, api-first-team, enterprise-full-stack",
736
+ help=(
737
+ "Validation tier or legacy workflow preset: solo, startup, mid_size, enterprise, "
738
+ "solo-developer, backlog-team, api-first-team, enterprise-full-stack"
739
+ ),
729
740
  ),
730
741
  install: str | None = typer.Option(
731
742
  None,
@@ -750,7 +761,7 @@ def init(
750
761
 
751
762
  enabled_module_ids: list[str] = []
752
763
  if profile is not None or install is not None:
753
- enabled_module_ids = _apply_profile_or_install_bundles(profile, install)
764
+ enabled_module_ids = _apply_explicit_profile_or_install(repo_path, profile, install)
754
765
  elif is_first_run(user_root=INIT_USER_MODULES_ROOT) and is_non_interactive():
755
766
  console.print(
756
767
  "[red]Error:[/red] In CI/CD (non-interactive) mode, first-run init requires "