This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

added fen, did some changes for board

author
pds.dad
date (Jul 2, 2026, 1:39 PM -0500) commit 5e2198d5 parent c8a74143 change-id pzlyutly
+82 -6
+59 -2
api/lichess/cbor_gen.go
··· 25 25 } 26 26 27 27 cw := cbg.NewCborWriter(w) 28 - fieldCount := 9 28 + fieldCount := 10 29 + 30 + if t.Fen == nil { 31 + fieldCount-- 32 + } 29 33 30 34 if t.Mode == nil { 31 35 fieldCount-- ··· 41 45 42 46 if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(fieldCount))); err != nil { 43 47 return err 48 + } 49 + 50 + // t.Fen (string) (string) 51 + if t.Fen != nil { 52 + 53 + if len("fen") > 1000000 { 54 + return xerrors.Errorf("Value in field \"fen\" was too long") 55 + } 56 + 57 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("fen"))); err != nil { 58 + return err 59 + } 60 + if _, err := cw.WriteString(string("fen")); err != nil { 61 + return err 62 + } 63 + 64 + if t.Fen == nil { 65 + if _, err := cw.Write(cbg.CborNull); err != nil { 66 + return err 67 + } 68 + } else { 69 + if len(*t.Fen) > 1000000 { 70 + return xerrors.Errorf("Value in field t.Fen was too long") 71 + } 72 + 73 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(*t.Fen))); err != nil { 74 + return err 75 + } 76 + if _, err := cw.WriteString(string(*t.Fen)); err != nil { 77 + return err 78 + } 79 + } 44 80 } 45 81 46 82 // t.Sig (string) (string) ··· 309 345 } 310 346 311 347 switch string(nameBuf[:nameLen]) { 312 - // t.Sig (string) (string) 348 + // t.Fen (string) (string) 349 + case "fen": 350 + 351 + { 352 + b, err := cr.ReadByte() 353 + if err != nil { 354 + return err 355 + } 356 + if b != cbg.CborNull[0] { 357 + if err := cr.UnreadByte(); err != nil { 358 + return err 359 + } 360 + 361 + sval, err := cbg.ReadStringWithMax(cr, 1000000) 362 + if err != nil { 363 + return err 364 + } 365 + 366 + t.Fen = (*string)(&sval) 367 + } 368 + } 369 + // t.Sig (string) (string) 313 370 case "sig": 314 371 315 372 {
+2
api/lichess/puzzleattempt.go
··· 16 16 LexiconTypeID string `json:"$type" cborgen:"$type,const=org.lichess.puzzle.attempt"` 17 17 // createdAt: client-declared timestamp when this attempt record was created. 18 18 CreatedAt string `json:"createdAt" cborgen:"createdAt"` 19 + // fen: The FEN of the puzzle's starting position (position before the opponent's setup move). Advisory context denormalized from the puzzle; derivable from puzzleId and not covered by sig. 20 + Fen *string `json:"fen,omitempty" cborgen:"fen,omitempty"` 19 21 // mode: Whether this attempt was played for rating and should be counted towards the user's rating. 20 22 Mode *string `json:"mode,omitempty" cborgen:"mode,omitempty"` 21 23 // nonce: Idempotency key echoed back by submitAttempt (the challenge's jti). Uniquely identifies the issued challenge, so duplicate records for one attempt can be detected. Covered by sig.
+3
client/src/lib/api/attempts.ts
··· 16 16 sig?: string; 17 17 /** Ranked only: the server-judged result, overriding the client engine's opinion so the record matches the signature. */ 18 18 solved?: boolean; 19 + /** The puzzle's starting FEN, denormalized into the record as advisory context. */ 20 + fen?: string; 19 21 }): void { 20 22 const { agent, did } = auth; 21 23 if (!agent || !did) return; ··· 31 33 solved: opts.solved ?? opts.result.solved, 32 34 playerMoves: opts.result.playedMoves, 33 35 createdAt: new Date().toISOString(), 36 + ...(opts.fen ? { fen: opts.fen } : {}), 34 37 ...(opts.nonce ? { nonce: opts.nonce } : {}), 35 38 ...(opts.sig ? { sig: opts.sig } : {}) 36 39 }
+6
client/src/lib/lexicon/lexicons.ts
··· 482 482 description: 483 483 "the moves played by the solver during the attempt, in the same notation as the puzzle's solution moves. For ranked attempts this must be the line submitted to submitAttempt verbatim: it is covered by sig.", 484 484 }, 485 + fen: { 486 + type: 'string', 487 + maxLength: 128, 488 + description: 489 + "The FEN of the puzzle's starting position (position before the opponent's setup move). Advisory context denormalized from the puzzle; derivable from puzzleId and not covered by sig.", 490 + }, 485 491 createdAt: { 486 492 type: 'string', 487 493 format: 'datetime',
+2
client/src/lib/lexicon/types/org/lichess/puzzle/attempt.ts
··· 28 28 nonce?: string 29 29 /** the moves played by the solver during the attempt, in the same notation as the puzzle's solution moves. For ranked attempts this must be the line submitted to submitAttempt verbatim: it is covered by sig. */ 30 30 playerMoves: string 31 + /** The FEN of the puzzle's starting position (position before the opponent's setup move). Advisory context denormalized from the puzzle; derivable from puzzleId and not covered by sig. */ 32 + fen?: string 31 33 /** client-declared timestamp when this attempt record was created. */ 32 34 createdAt: string 33 35 /** base64url (unpadded) detached signature by the service proving it judged playerMoves against the puzzle's solution with the given solved result. Signs the canonical DAG-CBOR encoding of an org.lichess.puzzle.defs#resultAttestation rebuilt from this record's fields — see that def for the exact verification recipe. Present only when the attempt was rated (ranked and not flagged). */
+2 -2
client/src/lib/puzzle/engine.svelte.ts
··· 13 13 playedMoves: string; 14 14 } 15 15 16 - const OPPONENT_MOVE_DELAY = 500; 17 - const REPLY_DELAY = 400; 16 + const OPPONENT_MOVE_DELAY = 300; 17 + const REPLY_DELAY = 200; 18 18 const REPLAY_STEP = 900; 19 19 20 20 /**
+1 -1
client/src/routes/+page.svelte
··· 42 42 } 43 43 44 44 function onComplete(r: PuzzleResult) { 45 - if (puzzle) recordAttempt({ puzzleId: puzzle.id, mode: 'casual', result: r }); 45 + if (puzzle) recordAttempt({ puzzleId: puzzle.id, mode: 'casual', result: r, fen: puzzle.fen }); 46 46 } 47 47 48 48 onMount(nextPuzzle);
+2 -1
client/src/routes/ranked/+page.svelte
··· 68 68 puzzleId, 69 69 mode: 'ranked', 70 70 result, 71 + fen: puzzle?.fen, 71 72 nonce: res.data.nonce, 72 73 sig: res.data.sig, 73 74 solved: res.data.solved ··· 82 83 phase = 'done'; 83 84 } catch (e) { 84 85 // Still log the attempt (client-claimed, unattested) when submit fails. 85 - if (puzzleId) recordAttempt({ puzzleId, mode: 'ranked', result }); 86 + if (puzzleId) recordAttempt({ puzzleId, mode: 'ranked', result, fen: puzzle?.fen }); 86 87 phase = 'done'; 87 88 error = 88 89 e instanceof ChallengeExpiredError
+5
lexicons/org/lichess/puzzle/attempt.json
··· 45 45 "type": "string", 46 46 "description": "the moves played by the solver during the attempt, in the same notation as the puzzle's solution moves. For ranked attempts this must be the line submitted to submitAttempt verbatim: it is covered by sig." 47 47 }, 48 + "fen": { 49 + "type": "string", 50 + "maxLength": 128, 51 + "description": "The FEN of the puzzle's starting position (position before the opponent's setup move). Advisory context denormalized from the puzzle; derivable from puzzleId and not covered by sig." 52 + }, 48 53 "createdAt": { 49 54 "type": "string", 50 55 "format": "datetime",