generated from coulomb/repo-seed
distribute/base.py: Artifact dataclass + Distributor protocol + idempotent BEGIN/END snippet markers (upsert_block replaces a pattern's block in place so re-distribution doesn't duplicate) + agnostic markdown body rendering from SolutionPattern fields. BaseDistributor honours per-flavor body/target hints. 8 new tests; suite 110/110. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
89 lines
3.1 KiB
Python
89 lines
3.1 KiB
Python
"""Distributor base tests (WP-0007 T01): markers, idempotent upsert, rendering."""
|
|
|
|
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, SolutionPattern # noqa: E402
|
|
from session_memory.distribute.base import ( # noqa: E402
|
|
Artifact,
|
|
BaseDistributor,
|
|
Distributor,
|
|
render_markdown_body,
|
|
upsert_block,
|
|
wrap_block,
|
|
)
|
|
|
|
|
|
def _pattern(pid="sp-x", polarity="problem"):
|
|
return SolutionPattern(
|
|
id=pid, name="Read before edit", version="1.2.0", polarity=polarity,
|
|
problem="Agents edit files they have not read.",
|
|
resolutions=[Resolution(summary="Read the file first", detail="then Edit",
|
|
steps=["Read", "Edit"])],
|
|
rendering_hints={"claude": {"target": "CLAUDE.md"}},
|
|
)
|
|
|
|
|
|
def test_render_markdown_body_has_problem_and_resolution():
|
|
body = render_markdown_body(_pattern())
|
|
assert "### Read before edit" in body
|
|
assert "Agents edit files" in body
|
|
assert "**Avoid:**" in body # problem polarity
|
|
assert "- Read the file first — then Edit" in body
|
|
assert " - Read" in body
|
|
|
|
|
|
def test_success_polarity_label():
|
|
assert "**Prefer:**" in render_markdown_body(_pattern(polarity="success"))
|
|
|
|
|
|
def test_wrap_block_has_markers_and_version():
|
|
block = wrap_block("sp-x", "hello", "1.2.0")
|
|
assert block.startswith("<!-- BEGIN helix-forge pattern:sp-x --> v1.2.0")
|
|
assert block.rstrip().endswith("<!-- END helix-forge pattern:sp-x -->")
|
|
|
|
|
|
def test_upsert_inserts_then_replaces_in_place():
|
|
doc = "# Title\n\nsome text\n"
|
|
b1 = wrap_block("sp-x", "first", "1")
|
|
once = upsert_block(doc, "sp-x", b1)
|
|
assert "first" in once and once.count("BEGIN helix-forge pattern:sp-x") == 1
|
|
# re-distributing the same id replaces, does not duplicate
|
|
b2 = wrap_block("sp-x", "second", "2")
|
|
twice = upsert_block(once, "sp-x", b2)
|
|
assert "second" in twice and "first" not in twice
|
|
assert twice.count("BEGIN helix-forge pattern:sp-x") == 1
|
|
|
|
|
|
def test_upsert_keeps_other_patterns():
|
|
doc = upsert_block("", "sp-a", wrap_block("sp-a", "A"))
|
|
doc = upsert_block(doc, "sp-b", wrap_block("sp-b", "B"))
|
|
assert "sp-a" in doc and "sp-b" in doc
|
|
|
|
|
|
def test_base_distributor_renders_artifact():
|
|
d = BaseDistributor(flavor="claude", target_path="CLAUDE.md")
|
|
art = d.render(_pattern())
|
|
assert isinstance(art, Artifact)
|
|
assert isinstance(d, Distributor) # satisfies the protocol
|
|
assert art.flavor == "claude"
|
|
assert art.target_path == "CLAUDE.md"
|
|
assert "BEGIN helix-forge pattern:sp-x" in art.content
|
|
assert "Read before edit" in art.content
|
|
|
|
|
|
def test_body_hint_overrides_default():
|
|
p = _pattern()
|
|
p.rendering_hints["claude"]["body"] = "custom claude body"
|
|
d = BaseDistributor(flavor="claude", target_path="CLAUDE.md")
|
|
assert "custom claude body" in d.render(p).content
|
|
|
|
|
|
def test_target_hint_overrides_default():
|
|
p = _pattern()
|
|
p.rendering_hints["claude"]["target"] = "docs/CLAUDE.md"
|
|
d = BaseDistributor(flavor="claude", target_path="CLAUDE.md")
|
|
assert d.render(p).target_path == "docs/CLAUDE.md"
|