from mcp_tool_provenance import (
# envelope
stamp, is_stamped, TOULMIN_KEYS, TAG_KEYS,
# vendored envelope value objects (re-exported)
ToulminArgument, QualifierLevel, DataAvailability, ArtifactTags, make_tags,
# triage
triage, drift_check, assert_no_drift, surface_summary, classified_set,
DriftReport, DriftError, BUCKETS,
)Wrap a tool/RPC response with a provenance envelope. Returns a new dict; result is not mutated.
| Param | Type | Notes |
|---|---|---|
result |
Mapping |
The payload to stamp. Its keys pass through verbatim. |
toulmin |
ToulminArgument | Mapping |
The reasoning. A ToulminArgument (its data_availability is dropped from the envelope), or a five-key mapping (claim / grounds / warrant / qualifier / rebuttal). |
tags |
ArtifactTags | Mapping |
The provenance tags. An ArtifactTags, or a four-key mapping (scope / signal_type / attribution / uncertainty). |
tool_name |
str |
Optional. Recorded under _tool when non-empty; the key is omitted when blank. |
Output shape: {**result, "_tool"?: tool_name, "_toulmin": {5 keys}, "_tags": {4 keys}}.
Raises ValueError if a dict input is missing required keys; TypeError for a wrong-typed input.
True iff result carries both a complete _toulmin (all five keys) and a complete _tags (all four keys). Useful as a runtime/CI assertion at the stamping boundary.
The fixed key tuples: ("claim", "grounds", "warrant", "qualifier", "rebuttal") and ("scope", "signal_type", "attribution", "uncertainty").
ToulminArgument(claim, grounds, warrant, qualifier, rebuttal, data_availability)—.to_dict()/.from_dict().QualifierLevel—CERTAIN/PROBABLE/PLAUSIBLE/TENTATIVE/DEFEATED.DataAvailability—SUFFICIENT/PARTIAL/MISSING.ArtifactTags(scope, signal_type, attribution, uncertainty)—.to_dict()/.render_footer().make_tags(scope=, signal_type=, attribution=, uncertainty=)— convenience constructor.
(These come from the vendored toulmin-argument and provenance-tags kernels; see ../KERNEL_SYNC.md.)
("real_dispatch", "read_only", "native_only") — the fixed, mutually-exclusive, collectively-exhaustive surface buckets. Also the reporting order.
real_dispatch— executes + writes/persists server-side (a real action).read_only— real server-side reads, no writes.native_only— guidance only; interactive / generator, not a server one-shot.
Build a surface map {bucket: (sorted, deduped tools...)} for all three buckets (each always present, possibly empty).
Verify classification is MECE over registry. Never raises — reports. ok=True only when every registry tool is in exactly one bucket, no tool is in two buckets, every bucket name is in BUCKETS, and no classified name is absent from the registry.
Raising variant of drift_check — raises DriftError (carrying the DriftReport on .report) on any drift; returns the clean report otherwise. The CI gate.
The honest, reportable split:
| Key | Meaning |
|---|---|
total |
number of tools in the registry |
surface |
{bucket: [sorted tools]} |
counts |
per-bucket counts |
executes_server_side |
counts["real_dispatch"] + counts["read_only"] — the honest "really acts" count |
native_only_count |
guidance-only count |
all_tools |
sorted registry |
unclassified |
registry tools in no bucket — must be [] (built-in drift guard) |
The set of every tool named in any bucket.
Dataclass: ok: bool, unclassified: list, multiply_classified: dict[str, list[str]], unknown_buckets: list, unknown_tools: list. .to_dict().
Exception raised by assert_no_drift. Carries the structured .report.