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.
- {requirements_as_code-0.7.2/requirements_as_code.egg-info → requirements_as_code-0.7.3}/PKG-INFO +148 -1
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/README.md +147 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-016-relationships-as-structural-references.md +2 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/cli.py +37 -1
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/outputs.py +70 -0
- requirements_as_code-0.7.3/rac/portfolio.py +250 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/relationships.py +125 -21
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3/requirements_as_code.egg-info}/PKG-INFO +148 -1
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/requirements_as_code.egg-info/SOURCES.txt +13 -0
- requirements_as_code-0.7.3/tests/fixtures/portfolio_summary/all_types/adr.md +13 -0
- requirements_as_code-0.7.3/tests/fixtures/portfolio_summary/all_types/design.md +17 -0
- requirements_as_code-0.7.3/tests/fixtures/portfolio_summary/all_types/prompt.md +17 -0
- requirements_as_code-0.7.3/tests/fixtures/portfolio_summary/all_types/req.md +17 -0
- requirements_as_code-0.7.3/tests/fixtures/portfolio_summary/all_types/roadmap.md +9 -0
- requirements_as_code-0.7.3/tests/fixtures/portfolio_summary/all_types/unknown.md +3 -0
- requirements_as_code-0.7.3/tests/fixtures/portfolio_summary/broken_rels/source.md +13 -0
- requirements_as_code-0.7.3/tests/fixtures/portfolio_summary/invalid_known/req-no-title.md +19 -0
- requirements_as_code-0.7.3/tests/fixtures/portfolio_summary/unknown_only/unknown.md +3 -0
- requirements_as_code-0.7.3/tests/fixtures/portfolio_summary/valid_clean/adr-001.md +25 -0
- requirements_as_code-0.7.3/tests/fixtures/portfolio_summary/valid_clean/req-001.md +26 -0
- requirements_as_code-0.7.3/tests/test_portfolio.py +328 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/.github/workflows/python-publish.yml +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/.gitignore +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/LICENSE +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/examples/example_dashboard_v1.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/examples/example_dashboard_v2.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-001-markdown-first.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-002-ai-optional.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-003-structured-outputs-first.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-004-artifact-model.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-005-cli-first.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-006-ingest-over-rewrite.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-007-json-contract-stability.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-008-agent-ready-architecture.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-009-ai-assisted-development.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-010-documents-are-not-artifacts.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-011-file-first-pipeline.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-012-open-core-strategy.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-013-leverage-existing-source-control-systems.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-014-viewer-agnostic-knowledge-artifacts.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-015-explorer-as-consumer.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/adr/adr-017-rac-managed-knowledge-not-work.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/designs/explorer-command-surface.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/designs/explorer-first-run-experience.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/designs/explorer-health-model.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/designs/explorer-import-workflow.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/designs/explorer-knowledge-graph.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/designs/explorer-visual-system.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/future/v1.0-workspace-analysis.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/future/v1.1-review-engine.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/future/v1.2-mcp-server.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/future/v1.4-claude-skills.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/future/v1.4-python-sdk.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/prompt/rac-agent-compression.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/prompt/rac-agent-instructions.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/prompt/rac-agent-release-gate-major.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/prompt/rac-agent-release-gate-minor.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/prompt/rac-agent-session-start.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/archive/v0.5-decisions.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/archive/v0.7-prompts.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.2-stats.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.3-ingest.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.3.1-formats.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.4-inspect.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.4.1-expansion.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.4.1-inspect-expansion.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.4.2-decision-metadata.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.5.0-artifact-improvement.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.5.1-guided-improvement.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.5.2-schema.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.6.0-roadmap-artifacts.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.6.1-roadmap-improvement.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.6.2-prompt-artifact.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.6.3-design-artifacts.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.7.0-relationship-metadata.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.7.1-relationship-inspection.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.7.2-relationship-validation.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.7.3-repo-intelligence.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.7.4-repo-indexing.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.8.0-service-api.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.8.1-repository-model.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.8.2-interactive-runtime-readiness.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.8.3-integration-freeze.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.9.0-explorer-foundation.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.9.1-explorer-experience.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.9.2-knowledge-operations.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/planning/roadmap/v0.9.3-intelligence-views.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/pyproject.toml +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/__init__.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/artifacts.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/classification.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/diff.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/fs.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/improve.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/ingest.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/inspect.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/models.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/parser.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/schema.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/stats.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/rac/validate.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/requirements_as_code.egg-info/dependency_links.txt +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/requirements_as_code.egg-info/entry_points.txt +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/requirements_as_code.egg-info/requires.txt +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/requirements_as_code.egg-info/top_level.txt +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/setup.cfg +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/conftest.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/decision/bad_category.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/decision/bad_status.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/decision/minimal.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/decision/portfolio/01_accepted_arch.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/decision/portfolio/02_proposed_process.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/decision/portfolio/03_no_metadata.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/decision/with_metadata.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/design/minimal.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/design/missing_constraints.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/design/valid.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/diff/new.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/diff/old.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/ingest/sample.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/inspect/ambiguous.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/inspect/decision.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/inspect/nested/another_requirement.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/inspect/requirement.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/invalid/duplicate_ids.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/invalid/empty_req_text.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/invalid/malformed_id.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/invalid/missing_id.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/invalid/missing_problem.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/invalid/missing_requirements.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/invalid/missing_title.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/invalid/multiple_titles.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/no_relationships/decision.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/no_relationships/requirement.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/portfolio/broken.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/portfolio/feature_a.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/portfolio/feature_b.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/portfolio/sub/feature_c.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/prompt/minimal.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/prompt/missing_output.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/prompt/valid.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationship_validation/ambiguous_target/adr-004-alt.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationship_validation/ambiguous_target/adr-004.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationship_validation/ambiguous_target/req-001.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationship_validation/broken/search.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationship_validation/duplicate/adr-004-alt.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationship_validation/duplicate/adr-004.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationship_validation/resolved/adr-004.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationship_validation/resolved/req-001.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationship_validation/resolved/roadmap-q3.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationship_validation/self_reference/adr-004.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationships/decision_with_links.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationships/design_with_links.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationships/prompt_with_links.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationships/requirement_with_links.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/relationships/roadmap_with_links.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/roadmap/minimal.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/roadmap/missing_initiatives.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/roadmap/valid.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/valid/bullet_requirements.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/valid/feature.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/valid/minimal.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/fixtures/valid/warnings.md +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_cli.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_decision_metadata.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_design.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_diff.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_improve.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_ingest.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_inspect.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_parser.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_prompt.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_relationship_validation.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_relationships.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_relationships_cmd.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_roadmap.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_schema.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_stats.py +0 -0
- {requirements_as_code-0.7.2 → requirements_as_code-0.7.3}/tests/test_validate.py +0 -0
{requirements_as_code-0.7.2/requirements_as_code.egg-info → requirements_as_code-0.7.3}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: requirements-as-code
|
|
3
|
-
Version: 0.7.
|
|
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)
|