The source-agnostic corroboration kernel — Resolver[T], the View contract, a pure diff, and the Corroborator. Zero runtime dependencies.
Project description
sm-resolver — the corroboration kernel
A tiny, dependency-free kernel for detecting when independent sources disagree about the same subject. Point it at two or more sources, ask them the same question, and it reports any disagreement. It is the machinery under cross-registry / cross-method divergence detection, factored out so any layer can reuse it.
Four pieces, and only the resolvers know a wire format:
View— the contract a claim implements:comparable() → {field: value}. Those fields are what gets compared; aNonevalue never participates.Resolver[T]— a per-source adapter: a canonical id →(Status, View). It hides one source's format (an HTTP GET, a DID resolve, a DNS lookup) and MUST NOT raise — an unreachable source iserror(no claim), never a falseabsent.diff_views— the pure diff: per-source claims →Findinglist. It emitsomission(present on one source, positively absent on another) and one finding per view field whose values disagree. It never learns its layer.Corroborator— resolve every source, diff, and emit new findings once (deduped). Fewer than two sources → no-op.
Install
pip install sm-resolver # zero runtime dependencies
Use
Supply a view (its fields are what you compare) and a thin resolver per source:
import asyncio
from collections.abc import Mapping
from dataclasses import dataclass
from sm_resolver import Corroborator, Status
@dataclass(frozen=True)
class RecordView: # your layer's view
endpoint: str | None = None
def comparable(self) -> Mapping[str, str | None]:
return {"endpoint": self.endpoint}
class MyResolver: # your thin per-source adapter
def __init__(self, label): self.label = label
async def resolve(self, agent_id) -> tuple[Status, RecordView | None]:
... # query this source; normalize to RecordView
findings = asyncio.run(
Corroborator([MyResolver("a"), MyResolver("b")]).check(["agent-1"])
)
for f in findings:
print(f.kind, f.agent_id, f.detail)
# endpoint agent-1 {'field': 'endpoint', 'values': {'a': 'https://real', 'b': 'https://evil'}}
Long-running? Pass on_finding= — it fires once per distinct finding across the
corroborator's lifetime.
Who uses it
sm-divergence builds the
reference layers on this kernel: a discovery layer (registries — NEST, the
NANDA Index) and an identity layer (DID methods — did:key, did:web,
Universal Resolver), each supplying its own view and thin resolvers. Capability
and evidence layers are the same shape.
Design rules
- A timeout is not a claim. An unreachable or erroring source is excluded, never counted as an omission.
- Only present, comparable values disagree. A
Nonefield contributes nothing — an unverifiable value is not a disagreement. - The diff stays pure and generic — deterministic, no I/O, never raises, never learns its layer. All I/O lives in the resolvers.
Develop
make ci-local # uv: sync → ruff → format → mypy --strict → pytest
License
First published: 2026-07-04 | Last modified: 2026-07-04
Personal research contributions aligned with Project NANDA standards. Stellarminds.ai
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sm_resolver-0.1.0.tar.gz.
File metadata
- Download URL: sm_resolver-0.1.0.tar.gz
- Upload date:
- Size: 36.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2517272794fd0b433cef92cfd71e05976c4f9778b34eee7706e53c8858e8dff7
|
|
| MD5 |
02df9f1be249775f3098e25dc003d28f
|
|
| BLAKE2b-256 |
c63739891a611a0872fa191e80dad49ff68b1ee6e2c92bfd4e16c61981a13232
|
Provenance
The following attestation bundles were made for sm_resolver-0.1.0.tar.gz:
Publisher:
release.yml on Sharathvc23/sm-resolver
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sm_resolver-0.1.0.tar.gz -
Subject digest:
2517272794fd0b433cef92cfd71e05976c4f9778b34eee7706e53c8858e8dff7 - Sigstore transparency entry: 2074224332
- Sigstore integration time:
-
Permalink:
Sharathvc23/sm-resolver@928af2355cedec1c1847597c5de23ac522306e62 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Sharathvc23
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@928af2355cedec1c1847597c5de23ac522306e62 -
Trigger Event:
push
-
Statement type:
File details
Details for the file sm_resolver-0.1.0-py3-none-any.whl.
File metadata
- Download URL: sm_resolver-0.1.0-py3-none-any.whl
- Upload date:
- Size: 9.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d091079ff0e1b1f75fbc282d61909942ddc92ce93e260b4a7b10dd449b54e90d
|
|
| MD5 |
2014e0e259cdba133fdc1a084260eab2
|
|
| BLAKE2b-256 |
0dcd126190e94f687b1707260ebf333c66ee22ada960887812bff2084ec799b8
|
Provenance
The following attestation bundles were made for sm_resolver-0.1.0-py3-none-any.whl:
Publisher:
release.yml on Sharathvc23/sm-resolver
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sm_resolver-0.1.0-py3-none-any.whl -
Subject digest:
d091079ff0e1b1f75fbc282d61909942ddc92ce93e260b4a7b10dd449b54e90d - Sigstore transparency entry: 2074224731
- Sigstore integration time:
-
Permalink:
Sharathvc23/sm-resolver@928af2355cedec1c1847597c5de23ac522306e62 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/Sharathvc23
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@928af2355cedec1c1847597c5de23ac522306e62 -
Trigger Event:
push
-
Statement type: