techne-sdk 0.3.7

TechneSDK's logic written once: version ranking (eventState) and offline record verification over the published check, shipped to TypeScript as WebAssembly; with opt-in atproto plumbing (service auth, DID resolution, signed labels, proven record fetches, PDS password sessions) behind the `crypto` and `net` features.
Documentation
//! Option (b), as the platform reads it (provenancePolicy#vouchedWriter): a credential counts when its
//! issuer is an admin writer, the commons root or an operator the root names in a
//! `pub.techne.draft.operator` record whose period holds when the app first saw the credential; and it
//! is revoked at its own revocation address (in the issuer's repo) or at the same rkey in the root's
//! repo. The shared fixtures (`fixtures/cases.json`, "operator (option b)") run the main cases through
//! the TypeScript package too; these pin the edges.
use serde_json::{json, Value};
use techne_lexicon_check::{dag_cbor, Endorsements};
use techne_sdk::verify::{verify, Claims, Record};

const ROOT: &str = "did:plc:root";
const OP: &str = "did:plc:op";
const LAB: &str = "did:plc:labeler";
const VERDICT: &str = "pub.techne.draft.verdict";
const UNTRUSTED: &str = "untrusted: no commons credential from a trusted issuer vouches for the author's declaration (revoked, issued outside an operator's period, or the declaration changed since)";

fn rec(uri: &str, value: Value) -> Value {
    let cid = dag_cbor::cid_for_json(&value).expect("cid").to_string();
    json!({"uri": uri, "cid": cid, "value": value})
}

fn declaration() -> Value {
    rec(
        &format!("at://{LAB}/pub.techne.draft.publisher/self"),
        json!({"$type": "pub.techne.draft.publisher", "writes": [VERDICT], "labels": ["spam"], "createdAt": "2026-10-01T00:00:00Z"}),
    )
}

/// `issuer`'s credential over the labeler's declaration, at rkey `c1` in the issuer's repo, first seen at `seen`.
fn credential(issuer: &str, seen: Option<&str>) -> Value {
    let decl = declaration();
    let mut c = rec(
        &format!("at://{issuer}/pub.techne.draft.credential/c1"),
        json!({
            "$type": "pub.techne.draft.credential",
            "issuer": issuer,
            "subject": LAB,
            "record": decl["uri"],
            "cid": decl["cid"],
            "revocation": format!("at://{issuer}/pub.techne.draft.credentialRevocation/c1"),
            "createdAt": "2026-10-01T00:00:00Z",
        }),
    );
    if let Some(seen) = seen {
        c["firstSeen"] = json!(seen);
    }
    c
}

/// The root's operator record for `subject` at `rkey`, with the period's ends as given.
fn operator(repo: &str, rkey: &str, subject: &str, from: Option<&str>, until: Option<&str>) -> Value {
    let mut v = json!({"$type": "pub.techne.draft.operator", "subject": subject, "createdAt": "2026-10-01T00:00:00Z"});
    if let Some(from) = from {
        v["validFrom"] = json!(from);
    }
    if let Some(until) = until {
        v["validUntil"] = json!(until);
    }
    rec(&format!("at://{repo}/pub.techne.draft.operator/{rkey}"), v)
}

fn october(subject_rkey: &str) -> Value {
    operator(ROOT, subject_rkey, OP, Some("2026-10-01T00:00:00Z"), Some("2026-11-01T00:00:00Z"))
}

fn revocation(repo: &str, rkey: &str) -> Value {
    rec(&format!("at://{repo}/pub.techne.draft.credentialRevocation/{rkey}"), json!({"createdAt": "2026-10-20T00:00:00Z"}))
}

fn claims(records: Vec<Value>) -> Claims {
    let mut all = vec![declaration()];
    all.extend(records);
    serde_json::from_value(json!({"root": ROOT, "records": all})).expect("claims")
}

fn verdict() -> Record {
    let subject = json!({"uri": "at://did:plc:x/community.lexicon.calendar.event/e1", "cid": "bafyreihqmazckfmotcirl5zpueuxfz2qal5zcl2tpn22ilgs6gvmirzsx4"});
    serde_json::from_value(rec(&format!("at://{LAB}/{VERDICT}/v1"), json!({"$type": VERDICT, "subject": subject, "values": ["spam"], "createdAt": "2026-10-20T00:00:00Z"})))
        .expect("record")
}

/// Whether the labeler's verdict counts and its chain verifies, under `records` (besides its declaration).
fn counts(records: Vec<Value>) -> bool {
    let claims = claims(records);
    let got = verify(&verdict(), &claims);
    assert_eq!(got.chain_verified, claims.endorses(LAB, VERDICT), "verify and endorses agree");
    assert_eq!(got.valid, got.chain_verified, "a verdict is valid exactly when its chain verifies: {:?}", got.problems);
    if !got.valid {
        assert_eq!(got.problems, vec![UNTRUSTED.to_string()]);
    }
    got.valid
}

