In the ancient days, OSM was much simpler. You had the streets and roads.
A crossing was considered a barrier along the way for road users (i.e. cars), so one would place a node with highway=crossing where the crosswalk is located. The routeplanner would apply a time penalty, the rendering engine shows a little icon, and done.
With an extra attribute (namely crossing_ref) a more precise type and the type of markings was indicated.
Then, someone figured out they could also shove in information about the traffic signals.
This kind of works for simple crossings, but breaks down for bigger intersections. crossing=unmarked, crossing=uncontrolled and crossing=controlled were added. And crossing=zebra, cause zebra crossings are so common. And crossing=marked, which was almost, but not quite, entirely unlike ~~tea~~ crossing=uncontrolled.
In the mean time, people started mapping cycleways and sidewalks/footways separately,
giving rise to a second way of tagging crossings: along the way; as highway=footway with footway=crossing.
Some ported over the traffic signal metadata over on the way, as they were used to doing on a node. Others starting mapping the traffic lights separately, often as barrier at the precise location where the pedestrian/cyclist/car driver has to wait.
This gives the potential of having the traffic light metadata on three separate locations:
1) Once on the point where the road and the footway meet 2) Once on the footway, marked with crossing 3) Once on the traffic light node on the footway
In other words, the current tagging is a clusterfuck.

