@agenomics/sas-resolver
v0.1.0
Published
ADR-064 reference resolver for ADR-061 manifest-referenced SAS attestations. Off-chain only; dereferences manifest.agent.owner_attestation, parses AEP_AGENT_REPUTATION_v1, and surfaces merge helpers for registry + SAS UX.
Maintainers
Readme
@agenomics/sas-resolver
Reference resolver for the SAS (Solana Attestation Service) integration described in ADR-061 and the caching strategy in ADR-065.
Consumes a validated AEP capability manifest (see
@agenomics/capability-manifest-validator)
and resolves the optional agent.owner_attestation SAS pointer into a
typed reputation snapshot. Implements the 7-step flow in ADR-061 §4
faithfully — subject-mismatch is the one hard error; every other failure
mode (missing attestation, schema mismatch, expiry, credential not in
allowlist) degrades to absent: true so SAS stays strictly additive.
Install
npm install @agenomics/sas-resolverPeer deps: @solana/kit@^6.8, @noble/curves@^1.4. Optional runtime
dep: ioredis@^5.4 (only needed if AEP_REDIS_URL is set — the
in-memory cache is the default).
Usage
import { createSolanaRpc } from "@solana/kit";
import { SasResolver, createCache } from "@agenomics/sas-resolver";
const resolver = new SasResolver({
rpc: createSolanaRpc("https://api.mainnet-beta.solana.com"),
allowedCredentials: new Set([
"<AEP_PROTOCOL credential PDA>",
"<AEP_VALIDATORS credential PDA>",
]),
schemaPda: "<AEP_AGENT_REPUTATION_v1 schema PDA>",
cache: createCache(process.env), // ADR-065: in-memory or Redis-backed
});
const result = await resolver.resolve(manifest, subjectAuthority);
// ^ CapabilityManifest (already validated)
// ^ base58 agent authority pubkey
if (!result.ok) throw new Error(result.error.message);
const reputation = result.value;
if (reputation.absent) {
// No owner_attestation, or attestation missing/expired/unsupported — SAS has no signal.
} else {
console.log("SAS score (bps):", reputation.attestation.score);
console.log("completed_tasks:", reputation.attestation.completed_tasks);
console.log("stale?", reputation.stale);
}Caching (ADR-065)
The resolver caches three SAS layers: attestation (5 min default),
schema (1 hour default), credential (1 hour default). TTLs are
configurable via ResolverConfig.ttl. Per-call overrides:
// Force-fresh read (e.g., a protocol-logic path that must see current state)
await resolver.resolve(manifest, subject, { maxAge: 0 });
// Accept up to 30s stale
await resolver.resolve(manifest, subject, { maxAge: 30_000 });Multi-instance deployments can set AEP_REDIS_URL and the factory
returns a LayeredCache (in-memory L1 + Redis L2). Pattern mirrors
mcp-server/src/pipeline/idempotency.ts
from ADR-059.
Merge helpers
The resolver ships a few convenience helpers for the ADR-061 §4 "display side-by-side, don't blend" merge convention:
import { renderSideBySide, detectDisagreement, scoreFreshness } from "@agenomics/sas-resolver";
const lines = renderSideBySide(onChainReputation, reputation); // { line1, line2 }
const disagrees = detectDisagreement(onChainReputation, reputation); // > 2000 bps delta
const freshness = scoreFreshness(reputation.attestation.last_updated, Date.now());
// 'fresh' | 'aging' | 'stale'Non-goals
- Does not fetch the Registry account or the manifest body — consume a pre-validated manifest.
- Does not validate the manifest — use
@agenomics/capability-manifest-validatorupstream. - Does not mint, close, or rotate attestations — read-only client.
- Does not take on-chain governance actions — see ADR-063 for the credential authority lifecycle.
Related
- ADR-061 — integration model + resolution flow + merge semantics
- ADR-063 — credential authority governance (Proposed)
- ADR-064 — this package
- ADR-065 — caching strategy
License
Part of the Agenomics Protocol. See repository root.
