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"}),
)
}
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
}
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")
}
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");
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");
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() {
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)]));
}