While the OP's use case is probably better solved by switching to a long format, the problem of a missing prefix for named single column arguments to cbind.data.frame persists and is perhaps highlighted better in the following example:
cbind(x=data.frame(a=1,b=2), y=data.frame(a=3, b=4))
#> x.a x.b y.a y.b
#> 1 1 2 3 4
cbind(x=data.frame(a=1,b=2), y=data.frame(a=3))
#> x.a x.b a
#> 1 1 2 3
Note, how the a column in the second case lacks the y. prefix. This odd behavior is documented in the value section of ?data.frame (which is called by cbind for data.frame arguments):
How the names of the data frame are created is complex, and the rest of this paragraph is only the basic story. [...] For a named matrix/list/data frame argument with more than one named column, the names of the columns are the name of the argument followed by a dot and the column name inside the argument: if the argument is unnamed, the argument's column names are used. For a named or unnamed matrix/list/data frame argument that contains a single column, the column name in the result is the column name in the argument.
One possible workaround (with several positive side effects) is switching from base data.frame to data.table. It handles the the column names more consistently:
library(data.table)
cbind(x=data.table(a=1,b=2), y=data.frame(a=3))
#> x.a x.b y.a
#> <num> <num> <num>
#> 1: 1 2 3