generated from coulomb/repo-seed
Complete memory graph and document value workplans
This commit is contained in:
@@ -21,6 +21,8 @@ def test_builtin_extension_registry_lists_query_processors_and_backend():
|
||||
assert "runtime.assessment" in ids
|
||||
assert "policy.local-label" in ids
|
||||
assert "document.function" in ids
|
||||
assert "memory.graph-contract" in ids
|
||||
assert "memory.runtime-adapter-boundary" in ids
|
||||
assert "memory.context-package" in ids
|
||||
assert "source.adapter-registry" in ids
|
||||
|
||||
@@ -131,6 +133,9 @@ def test_builtin_document_function_descriptor_exposes_deterministic_boundary():
|
||||
assert descriptor.kind == "document-function"
|
||||
assert descriptor.safety["network"] is False
|
||||
assert descriptor.metadata["external_policy_services_required"] is False
|
||||
assert descriptor.metadata["typed_values"] is True
|
||||
assert "table" in descriptor.metadata["value_kinds"]
|
||||
assert descriptor.metadata["render_export_execution"] is False
|
||||
assert {capability.id for capability in descriptor.capabilities} >= {
|
||||
"document_function",
|
||||
"deterministic",
|
||||
@@ -158,3 +163,22 @@ def test_builtin_memory_descriptor_exposes_local_optional_boundary():
|
||||
}
|
||||
assert "mkt context pack" in descriptor.cli["commands"]
|
||||
assert "mkt context activate" in descriptor.cli["commands"]
|
||||
|
||||
|
||||
def test_builtin_memory_graph_descriptor_exposes_runtime_handoff_boundaries():
|
||||
registry = builtin_extension_registry()
|
||||
|
||||
graph = registry.get("memory.graph-contract")
|
||||
adapters = registry.get("memory.runtime-adapter-boundary")
|
||||
|
||||
assert graph.kind == "memory-contract"
|
||||
assert graph.safety["external_memory_services"] is False
|
||||
assert "mkt memory graph pack" in graph.cli["commands"]
|
||||
assert "examples/memory/conversation-path.yaml" in graph.examples
|
||||
assert "examples/memory/knowledge-neighborhood.yaml" in graph.examples
|
||||
assert "memory.runtime.kontextual-engine" in graph.metadata["runtime_adapter_boundaries"]
|
||||
assert "memory.audit.sink" in graph.metadata["runtime_adapter_boundaries"]
|
||||
assert adapters.kind == "memory-runtime-adapter"
|
||||
assert adapters.safety["runtime_execution"] is False
|
||||
assert adapters.metadata["services_launched_by_markitect_tool"] is False
|
||||
assert "examples/memory/runtime-adapter-boundaries.yaml" in adapters.examples
|
||||
|
||||
@@ -19,6 +19,7 @@ def test_collect_cli_command_specs_from_builtin_registry():
|
||||
assert ("backend.local-sqlite", "mkt cache index") in commands
|
||||
assert ("backend.local-sqlite", "mkt search") in commands
|
||||
assert ("document.function", "mkt function render") in commands
|
||||
assert ("memory.graph-contract", "mkt memory graph pack") in commands
|
||||
assert ("memory.context-package", "mkt context pack") in commands
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,12 @@ from markitect_tool.document_function import (
|
||||
DocumentFunctionDescriptor,
|
||||
DocumentFunctionParameter,
|
||||
DocumentFunctionRegistry,
|
||||
DocumentValue,
|
||||
MAX_FUNCTION_PIPELINE_DEPTH,
|
||||
coerce_document_value,
|
||||
default_document_function_registry,
|
||||
document_value_to_json,
|
||||
format_document_value,
|
||||
parse_document_function_calls,
|
||||
render_document_functions,
|
||||
validate_document_functions,
|
||||
@@ -51,6 +56,20 @@ Decision
|
||||
assert "### Decision" in result.content
|
||||
assert len(result.calls) == 2
|
||||
assert result.provenance[0].operation == "document_function.text.upper"
|
||||
assert result.calls[0].value.kind == "string"
|
||||
assert result.calls[1].value.kind == "markdown"
|
||||
|
||||
|
||||
def test_document_values_coerce_and_map_to_markdown():
|
||||
table = coerce_document_value(
|
||||
[{"name": "Ada", "role": "Architect"}, {"name": "Grace", "role": "Reviewer"}],
|
||||
declared_kind="table",
|
||||
)
|
||||
|
||||
assert document_value_to_json(table)["kind"] == "table"
|
||||
assert format_document_value(DocumentValue(kind="boolean", value=True), inline=True) == "true"
|
||||
assert "| name | role |" in format_document_value(table, inline=False)
|
||||
assert "| Ada | Architect |" in format_document_value(table, inline=False)
|
||||
|
||||
|
||||
def test_pipeline_passes_previous_output_to_next_function():
|
||||
@@ -67,6 +86,17 @@ def test_pipeline_separator_inside_quotes_is_literal():
|
||||
assert result.content == "a/b"
|
||||
|
||||
|
||||
def test_pipeline_depth_limit_reports_syntax_error():
|
||||
expression = " | ".join(["text.trim value"] * (MAX_FUNCTION_PIPELINE_DEPTH + 1))
|
||||
|
||||
try:
|
||||
parse_document_function_calls("{{mkt:" + expression + "}}")
|
||||
except Exception as exc:
|
||||
assert "maximum depth" in str(exc)
|
||||
else:
|
||||
raise AssertionError("Expected pipeline depth diagnostic")
|
||||
|
||||
|
||||
def test_context_variables_can_be_used_in_function_arguments():
|
||||
context = ProcessingContext(variables={"title": "Architecture Decision"})
|
||||
|
||||
@@ -75,6 +105,16 @@ def test_context_variables_can_be_used_in_function_arguments():
|
||||
assert result.content == "## Architecture Decision"
|
||||
|
||||
|
||||
def test_dynamic_context_values_render_through_typed_mapper():
|
||||
context = ProcessingContext(variables={"items": ["alpha", "beta"]})
|
||||
|
||||
result = render_document_functions("{{mkt:data.get items}}", context=context)
|
||||
|
||||
assert result.valid
|
||||
assert result.content == "alpha, beta"
|
||||
assert result.calls[0].value.kind == "list"
|
||||
|
||||
|
||||
def test_validate_document_functions_reports_forbidden_calls():
|
||||
result = validate_document_functions("{{mkt:text.upper draft}}", forbidden=["text.upper"])
|
||||
|
||||
@@ -106,6 +146,41 @@ def test_registry_can_expose_custom_function_without_core_rewrite():
|
||||
assert result.content == "[ok]"
|
||||
|
||||
|
||||
def test_descriptor_output_type_mismatch_is_diagnostic():
|
||||
registry = DocumentFunctionRegistry()
|
||||
registry.register(
|
||||
DocumentFunctionDescriptor(
|
||||
id="demo.count",
|
||||
summary="Return a count.",
|
||||
output_type="number",
|
||||
implementation=lambda: "not-a-number",
|
||||
)
|
||||
)
|
||||
|
||||
result = render_document_functions("{{mkt:demo.count}}", registry=registry)
|
||||
|
||||
assert not result.valid
|
||||
assert result.content == "{{mkt:demo.count}}"
|
||||
assert result.diagnostics[0].code == "function.output_type_mismatch"
|
||||
|
||||
|
||||
def test_reference_values_require_provenance():
|
||||
registry = DocumentFunctionRegistry()
|
||||
registry.register(
|
||||
DocumentFunctionDescriptor(
|
||||
id="demo.reference",
|
||||
summary="Return a reference.",
|
||||
output_type="reference",
|
||||
implementation=lambda: DocumentValue(kind="reference", value="std:clause.md#payment"),
|
||||
)
|
||||
)
|
||||
|
||||
result = render_document_functions("{{mkt:demo.reference}}", registry=registry)
|
||||
|
||||
assert not result.valid
|
||||
assert result.diagnostics[0].code == "function.provenance_missing"
|
||||
|
||||
|
||||
def test_unknown_function_is_left_in_place_with_diagnostic():
|
||||
result = render_document_functions("{{mkt:nope.missing value}}")
|
||||
|
||||
@@ -133,6 +208,17 @@ def test_mkt_function_render_outputs_expanded_markdown(tmp_path: Path):
|
||||
assert "**Important**" in result.output
|
||||
|
||||
|
||||
def test_mkt_function_render_json_includes_typed_values(tmp_path: Path):
|
||||
file = tmp_path / "functions.md"
|
||||
file.write_text("{{mkt:text.upper draft}}\n", encoding="utf-8")
|
||||
|
||||
result = CliRunner().invoke(main, ["function", "render", str(file), "--format", "json"])
|
||||
data = json.loads(result.output)
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert data["calls"][0]["value"] == {"kind": "string", "value": "DRAFT"}
|
||||
|
||||
|
||||
def test_mkt_function_check_can_restrict_allowed_functions(tmp_path: Path):
|
||||
file = tmp_path / "functions.md"
|
||||
file.write_text("{{mkt:text.upper draft}}\n", encoding="utf-8")
|
||||
@@ -148,3 +234,4 @@ def test_default_registry_serializes_without_implementations():
|
||||
|
||||
assert data["count"] >= 1
|
||||
assert "implementation" not in data["functions"][0]
|
||||
assert {function["id"]: function["output_type"] for function in data["functions"]}["data.get"] == "dynamic"
|
||||
|
||||
@@ -48,6 +48,62 @@ def test_memory_graph_validation_and_context_package_compile(tmp_path: Path):
|
||||
assert package.retrieval_recipes[0].kind == "memory-graph-selection"
|
||||
|
||||
|
||||
def test_memory_graph_example_fixtures_cover_reasoning_conversation_and_knowledge():
|
||||
examples = Path("examples/memory")
|
||||
profile = load_memory_profile_file(examples / "memory-profile.local.yaml")
|
||||
|
||||
for graph_name, selection_name, package_title, expected_node_count in [
|
||||
(
|
||||
"decision-graph.yaml",
|
||||
"decision-graph-selection.yaml",
|
||||
"Memory Contract Boundary Package",
|
||||
3,
|
||||
),
|
||||
(
|
||||
"conversation-path.yaml",
|
||||
"conversation-path-selection.yaml",
|
||||
"Conversation Episode Package",
|
||||
4,
|
||||
),
|
||||
(
|
||||
"knowledge-neighborhood.yaml",
|
||||
"knowledge-neighborhood-selection.yaml",
|
||||
"Knowledge Neighborhood Package",
|
||||
6,
|
||||
),
|
||||
]:
|
||||
graph = load_memory_graph_file(examples / graph_name)
|
||||
selection = load_memory_graph_selection_file(examples / selection_name)
|
||||
validation = validate_memory_graph(graph, path=examples / graph_name)
|
||||
package = compile_memory_graph_selection_to_context_package(graph, selection, profile=profile)
|
||||
|
||||
assert validation.valid, validation.to_dict()
|
||||
assert package.title == package_title
|
||||
assert package.metadata["memory_graph"]["selected_nodes"] == selection.node_ids
|
||||
assert len(selection.node_ids) == expected_node_count
|
||||
assert package.metadata["memory_profile"]["id"] == "local-agent-memory"
|
||||
|
||||
|
||||
def test_memory_graph_invalid_example_fixtures_emit_errors():
|
||||
examples = Path("examples/memory")
|
||||
graph = load_memory_graph_file(examples / "invalid-memory-graph.yaml")
|
||||
profile = load_memory_profile_file(examples / "invalid-memory-profile.yaml")
|
||||
|
||||
graph_result = validate_memory_graph(graph, path=examples / "invalid-memory-graph.yaml")
|
||||
profile_result = validate_memory_profile(profile, path=examples / "invalid-memory-profile.yaml")
|
||||
|
||||
graph_codes = {diagnostic.code for diagnostic in graph_result.diagnostics}
|
||||
profile_codes = {diagnostic.code for diagnostic in profile_result.diagnostics}
|
||||
|
||||
assert not graph_result.valid
|
||||
assert "memory.graph.node.unknown_kind" in graph_codes
|
||||
assert "memory.graph.edge.unknown_target" in graph_codes
|
||||
assert "memory.graph.event.unknown_kind" in graph_codes
|
||||
assert not profile_result.valid
|
||||
assert "memory.profile.unknown_kind" in profile_codes
|
||||
assert "memory.profile.store_missing" in profile_codes
|
||||
|
||||
|
||||
def test_mkt_memory_blueprint_and_graph_cli(tmp_path: Path):
|
||||
_write_profile(tmp_path)
|
||||
_write_graph(tmp_path)
|
||||
|
||||
Reference in New Issue
Block a user