feat: WP-0007 — Interface Completeness & Evidence

T01: markidocx inspect (FR-806) and markidocx test (FR-810) CLI commands
T02: markidocx evidence get/list CLI commands (FR-1409, FR-814)
T03: list_styles() / GET /styles / MCP list_styles with real style data (FR-907)
T04: Evidence assembly — EvidenceSet summary via REST and MCP (FR-1406–1408)
T05: LEVEL3 edge-case tests — diagram mutation, renderer version check,
     bibliography duplicate keys / missing refs / special chars (FR-534, FR-538, FR-542)
T06: markidocx template extract + Word-first round-trip regression test (FR-606)

New: differ._compare_diagram_blocks tracks fenced diagram source drift (FR-534)
New: diagrams.check_renderer_version emits warning for outdated renderers (FR-538)
New: bibliography.validate_citations detects duplicate keys and missing entries (FR-542)
New: templates.extract_template / TemplateExtractionResult / list_styles / StyleEntry
New: REST POST /template/extract; MCP extract_template tool

278 tests pass, ruff+mypy clean.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-17 19:30:09 +00:00
parent 893b9fa57b
commit 9fe64bcd7f
16 changed files with 1537 additions and 19 deletions

View File

@@ -85,6 +85,9 @@ def compare(original: str, reimported: str) -> DriftReport:
# --- Figures (FR-532, FR-541) ---
_compare_figures(original, reimported, preserved, degraded, broken)
# --- Diagram source blocks (FR-534) ---
_compare_diagram_blocks(original, reimported, preserved, degraded, broken)
# --- Citations & Bibliography (FR-535, FR-542) ---
from markidocx.bibliography import compare_citations
@@ -181,6 +184,38 @@ def _compare_xrefs(
degraded.append(f"xref-link:degraded [{link_text}][{anchor}]")
_FENCED_BLOCK_RE = re.compile(r"```(\w+)\n(.*?)```", re.DOTALL)
def _extract_fenced_blocks(text: str) -> list[tuple[str, str]]:
"""Extract all fenced code blocks as (language, source) pairs."""
return [(m.group(1).strip().lower(), m.group(2).rstrip()) for m in _FENCED_BLOCK_RE.finditer(text)]
def _compare_diagram_blocks(
original: str,
reimported: str,
preserved: list[str],
degraded: list[str],
broken: list[str],
) -> None:
"""Compare diagram fenced blocks for source-content drift (FR-534)."""
from markidocx.diagrams import DIAGRAM_TYPES
orig_blocks = [(lang, src) for lang, src in _extract_fenced_blocks(original) if lang in DIAGRAM_TYPES]
reim_blocks = [(lang, src) for lang, src in _extract_fenced_blocks(reimported) if lang in DIAGRAM_TYPES]
for i, (lang, src) in enumerate(orig_blocks):
if i < len(reim_blocks):
reim_lang, reim_src = reim_blocks[i]
if lang == reim_lang and src == reim_src:
preserved.append(f"diagram:{lang}[{i}]")
else:
degraded.append(f"diagram:{lang}[{i}]:source-mutated")
else:
broken.append(f"diagram:{lang}[{i}]:missing")
def _compare_sets(
kind: str,
orig: list[str],