I've always thought of ASI as more "statements are separated for you but if you need them to be separated in a special way you can add semicolons to manually control separation behavior" than a "you forgot semicolons, let me fix your code for you". Pretty much the same as the argument for optional braces being a language feature not an auto-correction.
That said when you look at either in terms of how they are implemented it'll seem like a correction feature. I think the real difference between auto-correction and optional syntax is simply whether or not the language spec designed it to be optional.
Semicolon insertion in Javascript is nothing like braces.
The grammar for e.g. an if statement is simple: *if (* expression *)* statement *else* statement. One particular value of statement is a block statement, which is where the braces come from. Nothing more, nothing less.
Inversely, the grammar specifically says that most statements (of types empty, expression, do-while, continue, break, return, throw, and debugger) must end with a semicolon, and ASI is explicitly described as a few cases where you're allowed to add an extra token to the token stream when the grammar refuses to accept the stream as-is.
That is a sensible way to think about it, and it would be great if the language worked that way, but unfortunately it does not. Statements in JavaScript are not separated by line breaks.
What about "statements are separated for you" implies line breaks split valid statements? The issue in your example is your first statement "console.log('a')(1 < 2)" tries to pass "true" to the return value of console.log triggering a runtime typeError. If you define an appropriate function for console.log (remember it's not part of JS) e.g.
Your example runs just fine because there was never actually a syntaxError anywhere in it to begin with, let alone a sytanxError that could be fixed with a ; by ASI. Similarly if I define console.log = 2 all of the above will throw typeError but that also has nothing to do with ASI.
This is precisely what "but if you need them to be separated in a special way you can add semicolons to manually control separation behavior" was referring to.
Lua has very similar rules to JS regarding semicolons from the user's perspective: semicolons are optional, and only change a programs meaning in some very unusual edge cases. From a PL design perspective, they're fairly different, though. Lua's grammar doesn't have a statement terminator, and the language just lets you insert semicolons anywhere that doesn't appear inside a statement if you so wish. JS's grammar does have a statement terminator, but has rules for inferring it in some places when it's not present.
Does this distinction matter in practice? Probably not. The more important different is probably just that JS has more unfortunate edge cases related to semicolons than Lua.
That said when you look at either in terms of how they are implemented it'll seem like a correction feature. I think the real difference between auto-correction and optional syntax is simply whether or not the language spec designed it to be optional.