The original FEN specification is incorrect concerning the en passant target square.

The correct version is: The en passant target square which appears as the fourth field of a FEN record shall be "-" (nil) if no en passant capture is available. If an en passant capture is available, then the en passant target square will be the name of the destination square of an en passant capture. Note that for a non-nil en passant target square in a FEN string there will be at least one en passant capture in the position described by the FEN string; there may be two.

The original FEN specification is incorrect concerning the en passant target square.

The correct version is: The en passant target square which appears as the fourth field of a FEN record shall be "-" (nil) if no en passant capture is available. If an en passant capture is available, then the en passant target square will be the name of the destination square of an en passant capture. Note that for a non-nil en passant target square in a FEN string there will be at least one en passant capture in the position described by the FEN string; there may be two.

...
An en passant target square is given if and only if the last move was a pawn
advance of two squares. Therefore, an en passant target square field may have
a square name even if there is no pawn of the opposing side that may
immediately execute the en passant capture.

I think you are attacking the wrong problem. FEN is perfectly good and easily parsable, much easier than what you propose. FEN parsing is implemented by every amateur programmer in their engines, and is trivial. It is arguably the only good thing about the PGN standard.

The problem with PGN is everything after the tags. Move numbers are both useless and not even properly defined. SAN is an abortion, parsing it is atrocious, and requires writing almost a full move generator. Then all the stupid parsing rules about comments, etc.

Theory and practice sometimes clash. And when that happens, theory loses. Every single time.