fix(registry): fetch and parse package content for resolved registry references #138
No reviewers
Labels
No labels
auto/blocked-by-deps
auto/ci-timeout
auto/claimed-implementer
auto/claimed-merge
auto/claimed-reviewer
auto/driver-down
auto/invariant-violation
auto/last-attempt-tier-0
auto/last-attempt-tier-1
auto/last-attempt-tier-2
auto/last-attempt-tier-min
Automation Tracking
auto/needs-conflict-resolution
auto/needs-implementer
auto/postmortem
auto/ready-to-merge
auto/restart-throttled
auto/revert
auto/sentinel
auto/stale-inactivity
auto/unstable
Blocked
Bounty
$100
Bounty
$1000
Bounty
$10000
Bounty
$20
Bounty
$2000
Bounty
$250
Bounty
$50
Bounty
$500
Bounty
$5000
Bounty
$750
MoSCoW
Could have
MoSCoW
Must have
MoSCoW
Should have
Needs Feedback
Points
1
Points
13
Points
2
Points
21
Points
3
Points
34
Points
5
Points
55
Points
8
Points
88
Priority
Backlog
Priority
CI Blocker
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Signed-off: Owner
Signed-off: Scrum Master
Signed-off: Tech Lead
Spike
State
Completed
State
Duplicate
State
In Progress
State
In Review
State
Paused
State
Unverified
State
Verified
State
Wont Do
Type
Automation
Type
Bug
Type
Discussion
Type
Documentation
Type
Epic
Type
Feature
Type
Legendary
Type
Refactor
Type
Support
Type
Task
Type
Testing
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Blocks
Reference
cleveragents/cleveractors-core!138
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "bugfix/m1-registry-content-fetch"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Fixes #135:
PackageContentResolver._resolve_registry_asynconly performed the Package Registry Standard §8.2.2 "resolve" call and returned that stub directly as package content, never performing the required §8.2.1get_packagefetch. Atype: llmagent referenced via a bare REGISTRY-scheme string inagents.<name>therefore failedAgentFactory.acreate_agentwithAgentCreationError("Unknown agent type: agent")._resolve_registry_asyncnow follows upresolve_packagewithget_package/get_package_content, parses the returned YAMLcontent, and merges the real package content over the resolve stub (routed through the per-serverRegistryCachewhen available). The resolution cache now stores the fully-resolved content. A malformed/missingcontentresponse raisesValidationErrorinstead of silently propagating the stub.Also fixes
robot/fake_registry_server.py's/packages/{id}handler, which was returning raw fields instead of the spec-compliant{"content": "<yaml>"}envelope for actor/skill packages -- this was previously masking the same defect inrobot/skill_registry_auth.robot's real end-to-end skill-download flow and inrobot/registry_full_cache_integration.robot.Stacking note: This PR is based on
tdd/m1-registry-content-fetch(PR #137, not yet merged) rather thanmaster, since the regression test this fix turns green lives there. Please merge #137 first; this PR's diff againstmasterwill shrink to just the fix once that happens.Closes #135
Test plan
nox -s unit_tests-- full Behave suite green (3084 scenarios)nox -s coverage_report-- 96.8% (>= 96.5% threshold)nox -s typecheck-- 0 errorsnox -s lint/nox -s format -- --check-- cleannox -s security_scan/nox -s dead_code-- cleannox -s integration_tests-- full Robot suite green (363 tests), including new REGISTRY-backedtype: llmagent scenario inagent_package_references.robot@tdd_expected_failfrom the@tdd_issue_135scenario now that the fix landsPackageContentResolver._resolve_registry_async only performed the Package Registry Standard §8.2.2 "resolve" call (GET /{package_type}/{namespace}/{name} -> {"package_id", "type"}) and returned that stub directly as if it were the resolved package content. It never performed the required §8.2.1 "get package by ID" call (GET /packages/{package_id} -> {"content": "<YAML string>"}) to fetch and parse the real package payload, so a REGISTRY-scheme agents.<name> (and routes.<name>/skills:) reference ended up with type: "agent" (the resolve stub's package-type field) instead of the real package's type: "llm", per docs/index.md §4.1.1 and ADR-2037 D-3. _resolve_registry_async now follows up resolve_package with get_package/ get_package_content for the returned package_id, parses the YAML content string via a new _parse_package_content helper, and merges the parsed content over the resolve stub so the real type/config win. The fetch routes through the per-server RegistryCache when available, mirroring the existing resolve_package cache/no-cache branching, and the resolution cache now stores the fully-resolved content instead of the intermediate stub. A malformed or missing content response now raises ValidationError (a RegistryError subclass) instead of silently propagating the stub. Removed @tdd_expected_fail from the issue #135 regression scenario in features/registry_http_client.feature now that the fix lands. Updated existing mocks that only modeled the single §8.2.2 call (registry_http_client_steps.py, registry_reference_resolver_coverage_steps.py, cache_coverage_steps.py/.feature) to also serve a valid §8.2.1 response, and fixed robot/fake_registry_server.py's /packages/{id} handler to wrap known package content in the spec-compliant {"content": "<yaml>"} envelope instead of returning raw fields at the top level -- both registry_full_cache_integration.robot (updated miss-count assertions, now 2 misses per fetch instead of 1) and skill_registry_auth.robot's real end-to-end skill-download flow depend on this shape and were previously silently red. Added a new Robot scenario in agent_package_references.robot proving a type: llm agent referenced via a bare REGISTRY-scheme string constructs successfully through AgentFactory.acreate_agent against a real fake registry server. ISSUES CLOSED: #135PR Review: !138 (Ticket #135)
Verdict: Request Changes
The fix correctly implements the two-call Package Registry Standard §8.2.2 + §8.2.1 resolution flow for
PackageContentResolverand turns the new Behave/Robot regression tests green for the happy path. However, the implementation does not match the stated acceptance criteria or the CHANGELOG for one malformed-response edge case: a resolve response that lackspackage_idsilently returns the §8.2.2 stub instead of raisingValidationError. That leaves the original failure mode (AgentCreationError("Unknown agent type: agent")) reachable against a non-compliant registry and should be fixed before merge.Critical Issues
None.
Major Issues
src/cleveractors/registry/reference_resolver.py,PackageContentResolver._resolve_registry_async(lines 561–566)When
resolve_packagereturns a dict without a usablepackage_id, the code merges the stub and returns it verbatim without fetching/packages/{id}. This contradicts issue #135's acceptance criteria and the CHANGELOG, both of which state that "a resolve response missingpackage_id... now raisesValidationError".Reproduced with a mocked client returning
{"type": "agent"}: the resolver returned{"type": "agent", ...}and never calledget_package.Recommendation: Add an explicit validation after extracting
package_idand raiseValidationError(aRegistryErrorsubclass) when it is missing, not a string, or empty, e.g.:Minor Issues
Missing test coverage for new error branches
The new
_parse_package_contenterror paths (missing/non-stringcontent, malformed YAML, non-mapping result) and the missingpackage_idbranch are not exercised by any Behave/Robot test. Since these are new code paths introduced by this PR, they should have dedicated scenarios so the 96.5% threshold is not masking uncovered error handling.robot/fake_registry_server.pyresolve response is still non-compliant_build_resolve_responseembeds the real package content at the top level of the §8.2.2 resolve response. The Robot E2E tests therefore pass even if the resolver failed to call/packages/{id}. While the Behave scenario covers the compliant stub case, tightening the fake server to return only{"package_id", "type"}from the resolve endpoint would make the Robot regression a stricter guard against regressions of issue #135.Nits
Issue #135's subtasks say "coverage >= 97%", the PR description cites a 96.5% threshold, and
noxfile.pyenforcesCOVERAGE_THRESHOLD = 96.5. This is project housekeeping rather than a PR defect, but aligning the wording would avoid future confusion.Summary
This PR is well-focused and the core happy-path fix is solid: REGISTRY references now fetch real package content through
get_package/get_package_content, route throughRegistryCachewhen configured, cache the fully-resolved result, and surfaceValidationErrorfor malformed content responses. Once the missing/emptypackage_idcase is also validated and a regression test is added, this should be good to approve. I did not run the fullnoxsuite, but targeted Behave/Robot runs for the touched features passed, andpyright/ruffare clean on the changed files.ingore Nits issue, is not relevant, we have a noxfile threshold at 96.5% while having a 97% in the specification, but the 97% is the rounded value, which is also obtainable from a 96.5% real coverage.
a029089587toc0ca26cfe9Addressed the review findings from @hurui200320's request-changes review (verified each against issue #135's acceptance criteria,
docs/index.md§4.1.1,docs/adr/ADR-2037-agent-and-route-package-reference-resolution.mdD-3, anddocs/actor-registry-standard.md§8.2.1/§8.2.2 before applying):Major — missing
package_idsilently returned the resolve stubConfirmed as a genuine gap against
docs/index.md§4.1.1 ("a missing package ... MUST signal a configuration error") and the CHANGELOG's own (previously unimplemented) claim.PackageContentResolver._resolve_registry_asyncnow raisesValidationErrorwhen the §8.2.2 resolve response lacks a non-empty stringpackage_id, instead of merging the stub and returning it unfetched.Minor — missing test coverage for the new error branches
Added 5 Behave scenarios to
features/registry_http_client.feature: the missing-package_idcase above, plus_parse_package_content's four error paths (missingcontent, non-stringcontent, malformed YAML, non-mapping YAML). All previously untested lines are now covered.Minor —
robot/fake_registry_server.pyresolve response embedded real contentConfirmed non-compliant with §8.2.2 (
{"package_id", "type"}only)._build_resolve_responseno longer embeds_PACKAGE_CONTENT— the "cache warming" behavior it cited is not consumed by any production caller (RegistryCache.putis only exercised directly incache_coverage.feature). Verifiedrobot/agent_package_references.robot,robot/registry_full_cache_integration.robot, androbot/skill_registry_auth.robotdon't depend on the removed content and all still pass.Nit — coverage threshold wording
Per @CoreRasurae's comment above, leaving as-is: 96.5% real coverage rounds to the 97% cited in the issue subtasks, so there's no actual discrepancy to fix.
All changes squashed into the existing commit (amended, force-pushed) rather than added as new commits, since this PR is still a single unmerged commit implementing issue #135.
c0ca26cfe95a34ff04bfPR Review: !138 (Ticket #135)
Verdict: Approve
The implementation correctly fixes issue #135:
PackageContentResolver._resolve_registry_asyncnow performs the full Package Registry Standard §8.2.2 resolve + §8.2.1get_packagefetch, parses the YAMLcontent, and returns the real package payload instead of the resolve-endpoint stub. The previously requestedpackage_idvalidation and malformed-contentValidationErrorpaths are all in place and covered by Behave scenarios. The fake registry server now returns a strict §8.2.2 stub and a spec-compliant §8.2.1 envelope, making the Robot E2E tests a reliable regression guard. No critical or major issues remain.Critical Issues
None.
Major Issues
None.
Minor Issues
None.
Nits
None.
Summary
This is a focused, well-tested fix. The production change in
src/cleveractors/registry/reference_resolver.pyis minimal and follows the existing cache/no-cache branching pattern: after a successfulresolve_package, it validatespackage_id, fetches and parses the real content viaget_package/get_package_content(routed throughRegistryCachewhen configured), and caches the fully-resolved result. The new_parse_package_contenthelper raisesValidationErrorfor missing/non-stringcontent, malformed YAML, and non-mapping YAML, matching the stated acceptance criteria.Test coverage is comprehensive:
package_id, missing/non-stringcontent, malformed YAML, and non-mapping YAML.type: llmagent package resolves through the real resolver/client pipeline against the fake server.get_packageendpoints now conform strictly to §8.2.2 and §8.2.1, closing the test-double gap that was masking the defect.All previously raised review concerns have been addressed in the latest revision. I did not run the full
noxsuite locally due to environment dependencies, but the changed code is type-safe, lint-clean on inspection, and the PR's reported test results are consistent with the code structure.5a34ff04bf352acf8888