feat(registry): implement local: namespace reference resolution with filesystem + canonicalization #46

Closed
opened 2026-06-11 20:27:00 +00:00 by CoreRasurae · 2 comments
Member

Metadata

Commit Message: feat(registry): implement local namespace reference resolution
Branch: feature/m1-local-reference-resolution

Background and context

The Package Registry Standard v1.0.0 (per docs/actor-registry-standard.md) defines three reference schemes in §5.3: REGISTRY (server:ns/name@version), ID (ID:pkg_<type>_<40-hex-sha1>), and LOCAL (local:<path>). While parsing of local: references works (#26, PackageReference.from_string()), actual resolution is not implemented — ReferenceResolver.resolve() raises "not yet implemented" and PackageContentResolver returns an empty placeholder dict. The template registries (TemplateRegistry / EnhancedTemplateRegistry) also do not route local: references through any resolver.

This issue covers the full implementation: reading local YAML files, canonicalizing them per §6 to produce content-addressed PackageIds, resolving nested local: references recursively, and integrating this into both resolvers and the template system — while preserving the original local:<path> reference string in _original_reference.

Current behavior

  • PackageReference.from_string("local:path/to/file.yaml") parses correctly with security validation (no .., no absolute paths)
  • ReferenceResolver.resolve() for LOCAL raises InvalidPackageReferenceError("Local package resolution is not yet implemented")
  • PackageContentResolver.resolve() for LOCAL returns placeholder {"name": "...", "type": "local", "_original_reference": "..."} with no file I/O
  • Template registries _try_parse_registry_ref() filter to ReferenceType.REGISTRY only, so local: template names fall through to local template lookup and fail

Expected behavior

  1. local:path/to/package.yaml resolves by reading the YAML file from a configurable base directory, canonicalizing it via the existing Canonicalizer, and computing a PackageId (SHA-1)
  2. The resolved content dict carries both _original_reference: "local:path/to/package.yaml" and _package_id: "pkg_<type>_<sha1>"
  3. Nested local: references within local packages are recursively resolved during canonicalization (replaced with ID:pkg_... strings before hashing)
  4. ReferenceResolver.resolve() returns the computed PackageId for LOCAL references
  5. PackageContentResolver.resolve() returns the resolved content dict (cached in existing LRU)
  6. Template registries accept local: template names, routing them through the same resolution path as REGISTRY references
  7. Path validation follows security-first guard clauses (no traversal, no absolute paths, no symlink escape, file must exist and be .yaml/.yml)

Acceptance criteria

  • LocalPackageStore class exists in src/cleveractors/registry/local_store.py with resolve_package(relative_path) → LocalPackage
  • LocalPackage dataclass carries package_id, content, file_path, original_reference
  • PackageContentResolver accepts local_store via constructor injection and resolves LOCAL refs to content dicts
  • ReferenceResolver accepts local_store via constructor injection and resolves LOCAL refs to PackageIds
  • TemplateRegistry and EnhancedTemplateRegistry accept local_store via constructor injection and route local: names through LocalPackageStore
  • _try_parse_registry_ref() renamed to _try_parse_package_ref() and accepts both REGISTRY and LOCAL
  • _resolve_registry_ref() renamed to _resolve_package_ref() in base.py, accepts local_store parameter
  • Nested local: references within local YAML files are recursively resolved
  • _original_reference is preserved through the entire resolution chain
  • All local resolution results are cached in the existing PackageContentResolver LRU (key: local:<path>:<type>)
  • Behave BDD scenarios cover all guard clauses, successful resolution, nested resolution, caching, and error paths
  • Robot Framework integration tests verify end-to-end local file resolution
  • Coverage ≥ 97% on all new code via nox -s coverage_report
  • nox full suite passes

Supporting information

  • Spec reference: docs/actor-registry-standard.md §§5.3, 6.1-6.3, 7.3
  • Architecture plan elaborated in session — 8 files to create/modify, ~215 lines of changes
  • Patterns: Repository (LocalPackageStore), Strategy (three resolution types), Template Method (unified resolution flow), Adapter (filesystem → package interface), Proxy (caching layer), Dependency Injection, Guard Clause (path validation)
  • New file: src/cleveractors/registry/local_store.py
  • Modified: reference_resolver.py, resolver.py, canonical.py, base.py, registry.py, enhanced_registry.py, __init__.py

Subtasks

  • Implement LocalPackage frozen dataclass and LocalPackageStore class with path validation guard clauses
  • Implement recursive nested local: reference resolution (_walk_and_resolve)
  • Implement _detect_package_type() heuristic (infer PackageType from content structure)
  • Extend Canonicalizer.resolve_references() to handle local: strings alongside ID:pkg_
  • Add local_store parameter to PackageContentResolver.__init__(), implement LOCAL resolution in resolve() and aresolve()
  • Add local_store parameter to ReferenceResolver.__init__(), implement LOCAL resolution in resolve()
  • Rename _resolve_registry_ref_resolve_package_ref in base.py, add local_store parameter
  • Modify TemplateRegistry: rename _try_parse_registry_ref_try_parse_package_ref, accept LOCAL + REGISTRY, inject local_store
  • Mirror changes to EnhancedTemplateRegistry
  • Export LocalPackage, LocalPackageStore from registry/__init__.py
  • Behave BDD unit tests: path validation, resolution, nested refs, caching, error paths (features/)
  • Robot Framework integration tests: end-to-end local file resolution (robot/)
  • Verify coverage ≥ 97% via nox -s coverage_report
  • Run nox (all default sessions), fix any errors

Definition of Done

This issue is complete when:

  • All subtasks above are completed and checked off.
  • A Git commit is created where the first line matches the Commit Message in Metadata exactly.
  • The commit is pushed to the branch matching the Branch field in Metadata exactly.
  • The commit is submitted as a PR to master, reviewed, and merged.
  • nox full suite passes (lint, typecheck, security, unit_tests, coverage_report).
  • Coverage on new modules ≥ 97%.
  • A template referencing local:path/to/actor.yaml resolves correctly through the full chain.
## Metadata Commit Message: feat(registry): implement local namespace reference resolution Branch: feature/m1-local-reference-resolution ## Background and context The Package Registry Standard v1.0.0 (per `docs/actor-registry-standard.md`) defines three reference schemes in §5.3: `REGISTRY` (`server:ns/name@version`), `ID` (`ID:pkg_<type>_<40-hex-sha1>`), and `LOCAL` (`local:<path>`). While parsing of `local:` references works (#26, `PackageReference.from_string()`), actual resolution is not implemented — `ReferenceResolver.resolve()` raises `"not yet implemented"` and `PackageContentResolver` returns an empty placeholder dict. The template registries (`TemplateRegistry` / `EnhancedTemplateRegistry`) also do not route `local:` references through any resolver. This issue covers the full implementation: reading local YAML files, canonicalizing them per §6 to produce content-addressed `PackageId`s, resolving nested `local:` references recursively, and integrating this into both resolvers and the template system — while preserving the original `local:<path>` reference string in `_original_reference`. ## Current behavior - `PackageReference.from_string("local:path/to/file.yaml")` parses correctly with security validation (no `..`, no absolute paths) - `ReferenceResolver.resolve()` for LOCAL raises `InvalidPackageReferenceError("Local package resolution is not yet implemented")` - `PackageContentResolver.resolve()` for LOCAL returns placeholder `{"name": "...", "type": "local", "_original_reference": "..."}` with no file I/O - Template registries `_try_parse_registry_ref()` filter to `ReferenceType.REGISTRY` only, so `local:` template names fall through to local template lookup and fail ## Expected behavior 1. `local:path/to/package.yaml` resolves by reading the YAML file from a configurable base directory, canonicalizing it via the existing `Canonicalizer`, and computing a `PackageId` (SHA-1) 2. The resolved content dict carries both `_original_reference: "local:path/to/package.yaml"` and `_package_id: "pkg_<type>_<sha1>"` 3. Nested `local:` references within local packages are recursively resolved during canonicalization (replaced with `ID:pkg_...` strings before hashing) 4. `ReferenceResolver.resolve()` returns the computed `PackageId` for LOCAL references 5. `PackageContentResolver.resolve()` returns the resolved content dict (cached in existing LRU) 6. Template registries accept `local:` template names, routing them through the same resolution path as REGISTRY references 7. Path validation follows security-first guard clauses (no traversal, no absolute paths, no symlink escape, file must exist and be `.yaml`/`.yml`) ## Acceptance criteria - `LocalPackageStore` class exists in `src/cleveractors/registry/local_store.py` with `resolve_package(relative_path) → LocalPackage` - `LocalPackage` dataclass carries `package_id`, `content`, `file_path`, `original_reference` - `PackageContentResolver` accepts `local_store` via constructor injection and resolves LOCAL refs to content dicts - `ReferenceResolver` accepts `local_store` via constructor injection and resolves LOCAL refs to `PackageId`s - `TemplateRegistry` and `EnhancedTemplateRegistry` accept `local_store` via constructor injection and route `local:` names through `LocalPackageStore` - `_try_parse_registry_ref()` renamed to `_try_parse_package_ref()` and accepts both REGISTRY and LOCAL - `_resolve_registry_ref()` renamed to `_resolve_package_ref()` in `base.py`, accepts `local_store` parameter - Nested `local:` references within local YAML files are recursively resolved - `_original_reference` is preserved through the entire resolution chain - All local resolution results are cached in the existing `PackageContentResolver` LRU (key: `local:<path>:<type>`) - Behave BDD scenarios cover all guard clauses, successful resolution, nested resolution, caching, and error paths - Robot Framework integration tests verify end-to-end local file resolution - Coverage ≥ 97% on all new code via `nox -s coverage_report` - `nox` full suite passes ## Supporting information - Spec reference: `docs/actor-registry-standard.md` §§5.3, 6.1-6.3, 7.3 - Architecture plan elaborated in session — 8 files to create/modify, ~215 lines of changes - Patterns: Repository (`LocalPackageStore`), Strategy (three resolution types), Template Method (unified resolution flow), Adapter (filesystem → package interface), Proxy (caching layer), Dependency Injection, Guard Clause (path validation) - New file: `src/cleveractors/registry/local_store.py` - Modified: `reference_resolver.py`, `resolver.py`, `canonical.py`, `base.py`, `registry.py`, `enhanced_registry.py`, `__init__.py` ## Subtasks - [ ] Implement `LocalPackage` frozen dataclass and `LocalPackageStore` class with path validation guard clauses - [ ] Implement recursive nested `local:` reference resolution (`_walk_and_resolve`) - [ ] Implement `_detect_package_type()` heuristic (infer `PackageType` from content structure) - [ ] Extend `Canonicalizer.resolve_references()` to handle `local:` strings alongside `ID:pkg_` - [ ] Add `local_store` parameter to `PackageContentResolver.__init__()`, implement LOCAL resolution in `resolve()` and `aresolve()` - [ ] Add `local_store` parameter to `ReferenceResolver.__init__()`, implement LOCAL resolution in `resolve()` - [ ] Rename `_resolve_registry_ref` → `_resolve_package_ref` in `base.py`, add `local_store` parameter - [ ] Modify `TemplateRegistry`: rename `_try_parse_registry_ref` → `_try_parse_package_ref`, accept LOCAL + REGISTRY, inject `local_store` - [ ] Mirror changes to `EnhancedTemplateRegistry` - [ ] Export `LocalPackage`, `LocalPackageStore` from `registry/__init__.py` - [ ] Behave BDD unit tests: path validation, resolution, nested refs, caching, error paths (`features/`) - [ ] Robot Framework integration tests: end-to-end local file resolution (`robot/`) - [ ] Verify coverage ≥ 97% via `nox -s coverage_report` - [ ] Run `nox` (all default sessions), fix any errors ## Definition of Done This issue is complete when: - All subtasks above are completed and checked off. - A Git commit is created where the first line matches the Commit Message in Metadata exactly. - The commit is pushed to the branch matching the Branch field in Metadata exactly. - The commit is submitted as a PR to master, reviewed, and merged. - `nox` full suite passes (lint, typecheck, security, unit_tests, coverage_report). - Coverage on new modules ≥ 97%. - A template referencing `local:path/to/actor.yaml` resolves correctly through the full chain.
CoreRasurae added this to the v2.1.0 milestone 2026-06-11 20:27:00 +00:00
Author
Member

Child of Epic #22 — Package Registry Client.

Depends on:

  • #23 (core data types — PackageReference.from_string for local: parsing)
  • #25 (canonicalization — Canonicalizer for SHA-1 PackageId computation)
  • #26 (reference resolution — ReferenceResolver/PackageContentResolver infrastructure)
  • #27 (template alignment — TemplateRegistry/EnhancedTemplateRegistry integration)
  • #28 (caching — LRU cache for resolved LOCAL packages)

Architecture plan elaborated in opencode session. New module: src/cleveractors/registry/local_store.py. Modified: reference_resolver.py, resolver.py, canonical.py, base.py, registry.py, enhanced_registry.py, __init__.py.

Child of Epic #22 — Package Registry Client. Depends on: - #23 (core data types — PackageReference.from_string for `local:` parsing) - #25 (canonicalization — Canonicalizer for SHA-1 PackageId computation) - #26 (reference resolution — ReferenceResolver/PackageContentResolver infrastructure) - #27 (template alignment — TemplateRegistry/EnhancedTemplateRegistry integration) - #28 (caching — LRU cache for resolved LOCAL packages) Architecture plan elaborated in opencode session. New module: `src/cleveractors/registry/local_store.py`. Modified: `reference_resolver.py`, `resolver.py`, `canonical.py`, `base.py`, `registry.py`, `enhanced_registry.py`, `__init__.py`.
Author
Member

PR submitted: #47feature/m1-local-reference-resolution

Full implementation of local namespace reference resolution with LocalPackageStore, nested resolution, and template registry integration.

PR submitted: #47 — `feature/m1-local-reference-resolution` Full implementation of local namespace reference resolution with LocalPackageStore, nested resolution, and template registry integration.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
cleveragents/cleveractors-core#46
No description provided.