requirements-as-code 0.7.2__tar.gz → 0.7.3__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 (179) hide show
  1. {requirements_as_code-0.7.2/requirements_as_code.egg-info → requirements_as_code-0.7.3}/PKG-INFO +148 -1
  2. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/README.md +147 -0
  3. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-016-relationships-as-structural-references.md +2 -0
  4. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/cli.py +37 -1
  5. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/outputs.py +70 -0
  6. requirements_as_code-0.7.3/rac/portfolio.py +250 -0
  7. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/relationships.py +125 -21
  8. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3/requirements_as_code.egg-info}/PKG-INFO +148 -1
  9. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/requirements_as_code.egg-info/SOURCES.txt +13 -0
  10. requirements_as_code-0.7.3/tests/fixtures/portfolio_summary/all_types/adr.md +13 -0
  11. requirements_as_code-0.7.3/tests/fixtures/portfolio_summary/all_types/design.md +17 -0
  12. requirements_as_code-0.7.3/tests/fixtures/portfolio_summary/all_types/prompt.md +17 -0
  13. requirements_as_code-0.7.3/tests/fixtures/portfolio_summary/all_types/req.md +17 -0
  14. requirements_as_code-0.7.3/tests/fixtures/portfolio_summary/all_types/roadmap.md +9 -0
  15. requirements_as_code-0.7.3/tests/fixtures/portfolio_summary/all_types/unknown.md +3 -0
  16. requirements_as_code-0.7.3/tests/fixtures/portfolio_summary/broken_rels/source.md +13 -0
  17. requirements_as_code-0.7.3/tests/fixtures/portfolio_summary/invalid_known/req-no-title.md +19 -0
  18. requirements_as_code-0.7.3/tests/fixtures/portfolio_summary/unknown_only/unknown.md +3 -0
  19. requirements_as_code-0.7.3/tests/fixtures/portfolio_summary/valid_clean/adr-001.md +25 -0
  20. requirements_as_code-0.7.3/tests/fixtures/portfolio_summary/valid_clean/req-001.md +26 -0
  21. requirements_as_code-0.7.3/tests/test_portfolio.py +328 -0
  22. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/.github/workflows/python-publish.yml +0 -0
  23. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/.gitignore +0 -0
  24. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/LICENSE +0 -0
  25. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/examples/example_dashboard_v1.md +0 -0
  26. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/examples/example_dashboard_v2.md +0 -0
  27. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-001-markdown-first.md +0 -0
  28. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-002-ai-optional.md +0 -0
  29. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-003-structured-outputs-first.md +0 -0
  30. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-004-artifact-model.md +0 -0
  31. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-005-cli-first.md +0 -0
  32. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-006-ingest-over-rewrite.md +0 -0
  33. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-007-json-contract-stability.md +0 -0
  34. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-008-agent-ready-architecture.md +0 -0
  35. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-009-ai-assisted-development.md +0 -0
  36. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-010-documents-are-not-artifacts.md +0 -0
  37. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-011-file-first-pipeline.md +0 -0
  38. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-012-open-core-strategy.md +0 -0
  39. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-013-leverage-existing-source-control-systems.md +0 -0
  40. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-014-viewer-agnostic-knowledge-artifacts.md +0 -0
  41. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-015-explorer-as-consumer.md +0 -0
  42. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-017-rac-managed-knowledge-not-work.md +0 -0
  43. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/designs/explorer-command-surface.md +0 -0
  44. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/designs/explorer-first-run-experience.md +0 -0
  45. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/designs/explorer-health-model.md +0 -0
  46. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/designs/explorer-import-workflow.md +0 -0
  47. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/designs/explorer-knowledge-graph.md +0 -0
  48. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/designs/explorer-visual-system.md +0 -0
  49. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/future/v1.0-workspace-analysis.md +0 -0
  50. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/future/v1.1-review-engine.md +0 -0
  51. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/future/v1.2-mcp-server.md +0 -0
  52. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/future/v1.4-claude-skills.md +0 -0
  53. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/future/v1.4-python-sdk.md +0 -0
  54. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/prompt/rac-agent-compression.md +0 -0
  55. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/prompt/rac-agent-instructions.md +0 -0
  56. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/prompt/rac-agent-release-gate-major.md +0 -0
  57. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/prompt/rac-agent-release-gate-minor.md +0 -0
  58. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/prompt/rac-agent-session-start.md +0 -0
  59. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/archive/v0.5-decisions.md +0 -0
  60. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/archive/v0.7-prompts.md +0 -0
  61. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.2-stats.md +0 -0
  62. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.3-ingest.md +0 -0
  63. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.3.1-formats.md +0 -0
  64. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.4-inspect.md +0 -0
  65. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.4.1-expansion.md +0 -0
  66. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.4.1-inspect-expansion.md +0 -0
  67. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.4.2-decision-metadata.md +0 -0
  68. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.5.0-artifact-improvement.md +0 -0
  69. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.5.1-guided-improvement.md +0 -0
  70. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.5.2-schema.md +0 -0
  71. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.6.0-roadmap-artifacts.md +0 -0
  72. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.6.1-roadmap-improvement.md +0 -0
  73. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.6.2-prompt-artifact.md +0 -0
  74. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.6.3-design-artifacts.md +0 -0
  75. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.7.0-relationship-metadata.md +0 -0
  76. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.7.1-relationship-inspection.md +0 -0
  77. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.7.2-relationship-validation.md +0 -0
  78. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.7.3-repo-intelligence.md +0 -0
  79. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.7.4-repo-indexing.md +0 -0
  80. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.8.0-service-api.md +0 -0
  81. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.8.1-repository-model.md +0 -0
  82. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.8.2-interactive-runtime-readiness.md +0 -0
  83. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.8.3-integration-freeze.md +0 -0
  84. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.9.0-explorer-foundation.md +0 -0
  85. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.9.1-explorer-experience.md +0 -0
  86. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.9.2-knowledge-operations.md +0 -0
  87. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.9.3-intelligence-views.md +0 -0
  88. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/pyproject.toml +0 -0
  89. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/__init__.py +0 -0
  90. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/artifacts.py +0 -0
  91. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/classification.py +0 -0
  92. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/diff.py +0 -0
  93. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/fs.py +0 -0
  94. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/improve.py +0 -0
  95. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/ingest.py +0 -0
  96. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/inspect.py +0 -0
  97. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/models.py +0 -0
  98. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/parser.py +0 -0
  99. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/schema.py +0 -0
  100. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/stats.py +0 -0
  101. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/validate.py +0 -0
  102. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/requirements_as_code.egg-info/dependency_links.txt +0 -0
  103. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/requirements_as_code.egg-info/entry_points.txt +0 -0
  104. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/requirements_as_code.egg-info/requires.txt +0 -0
  105. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/requirements_as_code.egg-info/top_level.txt +0 -0
  106. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/setup.cfg +0 -0
  107. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/conftest.py +0 -0
  108. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/decision/bad_category.md +0 -0
  109. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/decision/bad_status.md +0 -0
  110. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/decision/minimal.md +0 -0
  111. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/decision/portfolio/01_accepted_arch.md +0 -0
  112. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/decision/portfolio/02_proposed_process.md +0 -0
  113. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/decision/portfolio/03_no_metadata.md +0 -0
  114. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/decision/with_metadata.md +0 -0
  115. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/design/minimal.md +0 -0
  116. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/design/missing_constraints.md +0 -0
  117. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/design/valid.md +0 -0
  118. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/diff/new.md +0 -0
  119. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/diff/old.md +0 -0
  120. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/ingest/sample.md +0 -0
  121. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/inspect/ambiguous.md +0 -0
  122. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/inspect/decision.md +0 -0
  123. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/inspect/nested/another_requirement.md +0 -0
  124. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/inspect/requirement.md +0 -0
  125. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/invalid/duplicate_ids.md +0 -0
  126. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/invalid/empty_req_text.md +0 -0
  127. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/invalid/malformed_id.md +0 -0
  128. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/invalid/missing_id.md +0 -0
  129. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/invalid/missing_problem.md +0 -0
  130. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/invalid/missing_requirements.md +0 -0
  131. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/invalid/missing_title.md +0 -0
  132. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/invalid/multiple_titles.md +0 -0
  133. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/no_relationships/decision.md +0 -0
  134. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/no_relationships/requirement.md +0 -0
  135. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/portfolio/broken.md +0 -0
  136. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/portfolio/feature_a.md +0 -0
  137. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/portfolio/feature_b.md +0 -0
  138. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/portfolio/sub/feature_c.md +0 -0
  139. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/prompt/minimal.md +0 -0
  140. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/prompt/missing_output.md +0 -0
  141. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/prompt/valid.md +0 -0
  142. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationship_validation/ambiguous_target/adr-004-alt.md +0 -0
  143. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationship_validation/ambiguous_target/adr-004.md +0 -0
  144. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationship_validation/ambiguous_target/req-001.md +0 -0
  145. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationship_validation/broken/search.md +0 -0
  146. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationship_validation/duplicate/adr-004-alt.md +0 -0
  147. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationship_validation/duplicate/adr-004.md +0 -0
  148. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationship_validation/resolved/adr-004.md +0 -0
  149. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationship_validation/resolved/req-001.md +0 -0
  150. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationship_validation/resolved/roadmap-q3.md +0 -0
  151. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationship_validation/self_reference/adr-004.md +0 -0
  152. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationships/decision_with_links.md +0 -0
  153. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationships/design_with_links.md +0 -0
  154. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationships/prompt_with_links.md +0 -0
  155. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationships/requirement_with_links.md +0 -0
  156. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationships/roadmap_with_links.md +0 -0
  157. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/roadmap/minimal.md +0 -0
  158. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/roadmap/missing_initiatives.md +0 -0
  159. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/roadmap/valid.md +0 -0
  160. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/valid/bullet_requirements.md +0 -0
  161. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/valid/feature.md +0 -0
  162. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/valid/minimal.md +0 -0
  163. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/valid/warnings.md +0 -0
  164. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_cli.py +0 -0
  165. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_decision_metadata.py +0 -0
  166. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_design.py +0 -0
  167. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_diff.py +0 -0
  168. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_improve.py +0 -0
  169. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_ingest.py +0 -0
  170. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_inspect.py +0 -0
  171. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_parser.py +0 -0
  172. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_prompt.py +0 -0
  173. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_relationship_validation.py +0 -0
  174. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_relationships.py +0 -0
  175. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_relationships_cmd.py +0 -0
  176. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_roadmap.py +0 -0
  177. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_schema.py +0 -0
  178. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_stats.py +0 -0
  179. {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_validate.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: requirements-as-code
3
- Version: 0.7.2
3
+ Version: 0.7.3
4
4
  Summary: RAC — lint and diff product requirements written in Markdown.
5
5
  Author: tcballard
6
6
  License-Expression: MIT
@@ -935,6 +935,153 @@ Notes:
935
935
 
936
936
  ---
937
937
 
938
+ ## Portfolio
939
+
940
+ A single-command repository intelligence summary: artifact counts, validation
941
+ health, completeness, relationship integrity, actionable attention items, and an
942
+ overall health score — without manually combining output from multiple commands.
943
+
944
+ ```bash
945
+ rac portfolio ./docs
946
+ rac portfolio ./docs --json
947
+ rac portfolio ./docs --top-level # don't recurse into subdirectories
948
+ ```
949
+
950
+ ```text
951
+ Repository Summary
952
+ ==================
953
+
954
+ Directory: ./docs
955
+ Artifacts: 42
956
+
957
+ By Type
958
+ -------
959
+
960
+ Requirement 18
961
+ Decision 12
962
+ Roadmap 5
963
+ Prompt 4
964
+ Design 2
965
+ Unknown 1
966
+
967
+ Validation
968
+ ----------
969
+
970
+ Valid: 40
971
+ Invalid: 2
972
+
973
+ Completeness
974
+ ------------
975
+
976
+ 78% (94 / 120 recommended slots filled)
977
+
978
+ Relationships
979
+ -------------
980
+
981
+ Total: 65
982
+ Valid: 63
983
+ Broken: 2
984
+ Orphaned: 4
985
+ Coverage: 71%
986
+
987
+ Attention (4 items)
988
+ ----------
989
+
990
+ ✗ search
991
+ Validation errors: missing-requirements
992
+ ! adr-004
993
+ Missing recommended sections: Alternatives Considered
994
+ ! q3-roadmap
995
+ Related Requirements references missing artifact: REQ-999
996
+ ! req-041
997
+ Missing recommended sections: Risks
998
+
999
+ Health Score
1000
+ ------------
1001
+
1002
+ 87 / 100
1003
+ ```
1004
+
1005
+ `--json` returns the stable machine contract (all fields present regardless of
1006
+ content, versioned with `schema_version`):
1007
+
1008
+ ```json
1009
+ {
1010
+ "schema_version": "1",
1011
+ "directory": "./docs",
1012
+ "recursive": true,
1013
+ "artifacts": {
1014
+ "total": 42,
1015
+ "by_type": {
1016
+ "requirement": 18,
1017
+ "decision": 12,
1018
+ "roadmap": 5,
1019
+ "prompt": 4,
1020
+ "design": 2,
1021
+ "unknown": 1
1022
+ }
1023
+ },
1024
+ "validation": { "valid": 40, "invalid": 2 },
1025
+ "completeness": { "recommended_slots": 120, "filled": 94, "ratio": 0.7833 },
1026
+ "relationships": {
1027
+ "total": 65,
1028
+ "valid": 63,
1029
+ "broken": 2,
1030
+ "orphaned": 4,
1031
+ "coverage": 0.7143
1032
+ },
1033
+ "attention": [
1034
+ {
1035
+ "path": "requirements/search.md",
1036
+ "identifier": "search",
1037
+ "severity": "error",
1038
+ "code": "invalid-artifact",
1039
+ "message": "Validation errors: missing-requirements"
1040
+ },
1041
+ {
1042
+ "path": "roadmaps/q3-roadmap.md",
1043
+ "identifier": "q3-roadmap",
1044
+ "severity": "warning",
1045
+ "code": "broken-relationship",
1046
+ "message": "Related Requirements references missing artifact: REQ-999"
1047
+ }
1048
+ ],
1049
+ "health": { "score": 87 }
1050
+ }
1051
+ ```
1052
+
1053
+ **Health score formula** (deterministic, no AI):
1054
+
1055
+ ```
1056
+ score = round(100 × (0.5 × validity + 0.25 × completeness + 0.25 × rel_integrity))
1057
+ ```
1058
+
1059
+ where each sub-score is a simple ratio that defaults to `1.0` when its
1060
+ denominator is zero, so an empty repository always scores 100.
1061
+
1062
+ Notes:
1063
+
1064
+ - **Advisory command.** `rac portfolio` always exits `0` when a summary is
1065
+ produced (`2` for usage errors — not a directory). For CI hard gates, use
1066
+ `rac relationships --validate` (exits `1` on broken refs).
1067
+ - **Attention severity.** `error` means the artifact is structurally invalid;
1068
+ `warning` means it is valid but needs attention (missing recommended sections
1069
+ or a stale relationship reference). Items are ordered errors-first, then by
1070
+ path, then by code — deterministically.
1071
+ - **`identifier`** is the artifact's canonical identifier (the same one
1072
+ `rac relationships --validate` resolves against): an explicit `## ID`, else a
1073
+ recognised `TYPE-NNN` filename prefix, else the filename stem.
1074
+ - **`rac stats` vs `rac portfolio`.** `rac stats` provides per-feature
1075
+ requirement and metric breakdowns for requirement-focused portfolios.
1076
+ `rac portfolio` provides a whole-repository intelligence rollup across all
1077
+ artifact types.
1078
+ - **Orphaned** means no other artifact holds a resolved inbound reference to
1079
+ it — the artifact may still declare outbound relationships.
1080
+ - **Coverage** is the fraction of known (non-unknown) artifacts that declare
1081
+ at least one outbound relationship section.
1082
+
1083
+ ---
1084
+
938
1085
  ## Review (Planned)
