feat: add adr_frontmatter_completeness assessor with central ADR repo support#514
feat: add adr_frontmatter_completeness assessor with central ADR repo support#514Dannyb48 wants to merge 1 commit into
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Enterprise Run ID: 📒 Files selected for processing (13)
📝 WalkthroughWalkthroughAdds ADR frontmatter scoring, central ADR source support, assessor wiring, and Tier 3 weight updates. Documentation assessment now falls back to configured central ADRs when local ADR files are absent. ChangesADR frontmatter and central source support
Possibly related PRs
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/agentready/assessors/adr_sources.py`:
- Around line 63-73: The frontmatter parsing logic in _parse_frontmatter_content
duplicates parse_frontmatter from adr_frontmatter, so replace the local YAML
parsing helper with the shared public parser. Update CentralAdrSource to import
and call parse_frontmatter directly, and if adr_frontmatter already depends on
adr_sources, move the parser into a small shared module to avoid an import
cycle.
In `@src/agentready/assessors/documentation.py`:
- Around line 753-793: The _check_central_adr_source method is awarding full
credit too early by only checking repository.config.adr_source and
local_path.exists(), while never validating the computed adr_dir contents.
Update this path in DocumentationAssessor to require the central ADR directory
to exist and to contain relevant ADR files (or matching entries, consistent with
AdrFrontmatterAssessor._assess_central and its applies_to filtering) before
returning a pass Finding with score=100.0. If the configured subpath is missing,
empty, or has no applicable ADRs, fall through and return None so the normal
failure path is used.
In `@src/agentready/data/default-weights.yaml`:
- Around line 61-67: The Tier 3 default weights in the YAML are now the source
of truth, but several assessor classes still have mismatched
attribute.default_weight values. Update the defaults in
ArchitectureDecisionsAssessor, OpenAPISpecsAssessor, StructuredLoggingAssessor,
and ProgressiveDisclosureAssessor to match default-weights.yaml, or refactor
them to read from one canonical weight source so scoring stays consistent
everywhere.
In `@tests/unit/test_assessors_documentation.py`:
- Around line 711-748: Add a regression test for ArchitectureDecisionsAssessor
that uses Config.adr_source pointing to an existing central repo root with a
present ADR path that is empty or contains no matching ADR files, and assert
assess(repo) falls through to the normal failure result instead of passing with
100.0; place it alongside test_passes_when_central_adr_source_configured and
test_falls_through_when_central_path_missing to cover the
_check_central_adr_source behavior when the central source exists but has no
valid ADRs.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: 9d89ab66-30f7-4160-883c-36cbb092869b
📒 Files selected for processing (9)
src/agentready/assessors/__init__.pysrc/agentready/assessors/adr_frontmatter.pysrc/agentready/assessors/adr_sources.pysrc/agentready/assessors/documentation.pysrc/agentready/data/default-weights.yamlsrc/agentready/models/config.pytests/unit/test_adr_central_source.pytests/unit/test_adr_frontmatter.pytests/unit/test_assessors_documentation.py
04d63da to
d79d26f
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/agentready/assessors/documentation.py (1)
569-574: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueStale weight in docstring. The class docstring still says "Tier 3 Important (3% weight)" but
default_weightis now0.01. Same drift exists onOpenAPISpecsAssessor(Line 1360 says 3%, weight is now0.02). Update both to avoid misleading future readers.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/agentready/assessors/documentation.py` around lines 569 - 574, Update the class docstrings for ArchitectureDecisionsAssessor and OpenAPISpecsAssessor so the stated tier/weight matches their current default_weight values. The ArchitectureDecisionsAssessor docstring should no longer say 3% weight and must reflect 0.01, and the OpenAPISpecsAssessor docstring should no longer say 3% weight and must reflect 0.02. Keep the wording aligned with the existing assessor class documentation style.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/agentready/assessors/_adr_utils.py`:
- Around line 20-23: The frontmatter parser in _adr_utils.load_frontmatter
currently returns any yaml.safe_load result, which can be a scalar or list and
then breaks callers that expect mapping access. Update this helper to enforce a
dict-or-None contract by returning the parsed value only when it is a dict,
otherwise return None, and keep the existing YAML error handling. This will let
classify_adr_file and CentralAdrSource.get_matching_adr_files continue to skip
invalid ADRs gracefully instead of hitting AttributeError on fm.get(...).
---
Outside diff comments:
In `@src/agentready/assessors/documentation.py`:
- Around line 569-574: Update the class docstrings for
ArchitectureDecisionsAssessor and OpenAPISpecsAssessor so the stated tier/weight
matches their current default_weight values. The ArchitectureDecisionsAssessor
docstring should no longer say 3% weight and must reflect 0.01, and the
OpenAPISpecsAssessor docstring should no longer say 3% weight and must reflect
0.02. Keep the wording aligned with the existing assessor class documentation
style.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: c6641b62-3126-48f2-9f75-751cd4fa4f4e
📒 Files selected for processing (13)
src/agentready/assessors/__init__.pysrc/agentready/assessors/_adr_utils.pysrc/agentready/assessors/adr_frontmatter.pysrc/agentready/assessors/adr_sources.pysrc/agentready/assessors/code_quality.pysrc/agentready/assessors/documentation.pysrc/agentready/assessors/patterns.pysrc/agentready/data/default-weights.yamlsrc/agentready/models/config.pytests/unit/test_adr_central_source.pytests/unit/test_adr_frontmatter.pytests/unit/test_assessors_documentation.pytests/unit/test_assessors_patterns.py
d79d26f to
0cc67e5
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/agentready/data/default-weights.yaml (1)
3-3: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winStale attribute count. Tier 3 grew to 8, so totals are now 9+9+8+2 = 28 attributes, not 27. Update this header to match the Tier 3 change on Line 12.
📝 Fix
-# This file defines the default weights for all 27 attributes. +# This file defines the default weights for all 28 attributes.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/agentready/data/default-weights.yaml` at line 3, The header comment in default-weights.yaml has a stale total attribute count; update the “default weights” summary to reflect the current 28 attributes after the Tier 3 increase. Keep the comment consistent with the tier breakdown used in this file, especially the Tier 3 definition in the same YAML, so the documented total matches the actual 9+9+8+2 distribution.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/agentready/assessors/adr_frontmatter.py`:
- Around line 207-265: The scoring in _score_files currently uses the external
score_from_coverage helper; switch it to self.calculate_proportional_score() so
ADR frontmatter scoring follows the shared BaseAssessor domain logic. Update the
score assignment in _score_files to derive the final score from
calculate_proportional_score using the valid and total counts, and keep the rest
of the Finding construction unchanged.
---
Outside diff comments:
In `@src/agentready/data/default-weights.yaml`:
- Line 3: The header comment in default-weights.yaml has a stale total attribute
count; update the “default weights” summary to reflect the current 28 attributes
after the Tier 3 increase. Keep the comment consistent with the tier breakdown
used in this file, especially the Tier 3 definition in the same YAML, so the
documented total matches the actual 9+9+8+2 distribution.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: 749841ad-77bc-4e17-85e2-6c65c90647f0
📒 Files selected for processing (13)
src/agentready/assessors/__init__.pysrc/agentready/assessors/_adr_utils.pysrc/agentready/assessors/adr_frontmatter.pysrc/agentready/assessors/adr_sources.pysrc/agentready/assessors/code_quality.pysrc/agentready/assessors/documentation.pysrc/agentready/assessors/patterns.pysrc/agentready/data/default-weights.yamlsrc/agentready/models/config.pytests/unit/test_adr_central_source.pytests/unit/test_adr_frontmatter.pytests/unit/test_assessors_documentation.pytests/unit/test_assessors_patterns.py
4f5c484 to
c211a26
Compare
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/agentready/assessors/adr_frontmatter.py`:
- Around line 61-69: The `assess_completeness` logic in `adr_frontmatter.py`
treats any non-empty `applies_to` list as complete, but `_applies_to_matches()`
only supports string entries, so invalid list members can slip through. Update
the `applies_to` validation in `assess_completeness` to require list items to be
strings and non-empty (matching the matcher contract used by
`_applies_to_matches`), and mark the ADR incomplete when the list contains any
non-string or blank entries.
- Around line 54-59: The ADR frontmatter check in assess_frontmatter is too
strict because it treats any status outside VALID_STATUSES as incomplete. Update
the status validation so it only verifies that status exists and is a non-empty
string, and stop rejecting unfamiliar lifecycle values in adr_frontmatter.py;
keep the applies_to/frontmatter presence checks unchanged.
In `@src/agentready/assessors/adr_sources.py`:
- Around line 99-106: The adr source path handling in AdrSource.adr_dir
currently trusts adr_path directly, allowing relative escapes or absolute paths
to point outside the cloned repo root. Update AdrSource.__init__ and/or adr_dir
so path values are normalized and validated against local_path, rejecting any
input that resolves outside the repo clone and only allowing subpaths within the
central ADR directory.
In `@src/agentready/assessors/documentation.py`:
- Around line 655-660: The central ADR source check in
DocumentationAssessor._assess_central is returning None for
configured-but-unavailable external repos, which then falls through to the
generic no-ADR failure. Update the handling around _check_central_adr_source so
that when a configured adr_source cannot be read or the repo/path is missing, it
returns a skipped/warning Finding instead of None; keep None reserved for “not
configured” or “not applicable,” and align the behavior with
AdrFrontmatterAssessor._assess_central and the central_finding branch in
_assess_central.
In `@src/agentready/models/config.py`:
- Around line 60-69: `adr_source` is currently an untyped free-form dict, so
invalid shapes and non-string values slip through and later crash the assessors.
Update the config model in `Config` to use a validated nested object for
`adr_source` with explicit `repo` and `path` fields, and add validation to
reject absolute or otherwise invalid `path` values up front so
`documentation.py` and `adr_sources.py` only receive safe strings.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: 88384f6b-73ab-4e8c-b42b-f6841f6ca7ca
📒 Files selected for processing (13)
src/agentready/assessors/__init__.pysrc/agentready/assessors/_adr_utils.pysrc/agentready/assessors/adr_frontmatter.pysrc/agentready/assessors/adr_sources.pysrc/agentready/assessors/code_quality.pysrc/agentready/assessors/documentation.pysrc/agentready/assessors/patterns.pysrc/agentready/data/default-weights.yamlsrc/agentready/models/config.pytests/unit/test_adr_central_source.pytests/unit/test_adr_frontmatter.pytests/unit/test_assessors_documentation.pytests/unit/test_assessors_patterns.py
| status = fm.get("status") | ||
| applies_to = fm.get("applies_to") | ||
|
|
||
| # status must be present, non-empty string, and in the allowed set | ||
| if not status or not isinstance(status, str) or status not in VALID_STATUSES: | ||
| return "incomplete" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Don't reject ADRs just because status isn't in this hard-coded set.
Line 58 turns any non-empty but unfamiliar status into "incomplete", but this feature is supposed to verify structured frontmatter presence. That will score down repos using valid but different lifecycle terms such as accepted, obsolete, or org-specific statuses.
Suggested fix
- # status must be present, non-empty string, and in the allowed set
- if not status or not isinstance(status, str) or status not in VALID_STATUSES:
+ # status must be present and non-empty
+ if not isinstance(status, str) or not status.strip():
return "incomplete"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| status = fm.get("status") | |
| applies_to = fm.get("applies_to") | |
| # status must be present, non-empty string, and in the allowed set | |
| if not status or not isinstance(status, str) or status not in VALID_STATUSES: | |
| return "incomplete" | |
| status = fm.get("status") | |
| applies_to = fm.get("applies_to") | |
| # status must be present and non-empty | |
| if not isinstance(status, str) or not status.strip(): | |
| return "incomplete" |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/agentready/assessors/adr_frontmatter.py` around lines 54 - 59, The ADR
frontmatter check in assess_frontmatter is too strict because it treats any
status outside VALID_STATUSES as incomplete. Update the status validation so it
only verifies that status exists and is a non-empty string, and stop rejecting
unfamiliar lifecycle values in adr_frontmatter.py; keep the
applies_to/frontmatter presence checks unchanged.
| # applies_to must be present and non-empty (string or non-empty list) | ||
| if applies_to is None: | ||
| return "incomplete" | ||
| if not isinstance(applies_to, (str, list)): | ||
| return "incomplete" | ||
| if isinstance(applies_to, str) and not applies_to.strip(): | ||
| return "incomplete" | ||
| if isinstance(applies_to, list) and not applies_to: | ||
| return "incomplete" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Validate applies_to list members against the matcher contract.
Line 68 accepts any non-empty list as valid, but _applies_to_matches() only knows how to match strings. For example, applies_to: [123] passes completeness locally and can never match centrally, so the same ADR is "valid" in one path and ignored in the other.
Suggested fix
- if isinstance(applies_to, list) and not applies_to:
- return "incomplete"
+ if isinstance(applies_to, list) and (
+ not applies_to
+ or any(not isinstance(item, str) or not item.strip() for item in applies_to)
+ ):
+ return "incomplete"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # applies_to must be present and non-empty (string or non-empty list) | |
| if applies_to is None: | |
| return "incomplete" | |
| if not isinstance(applies_to, (str, list)): | |
| return "incomplete" | |
| if isinstance(applies_to, str) and not applies_to.strip(): | |
| return "incomplete" | |
| if isinstance(applies_to, list) and not applies_to: | |
| return "incomplete" | |
| # applies_to must be present and non-empty (string or non-empty list) | |
| if applies_to is None: | |
| return "incomplete" | |
| if not isinstance(applies_to, (str, list)): | |
| return "incomplete" | |
| if isinstance(applies_to, str) and not applies_to.strip(): | |
| return "incomplete" | |
| if isinstance(applies_to, list) and ( | |
| not applies_to | |
| or any(not isinstance(item, str) or not item.strip() for item in applies_to) | |
| ): | |
| return "incomplete" |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/agentready/assessors/adr_frontmatter.py` around lines 61 - 69, The
`assess_completeness` logic in `adr_frontmatter.py` treats any non-empty
`applies_to` list as complete, but `_applies_to_matches()` only supports string
entries, so invalid list members can slip through. Update the `applies_to`
validation in `assess_completeness` to require list items to be strings and
non-empty (matching the matcher contract used by `_applies_to_matches`), and
mark the ADR incomplete when the list contains any non-string or blank entries.
| def __init__(self, local_path: Path, adr_path: str) -> None: | ||
| self._local_path = local_path | ||
| self._adr_path = adr_path.rstrip("/") | ||
|
|
||
| @property | ||
| def adr_dir(self) -> Path: | ||
| """Absolute path to the ADR subdirectory inside the central repo.""" | ||
| return self._local_path / self._adr_path |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Constrain adr_source.path to the cloned repo root.
Line 106 joins config input directly, so path values like ../../notes or an absolute path escape local_path. In the current flow, an untrusted repo config can make the assessor read arbitrary local .md files instead of only the central ADR clone.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/agentready/assessors/adr_sources.py` around lines 99 - 106, The adr
source path handling in AdrSource.adr_dir currently trusts adr_path directly,
allowing relative escapes or absolute paths to point outside the cloned repo
root. Update AdrSource.__init__ and/or adr_dir so path values are normalized and
validated against local_path, rejecting any input that resolves outside the repo
clone and only allowing subpaths within the central ADR directory.
| # Check for central ADR repo configured via adr_source config. | ||
| # If the org maintains ADRs centrally, the repo still gets full credit. | ||
| central_finding = self._check_central_adr_source(repository) | ||
| if central_finding is not None: | ||
| return central_finding | ||
|
|
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Don't convert a configured-but-unavailable central ADR source into a 0-point fail.
When Line 773 or Line 779 returns None, Line 657 falls through to the generic no-ADR failure path. That penalizes repositories for a missing/unreadable external ADR clone instead of degrading gracefully. AdrFrontmatterAssessor._assess_central() already returns Finding.skipped(...) for the same "central repo/path missing" cases, so this assessor should reserve None for "not configured" or "no ADRs apply" and return a skipped/warning finding when the configured source cannot be read.
Minimal fix
if not local_path.exists():
- return None
+ return Finding.skipped(
+ self.attribute,
+ f"Central ADR repo not found at {local_path}",
+ )
adr_path = adr_source.get("path") or "ADR"
source = CentralAdrSource(local_path=local_path, adr_path=adr_path)
if not source.adr_dir.is_dir():
- return None
+ return Finding.skipped(
+ self.attribute,
+ f"Central ADR directory not found at {source.adr_dir}",
+ )As per path instructions, src/agentready/assessors/**: "Check for proper error handling (return skipped/error Finding, don't crash)" and "Check for graceful degradation when tools missing."
Also applies to: 752-800
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/agentready/assessors/documentation.py` around lines 655 - 660, The
central ADR source check in DocumentationAssessor._assess_central is returning
None for configured-but-unavailable external repos, which then falls through to
the generic no-ADR failure. Update the handling around _check_central_adr_source
so that when a configured adr_source cannot be read or the repo/path is missing,
it returns a skipped/warning Finding instead of None; keep None reserved for
“not configured” or “not applicable,” and align the behavior with
AdrFrontmatterAssessor._assess_central and the central_finding branch in
_assess_central.
Source: Path instructions
| adr_source: Annotated[ | ||
| dict | None, | ||
| Field( | ||
| default=None, | ||
| description=( | ||
| "Central ADR repository config: " | ||
| "{'repo': '/path/to/local/clone', 'path': 'ADR/'}" | ||
| ), | ||
| ), | ||
| ] |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Validate adr_source as a typed nested config.
This field accepts any mapping shape/value types, but the consumers assume strings. A config like adr_source: {repo: 123, path: 456} will pass here, then src/agentready/assessors/documentation.py Line 772 calls Path(local_path_str) and src/agentready/assessors/adr_sources.py strips adr_path with .rstrip("/"), which raises during assessment. Please model adr_source as a validated object (repo, path) and reject absolute/invalid path values up front so bad config fails validation instead of crashing the assessors.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/agentready/models/config.py` around lines 60 - 69, `adr_source` is
currently an untyped free-form dict, so invalid shapes and non-string values
slip through and later crash the assessors. Update the config model in `Config`
to use a validated nested object for `adr_source` with explicit `repo` and
`path` fields, and add validation to reject absolute or otherwise invalid `path`
values up front so `documentation.py` and `adr_sources.py` only receive safe
strings.
…al ADR repo support (ambient-code#512, ambient-code#513) Adds a new `adr_frontmatter_completeness` assessor (Tier 3, 2% weight) that scores repos on whether ADR files contain structured YAML frontmatter with required `status` and `applies_to` fields. Supports both local ADR directories and a centrally maintained ADR repository via config. ## New assessor: adr_frontmatter_completeness Scoring: - ≥80% of ADR files have valid frontmatter → pass (100) - 50–79% → partial/fail (60) - <50% → fail (0) - No ADR files found → skipped Valid statuses cover MADR (Proposed, Accepted, Implementable, Implemented, Replaced, Deprecated, Superseded, Approved) and adr-tools (active, superseded, draft) conventions. ## Central ADR repository support Configure via `.agentready-config.yaml`: ```yaml adr_source: repo: /path/to/local/clone # locally cloned central ADR repo path: ADR # relative path within that repo ``` When configured, ADRs are read from the central repo and filtered by their `applies_to` frontmatter field matching the assessed repo name. Supports wildcard (`"*"`), short name, full org/repo, and list matching. No network calls — the central repo must be locally cloned. Gracefully skips if the path does not exist or no ADRs match. ## Fix: architecture_decisions respects central ADR repos `ArchitectureDecisionsAssessor` now passes when `adr_source` is configured and the central repo path exists and contains ADRs that match the repo via applies_to, rather than penalising repos that deliberately maintain ADRs centrally. ## Weight rebalancing (Tier 3) Added `adr_frontmatter_completeness: 0.02`. Funded by reducing `architecture_decisions` (2% → 1%) and `progressive_disclosure` (2% → 1%). Also synced `default_weight` values in ArchitectureDecisionsAssessor, OpenAPISpecsAssessor, StructuredLoggingAssessor, and ProgressiveDisclosureAssessor to match default-weights.yaml. Total weights remain 1.0. ## Shared utility module Extracted `parse_frontmatter` into `assessors/_adr_utils.py` to avoid a circular import between `adr_frontmatter` and `adr_sources`. Closes ambient-code#512, ambient-code#513 Co-authored-by: Cursor <cursoragent@cursor.com>
c211a26 to
687c4d2
Compare
Description
Adds a new
adr_frontmatter_completenessassessor (Tier 3, 2% weight) that scores repositories on whether ADR files contain structured YAML frontmatter with requiredstatusandapplies_tofields. Also adds central ADR repository support so teams that maintain ADRs in a shared repo are not penalised, and fixesArchitectureDecisionsAssessorto respect that same config.Type of Change
Related Issues
Fixes #512
Fixes #513
Changes Made
adr_frontmatter_completenessassessor (src/agentready/assessors/adr_frontmatter.py) — scores repos on YAML frontmatter coverage across ADR files; thresholds: ≥80% → pass, 50–79% → partial, <50% → failLocalAdrSourceandCentralAdrSource(src/agentready/assessors/adr_sources.py) —LocalAdrSourcediscovers ADR directories on the local repo filesystem;CentralAdrSourcereads ADRs from a locally cloned shared repo and filters byapplies_to(supports wildcard, short name, fullorg/repo, and list matching)Configmodel withadr_source: dict | Nonefield for central repo configuration (repo+pathkeys)ArchitectureDecisionsAssessor(src/agentready/assessors/documentation.py) to pass whenadr_sourceis configured and the central repo path exists, rather than failing repos that intentionally maintain ADRs centrallyAdrFrontmatterAssessorinassessors/__init__.pyadr_frontmatter_completeness: 0.02weight todefault-weights.yaml; rebalanced by reducingarchitecture_decisions(2% → 1%) andprogressive_disclosure(2% → 1%) to keep total at 1.0Testing
pytest)Checklist
Screenshots (if applicable)
Additional Notes
Central ADR repo config (
.agentready-config.yaml):No network calls are made — the central repo must be locally cloned. The assessor gracefully skips if the path does not exist or no ADRs match the assessed repo's name.
Valid status values cover MADR (Proposed, Accepted, Implementable, Implemented, Replaced, Deprecated, Superseded, Approved) and adr-tools (active, superseded, draft) conventions to accommodate common ADR tooling.
Summary by CodeRabbit
status/applies_to) with remediation guidance.applies_tomatching and evidence.adr_frontmatter_completenessattribute, and adjusted several default weights (including progressive disclosure and structured logging).