generated from coulomb/repo-seed
distribute/proposals.py: Scope-aware targeting (FR-X2, empty axis = any), render distributable (approved+distribution_ready) patterns into a proposals/ tree mirroring target paths — proposed not applied (FR-X3, HITL), idempotent on re-run. ActiveRegistry (FR-X4) records which pattern+version is proposed in which (repo,flavor). 6 new tests; suite 123/123. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
80 lines
3.0 KiB
Python
80 lines
3.0 KiB
Python
"""Scoping + proposals + active registry tests (WP-0007 T04)."""
|
|
|
|
import os
|
|
import sys
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
|
|
from session_memory.curate.schema import Resolution, Scope, SolutionPattern # noqa: E402
|
|
from session_memory.distribute.proposals import ( # noqa: E402
|
|
ActiveRegistry,
|
|
Target,
|
|
applies,
|
|
propose,
|
|
)
|
|
|
|
|
|
def _pattern(pid="sp-x", repos=None, flavors=None, status="approved", ready=True):
|
|
return SolutionPattern(
|
|
id=pid, name="Read before edit", version="1.0.0", polarity="problem",
|
|
problem="edit before read", resolutions=[Resolution(summary="read first")],
|
|
scope=Scope(repos=repos or [], flavors=flavors or []),
|
|
status=status, distribution_ready=ready,
|
|
)
|
|
|
|
|
|
def test_applies_respects_scope():
|
|
p = _pattern(repos=["agentic-resources"], flavors=["claude"])
|
|
assert applies(p, Target("agentic-resources", flavor="claude"))
|
|
assert not applies(p, Target("other-repo", flavor="claude"))
|
|
assert not applies(p, Target("agentic-resources", flavor="codex"))
|
|
|
|
|
|
def test_empty_scope_is_unrestricted():
|
|
assert applies(_pattern(), Target("any", flavor="grok"))
|
|
|
|
|
|
def test_propose_writes_scoped_proposal_files(tmp_path):
|
|
out = str(tmp_path / "proposals")
|
|
reg = ActiveRegistry(str(tmp_path / "active.json"))
|
|
p = _pattern(flavors=["claude"])
|
|
res = propose([p], [Target("agentic-resources", flavor="claude"),
|
|
Target("agentic-resources", flavor="codex")], out, reg)
|
|
# only claude target is in scope
|
|
assert len(res.proposals) == 1
|
|
path = os.path.join(out, "agentic-resources", "CLAUDE.md")
|
|
assert os.path.exists(path)
|
|
assert "BEGIN helix-forge pattern:sp-x" in open(path).read()
|
|
|
|
|
|
def test_not_distributable_skipped(tmp_path):
|
|
reg = ActiveRegistry(str(tmp_path / "active.json"))
|
|
prov = _pattern(status="provisional", ready=False)
|
|
res = propose([prov], [Target("r", flavor="claude")], str(tmp_path / "p"), reg)
|
|
assert res.proposals == []
|
|
assert "sp-x" in res.skipped_not_distributable
|
|
|
|
|
|
def test_proposals_idempotent_on_rerun(tmp_path):
|
|
out = str(tmp_path / "proposals")
|
|
reg_path = str(tmp_path / "active.json")
|
|
p = _pattern()
|
|
propose([p], [Target("r", flavor="claude")], out, ActiveRegistry(reg_path))
|
|
propose([p], [Target("r", flavor="claude")], out, ActiveRegistry(reg_path))
|
|
content = open(os.path.join(out, "r", "CLAUDE.md")).read()
|
|
assert content.count("BEGIN helix-forge pattern:sp-x") == 1 # no duplication
|
|
|
|
|
|
def test_active_registry_records_environment(tmp_path):
|
|
reg_path = str(tmp_path / "active.json")
|
|
reg = ActiveRegistry(reg_path)
|
|
propose([_pattern()], [Target("r", domain="helix_forge", flavor="claude")],
|
|
str(tmp_path / "p"), reg)
|
|
reg2 = ActiveRegistry(reg_path) # reload from disk
|
|
entries = reg2.entries()
|
|
assert len(entries) == 1
|
|
assert entries[0]["pattern_id"] == "sp-x"
|
|
assert entries[0]["repo"] == "r"
|
|
assert entries[0]["flavor"] == "claude"
|
|
assert entries[0]["status"] == "proposed"
|