feat(sdk): derive assurance in TypeScript and Go, not only Python

Python derived the assurance ladder and the other two clients did not, so a
TypeScript verifier -- which is what the product UI is -- had no way to
present it without inventing one. The rule that L3 is derived and never
signed only holds if every client applies it, so this is the property rather
than tidiness.

All three now report four facts kept apart: what the vault signed, whether a
quorum was met, whether an anchor confirmed, and what a verifier may
therefore report. A single badge would hide which of them was observed, and
that matters most exactly when one is missing.

Each carries the two asymmetries in its own tests. A witness outage withholds
L3 without reducing what the vault signed, because event-time assurance is a
fact about the past that no later outage changes. And an anchor never
promotes anything -- the report says so out loud, so a reader does not infer
it did.

The nine-case table is enumerated in each language, which is the only way two
implementations of a rule this narrow can be shown to agree. Python and
TypeScript were checked against each other directly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Codex
2026-08-22 20:45:18 +02:00
co-authored by Claude Opus 5
parent c1481e17dd
commit 974095c5f9
2 changed files with 177 additions and 0 deletions
+90
View File
@@ -0,0 +1,90 @@
package attesto
import "testing"
// Python derived assurance, TypeScript and Go did not. The rule that L3 is
// derived and never signed only holds if every client applies it, so parity
// here is the property rather than tidiness.
func boolPtr(value bool) *bool { return &value }
func TestL3IsDerivedAndNeverSigned(t *testing.T) {
report, err := EffectiveAssurance("L2", boolPtr(true), nil)
if err != nil {
t.Fatal(err)
}
if report.Effective != DerivedAssuranceLevel || !report.Derived {
t.Fatalf("expected derived L3, got %+v", report)
}
if report.VaultAssurance != "L2" {
t.Fatalf("the signed level must survive derivation, got %q", report.VaultAssurance)
}
if _, err := EffectiveAssurance("L3", nil, nil); err == nil {
t.Fatal("L3 was accepted as a signed vault assurance")
}
}
func TestAWithheldQuorumDoesNotReduceWhatTheVaultSigned(t *testing.T) {
for _, quorum := range []*bool{boolPtr(false), nil} {
report, err := EffectiveAssurance("L2", quorum, nil)
if err != nil {
t.Fatal(err)
}
if report.Effective != "L2" || report.Derived {
t.Fatalf("expected L2 withheld, got %+v", report)
}
}
}
func TestAnAnchorNeverPromotesAssurance(t *testing.T) {
report, err := EffectiveAssurance("L1", nil, boolPtr(true))
if err != nil {
t.Fatal(err)
}
if report.Effective != "L1" {
t.Fatalf("an anchor promoted the level to %q", report.Effective)
}
found := false
for _, reason := range report.Reasons {
if reason == "anchor confirmed; anchoring does not promote assurance" {
found = true
}
}
if !found {
t.Fatal("the report did not say that anchoring does not promote")
}
}
func TestTheTableAgreesWithTheOtherClients(t *testing.T) {
// Enumerated, because two implementations of a rule this narrow can only be
// shown to agree by listing every case.
cases := map[string]struct {
level string
quorum *bool
want string
}{
"L0/none": {"L0", nil, "L0"}, "L0/met": {"L0", boolPtr(true), "L0"},
"L0/unmet": {"L0", boolPtr(false), "L0"},
"L1/none": {"L1", nil, "L1"}, "L1/met": {"L1", boolPtr(true), "L1"},
"L1/unmet": {"L1", boolPtr(false), "L1"},
"L2/none": {"L2", nil, "L2"}, "L2/met": {"L2", boolPtr(true), "L3"},
"L2/unmet": {"L2", boolPtr(false), "L2"},
}
for name, item := range cases {
report, err := EffectiveAssurance(item.level, item.quorum, nil)
if err != nil {
t.Fatalf("%s: %v", name, err)
}
if report.Effective != item.want {
t.Fatalf("%s: got %q want %q", name, report.Effective, item.want)
}
}
}
func TestAnUnknownLevelIsRefused(t *testing.T) {
for _, level := range []string{"L9", "", "l2"} {
if _, err := EffectiveAssurance(level, nil, nil); err == nil {
t.Fatalf("%q was accepted as a vault assurance", level)
}
}
}
+87
View File
@@ -934,3 +934,90 @@ func toString(value any) string {
}
return ""
}
// VaultAssuranceLevels are the levels a vault may sign. L3 is deliberately
// absent: a vault that signed it would be asserting a property it cannot
// observe.
var VaultAssuranceLevels = []string{"L0", "L1", "L2"}
// DerivedAssuranceLevel is computed by a verifier and never signed.
const DerivedAssuranceLevel = "L3"
// AssuranceReport carries four facts, deliberately not collapsed into one
// badge. ADR-0010 requires a verifier to present vault assurance, witness
// state, quorum and anchor state separately: a single level would hide which of
// them was actually observed, and the difference matters most exactly when one
// is missing — an outage withholds L3 without changing what the vault signed at
// the time.
type AssuranceReport struct {
Effective string `json:"effective"`
VaultAssurance string `json:"vault_assurance"`
WitnessQuorumMet *bool `json:"witness_quorum_met"`
AnchorConfirmed *bool `json:"anchor_confirmed"`
Derived bool `json:"derived"`
Reasons []string `json:"reasons"`
}
// EffectiveAssurance derives the assurance a verifier may report, per
// ADR-0010 §40.4. The rule is narrow —
//
// if vaultAssurance == "L2" and witnessQuorumMet: L3, else vaultAssurance
//
// — and the narrowness is the point. Anchor confirmation is reported alongside
// and never promotes anything: an anchored L1 is an anchored L1.
//
// A witness outage withholds L3; it does not reduce what the vault signed. That
// asymmetry is deliberate, because event-time assurance is a fact about the past
// and no later outage can change it.
//
// nil for either observation means "not evaluated", which is reported as such
// rather than treated as false: a verifier that did not look and one that looked
// and found nothing are not the same verifier.
func EffectiveAssurance(vaultAssurance string, witnessQuorumMet, anchorConfirmed *bool) (*AssuranceReport, error) {
if vaultAssurance == DerivedAssuranceLevel {
return nil, fmt.Errorf("L3 is verifier-derived and can never be a signed vault assurance")
}
known := false
for _, level := range VaultAssuranceLevels {
if level == vaultAssurance {
known = true
break
}
}
if !known {
return nil, fmt.Errorf("unknown vault assurance: %q", vaultAssurance)
}
reasons := []string{}
switch {
case witnessQuorumMet == nil:
reasons = append(reasons, "witness quorum not evaluated")
case !*witnessQuorumMet:
reasons = append(reasons, "witness quorum not met")
}
switch {
case anchorConfirmed == nil:
reasons = append(reasons, "anchor state not evaluated")
case *anchorConfirmed:
// Said explicitly so a reader does not infer that an anchor lifted the
// level. It never does.
reasons = append(reasons, "anchor confirmed; anchoring does not promote assurance")
}
effective := vaultAssurance
if vaultAssurance == "L2" && witnessQuorumMet != nil && *witnessQuorumMet {
effective = DerivedAssuranceLevel
reasons = append(reasons, "L3 derived from L2 plus a met witness quorum")
} else if vaultAssurance == "L2" {
reasons = append(reasons, "L3 withheld: the quorum was not met or not evaluated")
}
return &AssuranceReport{
Effective: effective,
VaultAssurance: vaultAssurance,
WitnessQuorumMet: witnessQuorumMet,
AnchorConfirmed: anchorConfirmed,
Derived: effective == DerivedAssuranceLevel,
Reasons: reasons,
}, nil
}