generated from coulomb/repo-seed
155 lines
4.9 KiB
Python
155 lines
4.9 KiB
Python
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
|
|
pytestmark = [pytest.mark.integration, pytest.mark.markitect_tool]
|
|
|
|
mkt = pytest.importorskip(
|
|
"markitect_tool",
|
|
reason="Install kontextual-engine[markdown] to run markitect-tool contract tests.",
|
|
)
|
|
|
|
|
|
SAMPLE_MARKDOWN = """---
|
|
document_type: decision
|
|
status: accepted
|
|
policy:
|
|
labels: [public]
|
|
---
|
|
|
|
# Engine Boundary
|
|
|
|
## Context
|
|
|
|
The engine needs Markdown-native structure without owning a Markdown parser.
|
|
|
|
## Decision
|
|
|
|
Use markitect-tool as the syntax and deterministic operations layer.
|
|
|
|
## Consequences
|
|
|
|
- Engine assets stay cross-format.
|
|
- Markdown selectors stay Markitect-owned.
|
|
"""
|
|
|
|
|
|
def test_markitect_parser_returns_structured_markdown_document() -> None:
|
|
document = mkt.parse_markdown(SAMPLE_MARKDOWN, source_path="docs/decision.md")
|
|
serialized = document.to_dict()
|
|
|
|
assert serialized["frontmatter"]["status"] == "accepted"
|
|
assert serialized["source_path"] == "docs/decision.md"
|
|
assert [heading["text"] for heading in serialized["headings"]] == [
|
|
"Engine Boundary",
|
|
"Context",
|
|
"Decision",
|
|
"Consequences",
|
|
]
|
|
assert any(section["heading"]["text"] == "Decision" for section in serialized["sections"])
|
|
|
|
|
|
def test_markitect_selectors_extract_source_grounded_markdown_units() -> None:
|
|
document = mkt.parse_markdown(SAMPLE_MARKDOWN)
|
|
|
|
matches = mkt.query_document(document, "sections[heading=Decision]")
|
|
extracted = mkt.extract_document(document, "sections[heading=Decision]")
|
|
|
|
assert len(matches) == 1
|
|
assert matches[0].kind == "section"
|
|
assert matches[0].line is not None
|
|
assert "deterministic operations layer" in matches[0].text
|
|
assert extracted == [
|
|
"## Decision\n\nUse markitect-tool as the syntax and deterministic operations layer."
|
|
]
|
|
|
|
|
|
def test_markitect_ops_resolve_includes_transform_and_return_provenance(tmp_path: Path) -> None:
|
|
partial = tmp_path / "partial.md"
|
|
partial.write_text(
|
|
"# Included\n\n## Decision\n\nReuse Markitect operations.\n",
|
|
encoding="utf-8",
|
|
)
|
|
|
|
included = mkt.resolve_includes(
|
|
'{{include:partial.md}}',
|
|
base_dir=tmp_path,
|
|
)
|
|
transformed = mkt.transform_markdown(
|
|
included.markdown,
|
|
set_frontmatter={"status": "draft"},
|
|
heading_delta=1,
|
|
source_path="composed.md",
|
|
)
|
|
|
|
assert included.included_paths == [str(partial.resolve())]
|
|
assert included.provenance[0].operation == "include"
|
|
assert included.provenance[0].target_path == str(partial.resolve())
|
|
assert "status: draft" in transformed.markdown
|
|
assert "## Included" in transformed.markdown
|
|
assert "### Decision" in transformed.markdown
|
|
assert [event.operation for event in transformed.provenance] == [
|
|
"set_frontmatter",
|
|
"shift_headings",
|
|
]
|
|
|
|
|
|
def test_markitect_snapshot_identity_is_content_addressed_adapter_metadata(tmp_path: Path) -> None:
|
|
source = tmp_path / "decision.md"
|
|
source.write_text(SAMPLE_MARKDOWN, encoding="utf-8")
|
|
|
|
first = mkt.snapshot_identity_for_file(source, parse_options={"profile": "default"})
|
|
second = mkt.snapshot_identity_for_file(source, parse_options={"profile": "default"})
|
|
changed = mkt.snapshot_identity_for_file(source, parse_options={"profile": "strict"})
|
|
|
|
assert first.snapshot_id == second.snapshot_id
|
|
assert first.content_hash == second.content_hash
|
|
assert first.parser == "markdown-it-py/commonmark"
|
|
assert first.snapshot_id != changed.snapshot_id
|
|
assert first.to_dict()["source_path"] == str(source)
|
|
|
|
|
|
def test_markitect_context_packages_filter_by_local_policy(tmp_path: Path) -> None:
|
|
public = tmp_path / "public.md"
|
|
private = tmp_path / "private.md"
|
|
public.write_text(
|
|
"---\npolicy:\n labels: [public]\n---\n# Public\n\nVisible context.\n",
|
|
encoding="utf-8",
|
|
)
|
|
private.write_text(
|
|
"---\npolicy:\n labels: [internal]\n---\n# Private\n\nHidden context.\n",
|
|
encoding="utf-8",
|
|
)
|
|
package = mkt.create_context_package_from_sources(
|
|
"document",
|
|
[public, private],
|
|
root=tmp_path,
|
|
namespace=mkt.MemoryNamespace(project="kontextual-engine", task="boundary"),
|
|
budget=mkt.ContextBudget(max_items=5),
|
|
)
|
|
gateway = mkt.LocalLabelPolicyGateway(
|
|
{
|
|
"id": "kontextual-engine-boundary",
|
|
"subjects": {
|
|
"reader": {
|
|
"allowed_labels": ["public"],
|
|
"allowed_actions": ["read", "activate"],
|
|
}
|
|
},
|
|
"default_subject": "reader",
|
|
}
|
|
)
|
|
|
|
activation = mkt.activate_context_package(
|
|
package,
|
|
policy_gateway=gateway,
|
|
subject="reader",
|
|
)
|
|
|
|
assert package.namespace.project == "kontextual-engine"
|
|
assert len(activation.items) == 1
|
|
assert "Visible context" in activation.content
|
|
assert "Hidden context" not in activation.content
|
|
assert activation.policy["summary"]["denied"] == 1
|