939
1086
 
940
1087
  AI-assisted product review.
@@ -895,6 +895,153 @@ Notes:
895
895
 
896
896
  ---
897
897
 
898
+ ## Portfolio
899
+
900
+ A single-command repository intelligence summary: artifact counts, validation
901
+ health, completeness, relationship integrity, actionable attention items, and an
902
+ overall health score — without manually combining output from multiple commands.
903
+
904
+ ```bash
905
+ rac portfolio ./docs
906
+ rac portfolio ./docs --json
907
+ rac portfolio ./docs --top-level # don't recurse into subdirectories
908
+ ```
909
+
910
+ ```text
911
+ Repository Summary
912
+ ==================
913
+
914
+ Directory: ./docs
915
+ Artifacts: 42
916
+
917
+ By Type
918
+ -------
919
+
920
+ Requirement 18
921
+ Decision 12
922
+ Roadmap 5
923
+ Prompt 4
924
+ Design 2
925
+ Unknown 1
926
+
927
+ Validation
928
+ ----------
929
+
930
+ Valid: 40
931
+ Invalid: 2
932
+
933
+ Completeness
934
+ ------------
935
+
936
+ 78% (94 / 120 recommended slots filled)
937
+
938
+ Relationships
939
+ -------------
940
+
941
+ Total: 65
942
+ Valid: 63
943
+ Broken: 2
944
+ Orphaned: 4
945
+ Coverage: 71%
946
+
947
+ Attention (4 items)
948
+ ----------
949
+
950
+ ✗ search
951
+ Validation errors: missing-requirements
952
+ ! adr-004
953
+ Missing recommended sections: Alternatives Considered
954
+ ! q3-roadmap
955
+ Related Requirements references missing artifact: REQ-999
956
+ ! req-041
957
+ Missing recommended sections: Risks
958
+
959
+ Health Score
960
+ ------------
961
+
962
+ 87 / 100
963
+ ```
964
+
965
+ `--json` returns the stable machine contract (all fields present regardless of
966
+ content, versioned with `schema_version`):
967
+
968
+ ```json
969
+ {
970
+ "schema_version": "1",
971
+ "directory": "./docs",
972
+ "recursive": true,
973
+ "artifacts": {
974
+ "total": 42,
975
+ "by_type": {
976
+ "requirement": 18,
977
+ "decision": 12,
978
+ "roadmap": 5,
979
+ "prompt": 4,
980
+ "design": 2,
981
+ "unknown": 1
982
+ }
983
+ },
984
+ "validation": { "valid": 40, "invalid": 2 },
985
+ "completeness": { "recommended_slots": 120, "filled": 94, "ratio": 0.7833 },
986
+ "relationships": {
987
+ "total": 65,
988
+ "valid": 63,
989
+ "broken": 2,
990
+ "orphaned": 4,
991
+ "coverage": 0.7143
992
+ },
993
+ "attention": [
994
+ {
995
+ "path": "requirements/search.md",
996
+ "identifier": "search",
997
+ "severity": "error",
998
+ "code": "invalid-artifact",
999
+ "message": "Validation errors: missing-requirements"
1000
+ },
1001
+ {
1002
+ "path": "roadmaps/q3-roadmap.md",
1003
+ "identifier": "q3-roadmap",
1004
+ "severity": "warning",
1005
+ "code": "broken-relationship",
1006
+ "message": "Related Requirements references missing artifact: REQ-999"
1007
+ }
1008
+ ],
1009
+ "health": { "score": 87 }
1010
+ }
1011
+ ```
1012
+
1013
+ **Health score formula** (deterministic, no AI):
1014
+
1015
+ ```
1016
+ score = round(100 × (0.5 × validity + 0.25 × completeness + 0.25 × rel_integrity))
1017
+ ```
1018
+
1019
+ where each sub-score is a simple ratio that defaults to `1.0` when its
1020
+ denominator is zero, so an empty repository always scores 100.
1021
+
1022
+ Notes:
1023
+
1024
+ - **Advisory command.** `rac portfolio` always exits `0` when a summary is
1025
+ produced (`2` for usage errors — not a directory). For CI hard gates, use
1026
+ `rac relationships --validate` (exits `1` on broken refs).
1027
+ - **Attention severity.** `error` means the artifact is structurally invalid;
1028
+ `warning` means it is valid but needs attention (missing recommended sections
1029
+ or a stale relationship reference). Items are ordered errors-first, then by
1030
+ path, then by code — deterministically.
1031
+ - **`identifier`** is the artifact's canonical identifier (the same one
1032
+ `rac relationships --validate` resolves against): an explicit `## ID`, else a
1033
+ recognised `TYPE-NNN` filename prefix, else the filename stem.
1034
+ - **`rac stats` vs `rac portfolio`.** `rac stats` provides per-feature
1035
+ requirement and metric breakdowns for requirement-focused portfolios.
1036
+ `rac portfolio` provides a whole-repository intelligence rollup across all
1037
+ artifact types.
1038
+ - **Orphaned** means no other artifact holds a resolved inbound reference to
1039
+ it — the artifact may still declare outbound relationships.
1040
+ - **Coverage** is the fraction of known (non-unknown) artifacts that declare
1041
+ at least one outbound relationship section.
1042
+
1043
+ ---
1044
+
898
1045
  ## Review (Planned)