#[test]
fn an_operator_credential_first_seen_inside_the_period_counts() {
    assert!(counts(vec![credential(OP, Some("2026-10-20T00:00:00Z")), october(OP)]));
}

#[test]
fn the_period_is_from_inclusive_until_exclusive() {
    assert!(counts(vec![credential(OP, Some("2026-10-01T00:00:00Z")), october(OP)]), "at validFrom");
    assert!(!counts(vec![credential(OP, Some("2026-09-30T23:59:59Z")), october(OP)]), "before validFrom");
    assert!(!counts(vec![credential(OP, Some("2026-11-01T00:00:00Z")), october(OP)]), "at validUntil");
    // A wall clock past validUntil, but its instant (23:30Z) is inside.
    assert!(counts(vec![credential(OP, Some("2026-11-01T00:30:00+01:00")), october(OP)]), "an offset is read as its instant");
}

#[test]
fn an_open_period_and_a_later_period_at_did_millis() {
    assert!(counts(vec![credential(OP, Some("2030-01-01T00:00:00Z")), operator(ROOT, OP, OP, None, None)]), "no ends: always");
    let later = operator(ROOT, &format!("{OP}-1793000000000"), OP, Some("2026-12-01T00:00:00Z"), None);
    assert!(counts(vec![credential(OP, Some("2027-01-01T00:00:00Z")), october(OP), later.clone()]), "inside the later period");
    assert!(!counts(vec![credential(OP, Some("2026-11-15T00:00:00Z")), october(OP), later]), "between the periods");
}

#[test]
fn without_a_first_seen_time_only_an_open_period_holds() {
    assert!(!counts(vec![credential(OP, None), october(OP)]));
    assert!(counts(vec![credential(OP, None), operator(ROOT, OP, OP, None, None)]));
}

#[test]
fn only_the_roots_own_operator_record_for_that_did_counts() {
    let seen = Some("2026-10-20T00:00:00Z");
    assert!(!counts(vec![credential(OP, seen)]), "no operator record");
    let elsewhere = operator(OP, OP, OP, None, None);
    assert!(!counts(vec![credential(OP, seen), elsewhere]), "an operator record in the operator's own repo");
    assert!(!counts(vec![credential(OP, seen), operator(ROOT, OP, "did:plc:other", None, None)]), "another subject at the rkey");
    assert!(!counts(vec![credential(OP, seen), operator(ROOT, "did:plc:other", OP, None, None)]), "another rkey for the subject");
    assert!(!counts(vec![credential(OP, seen), operator(ROOT, &format!("{OP}x"), OP, None, None)]), "a DID that only starts with it");
    let mut tampered = october(OP);
    tampered["value"]["validUntil"] = json!("2027-01-01T00:00:00Z");
    assert!(!counts(vec![credential(OP, Some("2026-12-01T00:00:00Z")), tampered]), "a body that does not hash to its CID");
    let malformed = operator(ROOT, OP, OP, Some("not a time"), None);
    assert!(!counts(vec![credential(OP, seen), malformed]), "a malformed time holds at no time");
}

#[test]
fn the_root_revokes_at_the_same_rkey_and_the_issuer_at_its_own_address() {
    let seen = Some("2026-10-20T00:00:00Z");
    assert!(!counts(vec![credential(OP, seen), october(OP), revocation(ROOT, "c1")]), "the root, same rkey");
    assert!(!counts(vec![credential(OP, seen), october(OP), revocation(OP, "c1")]), "the operator, its own address");
    assert!(counts(vec![credential(OP, seen), october(OP), revocation(ROOT, "c2")]), "the root, another rkey");
    assert!(counts(vec![credential(OP, seen), october(OP), revocation("did:plc:other", "c1")]), "another repo, same rkey");
    // The root's own credential: no first-seen time or operator record needed, revoked at its address.
    assert!(counts(vec![credential(ROOT, None)]));
    assert!(!counts(vec![credential(ROOT, None), revocation(ROOT, "c1")]));
}

#[test]
fn two_versions_of_one_credential_count_only_when_both_were_first_seen_in_the_period() {
    // The app should hold one version per credential; when it holds two at one address, every one must
    // be trusted, so a version first seen after the period cannot borrow an earlier version's standing.
    let inside = credential(OP, Some("2026-10-20T00:00:00Z"));
    let mut after = credential(OP, Some("2026-11-05T00:00:00Z"));
    after["value"]["createdAt"] = json!("2026-11-05T00:00:00Z");
    after["cid"] = json!(dag_cbor::cid_for_json(&after["value"]).expect("cid").to_string());
    assert!(!counts(vec![inside.clone(), after, october(OP)]));
    assert!(counts(vec![inside, october(OP)]));
}