{
"id": "net.anisota.chronicle.progress",
"defs": {
"main": {
"key": "any",
"type": "record",
"record": {
"type": "object",
"required": [
"totalXP",
"level",
"signature",
"createdAt"
],
"properties": {
"level": {
"type": "integer",
"maximum": 99,
"minimum": 1,
"description": "Current player level (derived from XP table)"
},
"totalXP": {
"type": "integer",
"minimum": 0,
"description": "Total accumulated XP"
},
"createdAt": {
"type": "string",
"format": "datetime",
"description": "When the record was first created"
},
"signature": {
"ref": "#chronicleSignature",
"type": "ref"
},
"updatedAt": {
"type": "string",
"format": "datetime",
"description": "When the record was last updated"
},
"triggerSource": {
"type": "string",
"description": "What triggered this save (level_up, session_end, visibility_hidden, periodic, card_advance)"
},
"xpToNextLevel": {
"type": "integer",
"minimum": 0,
"description": "XP remaining to reach next level"
},
"progressPercentage": {
"type": "string",
"description": "Progress toward next level as decimal string"
},
"xpGainedSinceLastSign": {
"type": "integer",
"minimum": 0,
"description": "XP gained since the last signed progress record (for rate validation against daily activity)"
}
}
},
"description": "Signed player progression state. Singleton (rkey: self), overwritten via putRecord. Backend validates XP claims before signing."
},
"chronicleSignature": {
"type": "object",
"required": [
"sig",
"alg",
"kid",
"signedAt",
"nonce",
"version"
],
"properties": {
"alg": {
"type": "string",
"description": "Signing algorithm (ES256)"
},
"kid": {
"type": "string",
"description": "Key identifier for the signing key"
},
"sig": {
"type": "string",
"description": "Base64-encoded ES256 signature"
},
"nonce": {
"type": "string",
"description": "Unique random nonce to prevent replay"
},
"version": {
"type": "integer",
"description": "Signature schema version"
},
"signedAt": {
"type": "string",
"format": "datetime",
"description": "When the record was signed"
}
},
"description": "ES256 cryptographic signature proving record authenticity"
}
},
"$type": "com.atproto.lexicon.schema",
"lexicon": 1
}