899
1046
 
900
1047
  AI-assisted product review.
@@ -506,3 +506,5 @@ Review after the first v0.7.x relationship implementation, or before introducing
506
506
  * Explorer relationship visualisation
507
507
  * workflow-like dependency management
508
508
  * relationship scoring
509
+
510
+ **v0.7.3 note:** `rac portfolio` introduces a health score that includes relationship integrity as one of four weighted factors (0.25 weight). This is the first instance of relationship scoring in RAC Core. The formula is fully deterministic, documented in `rac/portfolio.py`, and uses only counts already produced by `summarize_relationships`. This ADR was reviewed before v0.7.3 implementation; no architectural objections were raised.
@@ -9,10 +9,11 @@ Commands:
9
9
  rac improve <file.md | -> [--json | --template]
10
10
  rac schema [--list] [type] [--json | --template]
11
11
  rac relationships <dir | file.md> [--validate] [--json] [--top-level]
12
+ rac portfolio <directory> [--json] [--top-level]
12
13
 
13
14
  Exit codes:
14
15
  0 success (incl. inspect/improve reporting Unknown; relationships found or
15
- not; --validate with all references resolved)
16
+ not; --validate with all references resolved; portfolio summary produced)
16
17
  1 validate: errors found; stats: no valid known artifacts; ingest:
