Files
GEWU/tests/api/test_mcp_contribution.py
vasily 78033bb830
CI / quality (push) Canceled after 0s
feat: online verification, node removals, and knowledge browser
Adds claim-bound online evidence records and citation verification scripts,
node removal transport/adapter, retrieval benchmark and owner-review tooling,
GraphCanvas/SourceDetail knowledge browser UI, and the ingest handoff helper.
Bumps the agents/gewu pack to the online-verification branch.
2026-10-16 20:02:29 +08:00

1127 lines
57 KiB
Python

import asyncio
import base64
import hashlib
import json
import socket
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from pathlib import Path
from typing import Any
import httpx2
from mcp import Client
from mcp.client.streamable_http import streamable_http_client
from mcp.types import TextContent
from gewu.adapters.git_repository import GitCanonicalRepository
from gewu.adapters.source_extractor import LocalSourceExtractor
from gewu.adapters.sqlite_identity import SQLiteIdentityStore
from gewu.adapters.sqlite_ingest_reviews import SQLiteIngestReviewStore
from gewu.adapters.url_fetch import PublicUrlFetcher
from gewu.application.acceptance import AcceptanceService
from gewu.application.context import ValidationContext
from gewu.application.reading import CanonicalNodeReader
from gewu.application.uploads import LocalArtifactStore
from gewu.bootstrap.app import create_app
from gewu.domain.contracts import ProposalOperation, ProposalRevision, Scope, SourceRevisionRecord
from gewu.domain.validation import evidence_digest, proposal_payload_digest
from gewu.transports.stdio_connector import SelectedFile, create_connector_server
from tests.domain.proposal_fixtures import (
BLOCK_TEXT,
NODE,
POLICIES,
PROJECTS,
SOURCE_REVISION,
proposal,
)
class _FixtureResponse:
def __init__(self, media_type: str, content: bytes, status: int = 200) -> None:
self.media_type = media_type
self.content = content
self.status = status
self.offset = 0
def getheader(self, name: str) -> str | None:
return {
"Content-Type": f"{self.media_type}; charset=utf-8",
"X-Source-Title": "Allowlisted fixture",
}.get(name)
def read(self, amount: int) -> bytes:
result = self.content[self.offset : self.offset + amount]
self.offset += len(result)
return result
class _FixtureConnection:
def __init__(self) -> None:
self.closed = False
self.path = ""
def request(self, _method: str, path: str, headers: dict[str, str]) -> None:
self.path = path
assert headers["Accept-Encoding"] == "identity"
return None
def getresponse(self) -> _FixtureResponse:
if self.path.startswith("/missing"):
return _FixtureResponse("text/plain", b"unavailable", status=404)
if self.path.startswith("/source.md?rev=2"):
return _FixtureResponse("text/markdown", b"# Captured fixture\nRevised evidence.\n")
if self.path.startswith("/page.html"):
return _FixtureResponse(
"text/html",
b"<article><h1>Web evidence</h1><p>Exact HTML statement.</p>"
b"<script>ignoreInjection()</script></article>",
)
if self.path.startswith("/paper.pdf"):
return _FixtureResponse("application/pdf", _pdf_fixture())
if self.path.startswith("/malformed.pdf"):
return _FixtureResponse("application/pdf", b"%PDF-1.4\nnot a valid PDF")
return _FixtureResponse(
"text/markdown", b"# Captured fixture\nAn exact source statement.\n"
)
def close(self) -> None:
self.closed = True
def _fixture_fetcher() -> PublicUrlFetcher:
def resolver(host: str, port: int, **_kwargs: Any) -> list[tuple[Any, ...]]:
return [(socket.AF_INET, socket.SOCK_STREAM, 6, "", ("93.184.216.34", port))]
return PublicUrlFetcher(
{"research.example"},
resolver=resolver,
connection_factory=lambda *_args: _FixtureConnection(),
)
def _text_payload(result: Any) -> str:
assert result.content and isinstance(result.content[0], TextContent)
return result.content[0].text
def _pdf_fixture() -> bytes:
stream = b"BT /F1 12 Tf 72 720 Td (Archived PDF evidence.) Tj ET"
objects = [
b"<< /Type /Catalog /Pages 2 0 R >>",
b"<< /Type /Pages /Kids [4 0 R] /Count 1 >>",
b"<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>",
b"<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] "
b"/Resources << /Font << /F1 3 0 R >> >> /Contents 5 0 R >>",
b"<< /Length " + str(len(stream)).encode() + b" >>\nstream\n" + stream + b"\nendstream",
]
result = bytearray(b"%PDF-1.4\n")
offsets = [0]
for number, item in enumerate(objects, start=1):
offsets.append(len(result))
result.extend(f"{number} 0 obj\n".encode() + item + b"\nendobj\n")
xref = len(result)
result.extend(f"xref\n0 {len(offsets)}\n0000000000 65535 f \n".encode())
for offset in offsets[1:]:
result.extend(f"{offset:010d} 00000 n \n".encode())
result.extend(
f"trailer\n<< /Size {len(offsets)} /Root 1 0 R >>\nstartxref\n{xref}\n%%EOF\n".encode()
)
return bytes(result)
def test_mcp_source_to_citation_vertical_slice(tmp_path: Path) -> None:
async def exercise() -> None:
repository = GitCanonicalRepository(tmp_path / "knowledge.git")
artifacts = LocalArtifactStore(tmp_path)
extractor = LocalSourceExtractor()
context = ValidationContext(
projects=PROJECTS,
policies=POLICIES,
sources={},
extractions={},
existing_nodes={},
)
identities = SQLiteIdentityStore(
tmp_path / "identity.sqlite3",
authority_lock_path=tmp_path / "workflow/locks/canonical-writer.lock",
)
token = identities.provision(
credential_id="pilot-agent-key",
principal_id="agent-pilot",
roles=("agent",),
project_ids=("dome-performance", "shared"),
)
viewer_token = identities.provision(
credential_id="pilot-viewer-key",
principal_id="pilot-viewer",
roles=("viewer",),
project_ids=("dome-performance", "shared"),
)
acceptance = AcceptanceService(
repository=repository,
artifact_store=artifacts,
workflow_root=tmp_path / "workflow",
context_provider=lambda: context,
actor_is_current=lambda actor: identities.is_current(
actor.principal_id,
actor.credential_id,
roles=actor.roles,
project_ids=actor.project_ids,
),
)
app = create_app(
identity_provider=identities,
node_reader=CanonicalNodeReader(repository),
artifact_store=artifacts,
extractor=extractor,
acceptance_service=acceptance,
context_provider=lambda: context,
url_fetcher=_fixture_fetcher(),
ingest_review_store=SQLiteIngestReviewStore(tmp_path / "ingest-reviews.sqlite3"),
)
async with app.router.lifespan_context(app):
async with httpx2.AsyncClient(
transport=httpx2.ASGITransport(app=app),
base_url="http://localhost",
headers={"Authorization": f"Bearer {token}"},
) as http:
async with Client(
streamable_http_client("http://localhost/mcp", http_client=http)
) as mcp:
tools = await mcp.list_tools()
assert {tool.name for tool in tools.tools} == {
"diagnostics",
"get_node",
"node_history",
"get_project_context",
"get_source",
"ingest_review_create",
"source_upload_begin",
"source_capture_text",
"source_capture_url",
"source_upload_status",
"source_upload_chunk",
"source_upload_finalize",
"source_extract",
"source_extraction_block",
"proposal_prepare",
"proposal_evaluate",
"proposal_submit",
"proposal_status",
"proposal_withdraw",
"run_create",
"run_checkpoint",
"run_status",
}
project_context = await mcp.call_tool(
"get_project_context", {"project_id": "dome-performance"}
)
assert not project_context.is_error
lens_result = json.loads(_text_payload(project_context))
assert (
lens_result["lens"]["north_star"] == PROJECTS["dome-performance"].north_star
)
assert lens_result["lens"]["key_questions"] == list(
PROJECTS["dome-performance"].key_questions
)
assert "autonomy_policy_id" not in lens_result["lens"]
draft = proposal().model_dump(mode="json")
draft.pop("payload_digest")
for operation in draft["operations"]:
node = operation.get("node")
if node is None:
continue
for group in ("claims", "assumptions", "limitations"):
for claim in node.get(group, []):
claim["assessment"].pop("assertion_digest")
claim["assessment"].pop("evidence_digests")
for evidence in claim["evidence"]:
evidence.pop("assertion_path")
evidence.pop("assertion_digest")
prepared_result = await mcp.call_tool(
"proposal_prepare",
{"proposal_json": json.dumps(draft, ensure_ascii=False)},
)
assert not prepared_result.is_error, prepared_result.content
prepared_payload = json.loads(_text_payload(prepared_result))
assert prepared_payload["status"] == "prepared"
prepared_proposal = ProposalRevision.model_validate_json(
prepared_payload["proposal_json"], strict=True
)
assert prepared_payload["payload_digest"] == prepared_proposal.payload_digest
assert prepared_proposal.payload_digest == proposal_payload_digest(
prepared_proposal
)
truncated_evaluation = await mcp.call_tool(
"proposal_evaluate",
{"proposal_json": prepared_payload["proposal_json"][:-1]},
)
assert not truncated_evaluation.is_error, truncated_evaluation.content
truncated_evaluation_payload = json.loads(_text_payload(truncated_evaluation))
assert truncated_evaluation_payload["proposal_id"] == (
prepared_proposal.proposal_id
)
assert truncated_evaluation_payload["input_repaired"] is True
malformed_prepare = await mcp.call_tool(
"proposal_prepare", {"proposal_json": '{"schema_version":'}
)
assert not malformed_prepare.is_error, malformed_prepare.content
malformed_prepare_payload = json.loads(_text_payload(malformed_prepare))
assert malformed_prepare_payload["status"] == "invalid"
assert malformed_prepare_payload["issues"][0]["code"] == (
"invalid_proposal_draft"
)
malformed_evaluation = await mcp.call_tool(
"proposal_evaluate", {"proposal_json": '{"schema_version":'}
)
assert not malformed_evaluation.is_error, malformed_evaluation.content
malformed_evaluation_payload = json.loads(_text_payload(malformed_evaluation))
assert malformed_evaluation_payload["status"] == "invalid"
assert malformed_evaluation_payload["findings"][0]["code"] == (
"PROPOSAL_JSON_INVALID"
)
invalid_draft = json.loads(json.dumps(draft))
invalid_evidence = invalid_draft["operations"][1]["node"]["claims"][0][
"evidence"
][0]
invalid_evidence["locator"]["kind"] = "text_span"
invalid_evidence["locator"]["page"] = 1
invalid_result = await mcp.call_tool(
"proposal_prepare",
{"proposal_json": json.dumps(invalid_draft, ensure_ascii=False)},
)
assert not invalid_result.is_error, invalid_result.content
invalid_payload = json.loads(_text_payload(invalid_result))
assert invalid_payload["status"] == "invalid"
assert any(
issue["path"].endswith("locator") and "PDF locators" in issue["message"]
for issue in invalid_payload["issues"]
)
invalid_review = await mcp.call_tool(
"ingest_review_create", {"review_json": "{}"}
)
assert not invalid_review.is_error, invalid_review.content
review_payload = json.loads(_text_payload(invalid_review))
assert review_payload["status"] == "invalid"
assert {issue["path"] for issue in review_payload["issues"]} >= {
"review_id",
"extraction_id",
"relevance_rationale",
}
project_only_token = identities.provision(
credential_id="project-only-source-agent-key",
principal_id="agent-project-only",
roles=("agent",),
project_ids=("dome-performance",),
)
project_only_draft = json.loads(json.dumps(draft))
project_only_draft["proposal_id"] = "proposal-project-only-source"
project_only_draft["scope"]["include_shared"] = False
project_only_draft["proposer_id"] = "agent-project-only"
project_only_draft["operations"] = [project_only_draft["operations"][0]]
async with httpx2.AsyncClient(
transport=httpx2.ASGITransport(app=app),
base_url="http://localhost",
headers={"Authorization": f"Bearer {project_only_token}"},
) as project_only_http:
async with Client(
streamable_http_client(
"http://localhost/mcp", http_client=project_only_http
)
) as project_only_mcp:
project_source = await project_only_mcp.call_tool(
"proposal_prepare",
{"proposal_json": json.dumps(project_only_draft)},
)
assert not project_source.is_error, project_source.content
assert json.loads(_text_payload(project_source))["status"] == "prepared"
shared_draft = json.loads(json.dumps(project_only_draft))
shared_draft["proposal_id"] = "proposal-project-only-shared-source"
shared_draft["operations"][0]["source"]["ingested_for"] = ["shared"]
shared_source = await project_only_mcp.call_tool(
"proposal_prepare",
{"proposal_json": json.dumps(shared_draft)},
)
assert shared_source.is_error
denied_lens = await mcp.call_tool(
"get_project_context", {"project_id": "interactive-video"}
)
assert denied_lens.is_error
async with httpx2.AsyncClient(
transport=httpx2.ASGITransport(app=app),
base_url="http://localhost",
headers={"Authorization": f"Bearer {viewer_token}"},
) as viewer_http:
async with Client(
streamable_http_client("http://localhost/mcp", http_client=viewer_http)
) as viewer_mcp:
viewer_proposal = await viewer_mcp.call_tool(
"proposal_submit",
{"proposal_json": proposal().model_dump_json()},
)
assert viewer_proposal.is_error
viewer_prepare = await viewer_mcp.call_tool(
"proposal_prepare",
{"proposal_json": json.dumps(draft, ensure_ascii=False)},
)
assert viewer_prepare.is_error
viewer_upload = await viewer_mcp.call_tool(
"source_upload_begin",
{
"project_id": "dome-performance",
"filename": "viewer.md",
"media_type": "text/markdown",
"byte_length": 4,
"expected_sha256": hashlib.sha256(b"data").hexdigest(),
},
)
assert viewer_upload.is_error
viewer_paste = await viewer_mcp.call_tool(
"source_capture_text",
{
"capture_id": "viewer-capture-1",
"project_id": "dome-performance",
"source_key": "viewer-paste",
"text": "Viewer supplied text",
},
)
assert viewer_paste.is_error
diagnostics_result = await mcp.call_tool(
"diagnostics",
{"projects": ["dome-performance"], "include_shared": True},
)
assert not diagnostics_result.is_error
diagnostics = json.loads(_text_payload(diagnostics_result))
assert diagnostics["workflow_status"] == "not_verified"
assert diagnostics["selected_scope"]["include_shared"] is True
assert "proposal_submit" in diagnostics["authorized_operations"]
assert "run_checkpoint" in diagnostics["authorized_operations"]
assert token not in _text_payload(diagnostics_result)
run_request = {
"run_id": "mcp-run-pilot",
"objective": "Compare audience response",
"scope": {
"projects": ["dome-performance"],
"include_shared": False,
"all_projects": False,
},
"lens": "Audience behavior",
"pack_id": "gewu",
"pack_version": "0.3.0",
"pack_snapshot_digest": "a" * 64,
"module_pins": [
{
"module_id": "profile",
"implementation_version": "1.0.0",
"sha256": "b" * 64,
}
],
}
invalid_run = await mcp.call_tool("run_create", {"request_json": "{}"})
assert not invalid_run.is_error
invalid_run_result = json.loads(_text_payload(invalid_run))
assert invalid_run_result["status"] == "invalid"
assert "run_id" in {issue["path"] for issue in invalid_run_result["issues"]}
created_run = await mcp.call_tool(
"run_create", {"request_json": json.dumps(run_request)}
)
assert not created_run.is_error
run_record = json.loads(_text_payload(created_run))
assert run_record["revision"] == 0
checkpoint = {
"run_id": "mcp-run-pilot",
"expected_revision": 0,
"stage": "source-review",
}
saved_run = await mcp.call_tool(
"run_checkpoint", {"request_json": json.dumps(checkpoint)}
)
assert not saved_run.is_error
assert json.loads(_text_payload(saved_run))["revision"] == 1
invalid_checkpoint = await mcp.call_tool(
"run_checkpoint",
{
"request_json": json.dumps(
{
**checkpoint,
"expected_revision": 1,
"coverage": {"skipped": ["pending source"]},
}
)
},
)
assert not invalid_checkpoint.is_error
invalid_result = json.loads(_text_payload(invalid_checkpoint))
assert invalid_result["status"] == "invalid"
assert invalid_result["issues"][0]["path"] == "coverage.skipped[0]"
assert "pending source" not in _text_payload(invalid_checkpoint)
read_run = await mcp.call_tool("run_status", {"run_id": "mcp-run-pilot"})
assert not read_run.is_error
assert json.loads(_text_payload(read_run))["revision"] == 1
denied = await mcp.call_tool(
"source_upload_begin",
{
"project_id": "interactive-video",
"filename": "private.md",
"media_type": "text/markdown",
"byte_length": 4,
"expected_sha256": "0" * 64,
},
)
assert denied.is_error
forbidden_capture = await mcp.call_tool(
"source_capture_url",
{
"project_id": "interactive-video",
"url": "https://research.example/source.md",
},
)
assert forbidden_capture.is_error
forbidden_paste = await mcp.call_tool(
"source_capture_text",
{
"capture_id": "out-of-scope-paste-1",
"project_id": "interactive-video",
"source_key": "out-of-scope-paste",
"text": "Must not be uploaded",
},
)
assert forbidden_paste.is_error
unallowlisted_capture = await mcp.call_tool(
"source_capture_url",
{
"project_id": "dome-performance",
"url": "https://internal.example/private",
},
)
assert unallowlisted_capture.is_error
captured = await mcp.call_tool(
"source_capture_url",
{
"project_id": "dome-performance",
"url": "https://research.example/source.md?token=do-not-echo",
},
)
assert not captured.is_error
capture_result = json.loads(_text_payload(captured))
assert capture_result["title"] == "Allowlisted fixture"
assert capture_result["media_type"] == "text/markdown"
assert "do-not-echo" not in _text_payload(captured)
assert capture_result["original_url"] == ("https://research.example/source.md")
captured_source = SourceRevisionRecord.model_validate_json(
json.dumps(capture_result["source_candidate"]), strict=True
)
assert captured_source.archive_status == "archived"
assert captured_source.final_url == "https://research.example/source.md"
assert captured_source.artifact_sha256 == capture_result["sha256"]
assert captured_source.capture_method == "url-fetch"
assert f":r:{captured_source.artifact_sha256}:" in captured_source.revision_id
pasted_text = "## Meeting note\nPasted evidence: 400 visitors.\n"
pasted_arguments = {
"capture_id": "interview-paste-1",
"project_id": "dome-performance",
"source_key": "research-interview-2026-10-14",
"text": pasted_text,
"title": "Research interview notes",
"original_url": "https://research.example/interview?token=secret",
"media_type": "text/markdown",
"source_type": "internal",
}
pasted = await mcp.call_tool("source_capture_text", pasted_arguments)
assert not pasted.is_error
pasted_retry = await mcp.call_tool("source_capture_text", pasted_arguments)
assert not pasted_retry.is_error
assert json.loads(_text_payload(pasted_retry)) == json.loads(
_text_payload(pasted)
)
changed_paste_retry = await mcp.call_tool(
"source_capture_text",
{**pasted_arguments, "text": pasted_text + "changed"},
)
assert changed_paste_retry.is_error
invalid_capture_id = await mcp.call_tool(
"source_capture_text",
{**pasted_arguments, "capture_id": "invalid capture id"},
)
assert invalid_capture_id.is_error
pasted_result = json.loads(_text_payload(pasted))
pasted_source = SourceRevisionRecord.model_validate_json(
json.dumps(pasted_result["source_candidate"]), strict=True
)
assert pasted_source.capture_method == "pasted-text"
assert pasted_source.original_url == "https://research.example/interview"
assert "secret" not in _text_payload(pasted)
capture_journal = tmp_path / "staging" / "capture-receipts"
assert all(
pasted_text.encode() not in path.read_bytes()
for path in capture_journal.glob("*.json")
)
assert (
pasted_source.artifact_sha256
== hashlib.sha256(pasted_text.encode()).hexdigest()
)
assert pasted_result["byte_length"] == len(pasted_text.encode())
assert pasted_result["extraction_id"]
pasted_extraction = artifacts.get_extraction(
pasted_result["extraction_id"],
owner_id="agent-pilot",
project_id="dome-performance",
)
assert pasted_extraction is not None
assert pasted_extraction.source_revision_id == pasted_source.revision_id
assert (
"Pasted evidence: 400 visitors."
in pasted_extraction.blocks[0].original_text
)
oversized_paste = await mcp.call_tool(
"source_capture_text",
{
"capture_id": "oversized-paste-1",
"project_id": "dome-performance",
"source_key": "oversized-paste",
"text": "x" * 1_000_001,
},
)
assert oversized_paste.is_error
control_character_paste = await mcp.call_tool(
"source_capture_text",
{
"capture_id": "invalid-paste-1",
"project_id": "dome-performance",
"source_key": "invalid-paste",
"text": "unsafe\x00content",
},
)
assert control_character_paste.is_error
oversized_author_paste = await mcp.call_tool(
"source_capture_text",
{
"capture_id": "invalid-author-paste-1",
"project_id": "dome-performance",
"source_key": "invalid-author-paste",
"text": "valid body",
"authors": ["a" * 301],
},
)
assert oversized_author_paste.is_error
changed_capture = await mcp.call_tool(
"source_capture_url",
{
"project_id": "dome-performance",
"url": "https://research.example/source.md?rev=2",
},
)
assert not changed_capture.is_error
changed_source = SourceRevisionRecord.model_validate_json(
json.dumps(json.loads(_text_payload(changed_capture))["source_candidate"]),
strict=True,
)
assert changed_source.source_id == captured_source.source_id
assert changed_source.revision_id != captured_source.revision_id
with artifacts.open_artifact(
capture_result["sha256"], project_id="dome-performance"
) as artifact:
assert artifact.read() == (
b"# Captured fixture\nAn exact source statement.\n"
)
failed_capture = await mcp.call_tool(
"source_capture_url",
{
"project_id": "dome-performance",
"url": "https://research.example/missing?access-token=must-not-leak",
"title": "Temporarily unavailable paper",
"source_type": "paper",
},
)
assert not failed_capture.is_error
failed_result = json.loads(_text_payload(failed_capture))
failed_source = SourceRevisionRecord.model_validate_json(
json.dumps(failed_result["source_candidate"]), strict=True
)
assert failed_result["status"] == "capture_failed"
assert failed_source.archive_status == "capture-failed"
assert failed_source.artifact_sha256 is None
assert "access-token" not in _text_payload(failed_capture)
failed_proposal = ProposalRevision(
proposal_id="proposal-failed-url-capture",
revision=1,
initiating_project_id="dome-performance",
scope=Scope(projects=("dome-performance",), include_shared=True),
base_commit=repository.head(),
payload_digest="0" * 64,
proposer_id="agent-pilot",
run_id="run-failed-url-capture",
operations=(
ProposalOperation(operation="register_source", source=failed_source),
),
)
failed_proposal = failed_proposal.model_copy(
update={"payload_digest": proposal_payload_digest(failed_proposal)}
)
registered_failure = await mcp.call_tool(
"proposal_submit",
{"proposal_json": failed_proposal.model_dump_json()},
)
assert not registered_failure.is_error
assert (
json.loads(_text_payload(registered_failure))["receipt"]["state"]
== "accepted"
)
captured_html = await mcp.call_tool(
"source_capture_url",
{
"project_id": "dome-performance",
"url": "https://research.example/page.html",
},
)
assert not captured_html.is_error
html_result = json.loads(_text_payload(captured_html))
assert html_result["media_type"] == "text/html"
html_extraction_result = await mcp.call_tool(
"source_extract",
{
"project_id": "dome-performance",
"artifact_sha256": html_result["sha256"],
"source_revision_id": "shared:web-page:r1",
},
)
assert not html_extraction_result.is_error
html_extraction = json.loads(_text_payload(html_extraction_result))
html_block_result = await mcp.call_tool(
"source_extraction_block",
{
"project_id": "dome-performance",
"extraction_id": html_extraction["extraction_id"],
"block_id": html_extraction["blocks"][0]["block_id"],
"offset": 0,
"length": 500,
},
)
assert not html_block_result.is_error
html_block = json.loads(_text_payload(html_block_result))
assert html_block["normalization_profile"] == "unicode-nfc-lf-v1"
assert "Exact HTML statement." in html_block["normalized_text"]
assert "original_text" not in html_block
assert "normalization_map" not in html_block
mapped_html_result = await mcp.call_tool(
"source_extraction_block",
{
"project_id": "dome-performance",
"extraction_id": html_extraction["extraction_id"],
"block_id": html_extraction["blocks"][0]["block_id"],
"offset": 0,
"length": 500,
"include_original_mapping": True,
},
)
assert not mapped_html_result.is_error
mapped_html = json.loads(_text_payload(mapped_html_result))
assert (
mapped_html["normalization_profile"] == html_block["normalization_profile"]
)
assert mapped_html["original_text"]
assert len(mapped_html["normalization_map"]) == len(
mapped_html["normalized_text"]
)
assert "ignoreInjection" not in html_block["normalized_text"]
captured_pdf = await mcp.call_tool(
"source_capture_url",
{
"project_id": "dome-performance",
"url": "https://research.example/paper.pdf",
},
)
assert not captured_pdf.is_error
pdf_result = json.loads(_text_payload(captured_pdf))
assert pdf_result["media_type"] == "application/pdf"
with artifacts.open_artifact(
pdf_result["sha256"], project_id="dome-performance"
) as artifact:
assert artifact.read() == _pdf_fixture()
pdf_extracted = await mcp.call_tool(
"source_extract",
{
"project_id": "dome-performance",
"artifact_sha256": pdf_result["sha256"],
"source_revision_id": "shared:pdf:r1",
},
)
assert not pdf_extracted.is_error
pdf_record = json.loads(_text_payload(pdf_extracted))
assert pdf_record["blocks"][0]["page"] == 1
pdf_block_result = await mcp.call_tool(
"source_extraction_block",
{
"project_id": "dome-performance",
"extraction_id": pdf_record["extraction_id"],
"block_id": pdf_record["blocks"][0]["block_id"],
"offset": 0,
"length": 500,
},
)
assert not pdf_block_result.is_error
pdf_block = json.loads(_text_payload(pdf_block_result))
assert pdf_block["normalization_profile"] == "unicode-nfc-lf-v1"
assert pdf_block["page"] == 1
assert "Archived PDF evidence." in pdf_block["normalized_text"]
assert "normalization_map" not in pdf_block
malformed_pdf = await mcp.call_tool(
"source_capture_url",
{
"project_id": "dome-performance",
"url": "https://research.example/malformed.pdf",
},
)
assert not malformed_pdf.is_error
malformed_result = json.loads(_text_payload(malformed_pdf))
malformed_extraction = await mcp.call_tool(
"source_extract",
{
"project_id": "dome-performance",
"artifact_sha256": malformed_result["sha256"],
"source_revision_id": malformed_result["source_candidate"][
"revision_id"
],
},
)
assert not malformed_extraction.is_error
unavailable = json.loads(_text_payload(malformed_extraction))
assert unavailable["status"] == "unavailable"
assert unavailable["error_code"] == "PDF_UNSUPPORTED"
content = BLOCK_TEXT.encode("utf-8")
digest = hashlib.sha256(content).hexdigest()
interrupted_begin = await mcp.call_tool(
"source_upload_begin",
{
"project_id": "dome-performance",
"filename": "interrupted.md",
"media_type": "text/markdown",
"byte_length": len(content),
"expected_sha256": digest,
},
)
assert not interrupted_begin.is_error
interrupted_upload = json.loads(_text_payload(interrupted_begin))
interrupted_finalize = await mcp.call_tool(
"source_upload_finalize",
{"upload_id": interrupted_upload["upload_id"]},
)
assert interrupted_finalize.is_error
uncitable = await mcp.call_tool(
"source_extract",
{
"project_id": "dome-performance",
"artifact_sha256": digest,
"source_revision_id": SOURCE_REVISION.revision_id,
},
)
assert uncitable.is_error
begun = await mcp.call_tool(
"source_upload_begin",
{
"project_id": "dome-performance",
"filename": "pilot.md",
"media_type": "text/markdown",
"byte_length": len(content),
"expected_sha256": digest,
},
)
assert not begun.is_error
upload = json.loads(_text_payload(begun))
wrong_digest_chunk = await mcp.call_tool(
"source_upload_chunk",
{
"upload_id": upload["upload_id"],
"offset": 0,
"content_base64": base64.b64encode(content).decode(),
"chunk_sha256": "0" * 64,
},
)
assert wrong_digest_chunk.is_error
chunked = await mcp.call_tool(
"source_upload_chunk",
{
"upload_id": upload["upload_id"],
"offset": 0,
"content_base64": base64.b64encode(content).decode(),
"chunk_sha256": digest,
},
)
assert not chunked.is_error
finalized = await mcp.call_tool(
"source_upload_finalize", {"upload_id": upload["upload_id"]}
)
assert not finalized.is_error
artifact = json.loads(_text_payload(finalized))
extracted = await mcp.call_tool(
"source_extract",
{
"project_id": "dome-performance",
"artifact_sha256": artifact["sha256"],
"source_revision_id": SOURCE_REVISION.revision_id,
},
)
assert not extracted.is_error
extraction_info = json.loads(_text_payload(extracted))
record = extractor.extract(
SOURCE_REVISION.revision_id, content, "text/markdown"
)
assert extraction_info["extraction_id"] == record.extraction_id
evidence = (
NODE.claims[0]
.evidence[0]
.model_copy(
update={
"extraction_id": record.extraction_id,
"locator": NODE.claims[0]
.evidence[0]
.locator.model_copy(update={"block_id": record.blocks[0].block_id}),
}
)
)
claim = NODE.claims[0].model_copy(
update={
"evidence": (evidence,),
"assessment": NODE.claims[0].assessment.model_copy(
update={"evidence_digests": (evidence_digest(evidence),)}
),
}
)
node = NODE.model_copy(update={"claims": (claim,)})
source = SOURCE_REVISION.model_copy(
update={"artifact_sha256": artifact["sha256"], "byte_length": len(content)}
)
candidate = proposal(node=node, source=source, base_commit=repository.head())
candidate = candidate.model_copy(update={"payload_digest": "0" * 64})
candidate = candidate.model_copy(
update={"payload_digest": proposal_payload_digest(candidate)}
)
wrong_location_evidence = evidence.model_copy(
update={
"quote": "400 visitors",
"locator": evidence.locator.model_copy(update={"start": 0, "end": 13}),
}
)
wrong_location_claim = claim.model_copy(
update={
"evidence": (wrong_location_evidence,),
"assessment": claim.assessment.model_copy(
update={
"evidence_digests": (evidence_digest(wrong_location_evidence),)
}
),
}
)
wrong_location_node = node.model_copy(
update={"claims": (wrong_location_claim,)}
)
wrong_location = proposal(
node=wrong_location_node,
source=source,
base_commit=repository.head(),
)
wrong_location = wrong_location.model_copy(
update={
"proposal_id": "proposal-wrong-location",
"payload_digest": "0" * 64,
}
)
wrong_location = wrong_location.model_copy(
update={"payload_digest": proposal_payload_digest(wrong_location)}
)
head_before_evaluate = repository.head()
invalid_evaluation = await mcp.call_tool(
"proposal_evaluate",
{"proposal_json": wrong_location.model_dump_json()},
)
assert not invalid_evaluation.is_error, invalid_evaluation.content
invalid_evaluation_payload = json.loads(_text_payload(invalid_evaluation))
assert invalid_evaluation_payload["status"] == "invalid"
assert "EVIDENCE_MISMATCH" in {
finding["code"] for finding in invalid_evaluation_payload["findings"]
}
assert repository.head() == head_before_evaluate
rejected = await mcp.call_tool(
"proposal_submit",
{"proposal_json": wrong_location.model_dump_json()},
)
assert not rejected.is_error, rejected.content
rejected_outcome = json.loads(_text_payload(rejected))
assert rejected_outcome["status"] == "invalid"
assert "EVIDENCE_MISMATCH" in {
finding["code"] for finding in rejected_outcome["findings"]
}
rejected_status = await mcp.call_tool(
"proposal_status",
{"proposal_id": "proposal-wrong-location", "revision": 1},
)
assert not rejected_status.is_error, rejected_status.content
rejected_status_payload = json.loads(_text_payload(rejected_status))
assert rejected_status_payload["lifecycle"] == "evaluated"
assert rejected_status_payload["validation_status"] == "invalid"
assert rejected_status_payload["receipt"] is None
assert "quote" not in _text_payload(rejected_status)
withdrawn = await mcp.call_tool(
"proposal_withdraw",
{"proposal_id": "proposal-wrong-location", "revision": 1},
)
assert not withdrawn.is_error, withdrawn.content
assert json.loads(_text_payload(withdrawn))["lifecycle"] == "withdrawn"
resubmitted = await mcp.call_tool(
"proposal_submit",
{"proposal_json": wrong_location.model_dump_json()},
)
assert resubmitted.is_error
candidate_head = repository.head()
valid_evaluation = await mcp.call_tool(
"proposal_evaluate",
{"proposal_json": candidate.model_dump_json()},
)
assert not valid_evaluation.is_error, valid_evaluation.content
valid_evaluation_payload = json.loads(_text_payload(valid_evaluation))
assert valid_evaluation_payload["status"] == "eligible"
assert valid_evaluation_payload["eligible_for_auto_accept"]
assert repository.head() == candidate_head
spoofed_assessment = claim.assessment.model_copy(
update={"assessor_id": "agent-other"}
)
spoofed_claim = claim.model_copy(update={"assessment": spoofed_assessment})
spoofed_node = node.model_copy(update={"claims": (spoofed_claim,)})
spoofed = proposal(
node=spoofed_node,
source=source,
base_commit=repository.head(),
)
spoofed = spoofed.model_copy(update={"payload_digest": "0" * 64})
spoofed = spoofed.model_copy(
update={"payload_digest": proposal_payload_digest(spoofed)}
)
spoofed_result = await mcp.call_tool(
"proposal_evaluate",
{"proposal_json": spoofed.model_dump_json()},
)
assert not spoofed_result.is_error, spoofed_result.content
assert "ASSESSOR_ATTRIBUTION_MISMATCH" in {
finding["code"]
for finding in json.loads(_text_payload(spoofed_result))["findings"]
}
unstored = await mcp.call_tool(
"proposal_status",
{"proposal_id": candidate.proposal_id, "revision": candidate.revision},
)
assert unstored.is_error
submitted = await mcp.call_tool(
"proposal_submit",
{"proposal_json": candidate.model_dump_json()[:-1]},
)
assert not submitted.is_error, submitted.content
outcome = json.loads(_text_payload(submitted))
assert outcome["status"] == "accepted"
assert outcome["validation_status"] == "eligible"
assert outcome["input_repaired"] is True
assert outcome["receipt"] is not None
accepted_head = repository.head()
retried = await mcp.call_tool(
"proposal_submit",
{"proposal_json": candidate.model_dump_json()},
)
assert not retried.is_error, retried.content
retry_outcome = json.loads(_text_payload(retried))
assert retry_outcome["receipt"] == outcome["receipt"]
assert repository.head() == accepted_head
accepted_status = await mcp.call_tool(
"proposal_status",
{"proposal_id": candidate.proposal_id, "revision": candidate.revision},
)
assert not accepted_status.is_error, accepted_status.content
accepted_status_payload = json.loads(_text_payload(accepted_status))
assert accepted_status_payload["lifecycle"] == "accepted"
assert accepted_status_payload["receipt"] == outcome["receipt"]
other_token = identities.provision(
credential_id="other-agent-key",
principal_id="agent-other",
roles=("agent",),
project_ids=("dome-performance",),
)
async with httpx2.AsyncClient(
transport=httpx2.ASGITransport(app=app),
base_url="http://localhost",
headers={"Authorization": f"Bearer {other_token}"},
) as other_http:
async with Client(
streamable_http_client("http://localhost/mcp", http_client=other_http)
) as other_mcp:
private_status = await other_mcp.call_tool(
"proposal_status",
{
"proposal_id": candidate.proposal_id,
"revision": candidate.revision,
},
)
assert private_status.is_error
impersonated_evaluation = await other_mcp.call_tool(
"proposal_evaluate",
{"proposal_json": candidate.model_dump_json()},
)
assert impersonated_evaluation.is_error
unauthorized_withdrawal = await other_mcp.call_tool(
"proposal_withdraw",
{
"proposal_id": candidate.proposal_id,
"revision": candidate.revision,
},
)
assert unauthorized_withdrawal.is_error
read = await mcp.call_tool(
"get_node",
{"project_id": node.project_id, "node_id": node.node_id},
)
assert not read.is_error
envelope = json.loads(_text_payload(read))
assert envelope["canonical_revision"] == outcome["receipt"]["commit_id"]
assert envelope["citations"][0]["quote"] == BLOCK_TEXT
selected_path = tmp_path / "operator-selected.md"
selected_bytes = b"A separately selected source for the stdio bridge.\n"
selected_path.write_bytes(selected_bytes)
@asynccontextmanager
async def remote_client() -> AsyncIterator[Client]:
async with Client(
streamable_http_client("http://localhost/mcp", http_client=http)
) as remote:
yield remote
connector = create_connector_server(
(SelectedFile("source-1", selected_path),), remote_client
)
async with Client(connector) as local:
connector_tools = await local.list_tools()
assert {tool.name for tool in connector_tools.tools} == {
"list_selected_files",
"upload_selected_file",
}
connector_result = await local.call_tool(
"upload_selected_file",
{
"file_id": "source-1",
"project_id": "dome-performance",
"source_revision_id": "dome:connector-probe:r1",
},
)
assert not connector_result.is_error
connector_text = _text_payload(connector_result)
connector_receipt = json.loads(connector_text)
assert (
connector_receipt["sha256"]
== hashlib.sha256(selected_bytes).hexdigest()
)
assert selected_bytes.decode() not in connector_text
asyncio.run(exercise())