MinusKelvinSome thoughts:
− Needs an introduction giving a non-normative high-level overview of how UCI
works to aid in comprehension.
− 1·3: ASCII requirement precludes placing my syzygy tablebase files in a folder
called "échecs" (French for chess), so this should probably be adjusted to
match 1·4.
− Typically to deal with the whole "\n" vs "\r\n" thing specification authors
define a "line ending" to be either and then use "line ending" everywhere
else in the specification.
− 2·5: I don't think "algebraic token" is a very clear term for this, I think it
should be called a "move token".
− State machine is as I understand UCI 👍
− Small bug: engine sending "bestmove" in the ping state needs to transition
to the sync state rather than the idle state. Otherwise, you allow "isready"
without a matching "readyok".
− 3·5: I don't think it's a good idea to consider ill-formed messages as errors
rather than violations. Is there a reason for this? For extensions to UCI,
this could be advertised via options (like "UCI_Chess960").
− I think that "the X may send any message" is not a good statement to make in
general, and the specification should be more explicit and restrictive in what
is allowed at any time.
− Good rationale for gray statement at end of section 3. This could probably be
moved up a bit to the start of section 3.
− Addressing the thing above, I think that
− this breaks existing UCI, but I would not be opposed to requiring "isready" /
"readyok" after "uciok" to
− 5 and 6: All of these should use a formal grammar to describe well-formedness.
− 5·3: Should also note that receiving no protocol message before "uciok"
indicates old UCI.
− How strings work needs to be specified more formally, or possibly completely
reworked. Edge case to consider:
option name Draw value type int min -1000 max 1000
option name Draw type string default <empty>
setoption name Draw value value 50
Am I setting "Draw value" to 50 or "Draw" to "value 50"?
− 6·7: typo: missing word in "Limits, context items, and modifiers may appear
in [any] order".
− A full specification should also reference FEN and describe the move format
more precisely (notably castling notation).
− I would like to see specifications for common UCI extensions,
e.g. "UCI_Chess960" and "UCI_ShowWDL".
− An appendix with common and fairly standardized engine options (e.g. "Hash",
"Threads", "SyzygyPath", "MultiPV") would also be nice.
expo
Needs an introduction giving a non-normative high-level overview of how UCI
works to aid in comprehension.
Will do!
1·3: ASCII requirement [...] should probably be adjusted to match 1·4.
Will do. In fact, you've pointed out what is simply a mistake – as written, it's
possible for the engine to name an option that the client cannot use. I'm still
not sure what the best way is to handle file paths, which on many systems are
just a series of bytes (with only a few restrictions). Perhaps the best thing
is relaxing the UTF-8 requirement for anything following "info string" and
"option name ... value" (but still disallowing U+000A and U+000D, which seems
like a reasonable restriction).
2·5: I don't think "algebraic token" is a very clear term for this, I think it
should be called a "move token".
I thought about this, but I was worried about confusing "'moves' token" (as in
"'position startpos moves ...'") and "move token", and I also wanted to avoid
any conflation of tokens and legal moves that those tokens may correspond to
when interpreted as long algebraic notation. That was the thinking, anyway.
Small bug: engine sending "bestmove" in the ping state needs to transition
to the sync state rather than the idle state. Otherwise, you allow "isready"
without a matching "readyok".
I actually hadn't thought to try to ensure that every "isready" is matched by
a "readyok". My thinking was that "isready" could be answered with "bestmove",
so that all three of these would be valid:
client send isready → eng send bestmove → eng read isready → eng send readyok
client send isready → eng read isready → eng send readyok → eng send bestmove
client send isready → eng read isready → eng send bestmove
But yes! I agree that if we wanted to ensure that every "isready" is matched by
a "readyok", there'd need to be a transition to sync from ping. (And I think
that'd be enough? although I've yet to work through all the cases.)
3·5: I don't think it's a good idea to consider ill-formed messages as errors
rather than violations. Is there a reason for this?
This is for compatible with legacy client and engines – according to HMK,
clients and engines should generally just ignore things they don't understand.
Whereas when a violation occurs, all bets are off – these are fatal or
unrecoverable, as it were (I mean, you can try to recover from them, but nobody
who conforms to this specification is required to handle them). So the idea was
to be selective about what was considered a violation (and to put most of that
burden on clients, since there are far fewer clients than engines).
I think that "the X may send any message" is not a good statement to make in
general, and the specification should be more explicit and restrictive in what
is allowed at any time.
The reasoning here was roughly the same as above. "The (engine|client) may send
any message" simply means that an unexpected or malformed is not a _violation_
(but in most cases is an error).
Good rationale for gray statement at end of section 3. This could probably be
moved up a bit to the start of section 3.
Can do!
5 and 6: All of these should use a formal grammar to describe well-formedness.
This was a conscious decision, but it's definitely worth revisiting. I'll write
out a version using more notation so we can see how it looks and compare the two.
5·3: Should also note that receiving no protocol message before "uciok"
indicates old UCI.
That's a really good idea! I'll add that.
option name Draw value type int min -1000 max 1000
I had restricted all option integers to be nonnegative because I couldn't
thinking of anything that needed negative integers, but this is an excellent
counterexample. I'll widen the range to include negative integers.
Am I setting "Draw value" to 50 or "Draw" to "value 50"?
I'll add something to address this. Good catch!
6·7: typo: missing word in "Limits, context items, and modifiers may appear
in [any] order".
Good catch!
A full specification should also reference FEN and describe the move format
more precisely (notable: castling notation).
Will do.
I would like to see specifications for common UCI extensions,
e.g. "UCI_Chess960" and "UCI_ShowWDL".
Agreed; I'll put this on the to-do list.
An appendix with common and fairly standardized engine options (e.g. "Hash",
"Threads", "SyzygyPath", "MultiPV") would also be nice.
Agreed.
Something related already came up in the TalkChess thread. I had come to the
conclusion that engine options have to be implementation-defined (and more
generally, that the specification should be concerned with syntax rather than
semantics) given the diversity of engines now and potentially in the future.
And in fact, I think it's simply impossible to formally define the semantics,
since I don't think that that can be done in a way that's agnostic to clients'
and engines' internal representations – the only thing that we can govern is
outwardly observable behavior (the messages that the client and engine send).
That said, providing additional recommendations (as comments) would be a really
good thing – particularly things that would be helpful for new engine devs.