17
18
  conversion failed; relationships --validate: broken/ambiguous/self
18
19
  references or duplicate identifiers found
@@ -34,6 +35,7 @@ from .classification import score_artifacts
34
35
  from .improve import improve_product
35
36
  from .inspect import build_inspection, inspect_directory
36
37
  from .parser import parse, parse_file
38
+ from .portfolio import build_portfolio_summary
37
39
  from .relationships import (
38
40
  build_relationship_report,
39
41
  build_relationship_report_file,
@@ -290,6 +292,19 @@ def cmd_relationships(args: argparse.Namespace) -> int:
290
292
  return EXIT_OK
291
293
 
292
294
 
295
+ def cmd_portfolio(args: argparse.Namespace) -> int:
296
+ if not Path(args.directory).is_dir():
297
+ print(f"rac: not a directory: {args.directory}", file=sys.stderr)
298
+ raise SystemExit(EXIT_USAGE)
299
+ recursive = not args.top_level
300
+ summary = build_portfolio_summary(args.directory, recursive=recursive)
301
+ if args.json:
302
+ print(outputs.render_portfolio_json(summary))
303
+ else:
304
+ print(outputs.render_portfolio_human(summary))
305
+ return EXIT_OK
306
+
307
+
293
308
  def build_parser() -> argparse.ArgumentParser:
294
309
  version_str = f"rac {__version__}"
295
310
 
@@ -470,6 +485,27 @@ def build_parser() -> argparse.ArgumentParser:
470
485
  )
471
486
  p_relationships.set_defaults(func=cmd_relationships)
472
487
 
488
+ p_portfolio = sub.add_parser(
489
+ "portfolio",
490
+ help="Repository intelligence summary: artifact counts, health score, and attention items.",
491
+ parents=[version_parent],
492
+ )
493
+ p_portfolio.add_argument("directory", help="Directory to scan recursively for *.md.")
494
+ p_portfolio.add_argument(
495
+ "--json", action="store_true", help="Emit JSON instead of human-readable text."
496
+ )
497
+ p_portfolio.add_argument(
498
+ "--top-level",
499
+ action="store_true",
500
+ help="Only the top-level files in the directory (no recursion).",
501
+ )
502
+ p_portfolio.add_argument(
503
+ "--recursive",
504
+ action="store_true",
505
+ help="Recurse into subdirectories (the default; accepted for clarity).",
506
+ )
507
+ p_portfolio.set_defaults(func=cmd_portfolio)
508
+
473
509
  return parser
474
510
 
475
511
 
@@ -754,3 +754,73 @@ def render_ingest_json(result: IngestResult, output_path: str | None) -> str:
754
754
  "markdown": result.markdown,
755
755
  }
756
756
  return json.dumps(payload, indent=2)
757
+
758
+
759
+ # --- portfolio ---------------------------------------------------------------
760
+
761
+
762
+ def render_portfolio_human(s) -> str:
763
+ """Human-readable `rac portfolio` output."""
764
+ lines = [
765
+ _bold("Repository Summary"),
766
+ "==================",
767
+ "",
768
+ f"Directory: {s.directory}",
769
+ f"Artifacts: {s.total_artifacts}",
770
+ "",
771
+ _bold("By Type"),
772
+ "-------",
773
+ "",
774
+ ]
775
+ for type_name, count in s.by_type.items():
776
+ if count > 0:
777
+ lines.append(f" {type_name.title():<14} {count}")
778
+
779
+ lines += [
780
+ "",
781
+ _bold("Validation"),
782
+ "----------",
783
+ "",
784
+ f" Valid: {s.valid_artifacts}",
785
+ f" Invalid: {s.invalid_artifacts}",
786
+ "",
787
+ _bold("Completeness"),
788
+ "------------",
789
+ "",
790
+ f" {s.completeness:.0%} ({s.filled_slots} / {s.recommended_slots} recommended slots filled)",
791
+ "",
792
+ _bold("Relationships"),
793
+ "-------------",
794
+ "",
795
+ f" Total: {s.relationships.total}",
796
+ f" Valid: {s.relationships.valid}",
797
+ f" Broken: {s.relationships.broken}",
798
+ f" Orphaned: {s.relationships.orphaned}",
799
+ f" Coverage: {s.relationships.coverage:.0%}",
800
+ ]
801
+
802
+ if s.attention:
803
+ lines += ["", _bold(f"Attention ({len(s.attention)} items)"), "----------", ""]
804
+ for item in s.attention:
805
+ icon = _red("✗") if item.severity == "error" else _yellow("!")
806
+ lines.append(f" {icon} {item.identifier}")
807
+ lines.append(f" {item.message}")
808
+ else:
809
+ lines += ["", _green("✓ No attention items.")]
810
+
811
+ score = s.health_score
812
+ score_color = _green if score >= 80 else _yellow if score >= 60 else _red
813
+ lines += [
814
+ "",
815
+ _bold("Health Score"),
816
+ "------------",
817
+ "",
818
+ f" {score_color(str(score))} / 100",
819
+ ]
820
+
821
+ return "\n".join(lines)
822
+
823
+
824
+ def render_portfolio_json(s) -> str:
825
+ """JSON `rac portfolio` output (stable contract, ADR-007)."""
826
+ return json.dumps(s.to_dict(), indent=2)